From b6704113065f4ccef308926d87895c49f5691187 Mon Sep 17 00:00:00 2001 From: tkgstrator <29420801+tkgstrator@users.noreply.github.com> Date: Sat, 1 Aug 2026 16:41:58 +0900 Subject: [PATCH 1/2] feat(build_patched_ipa): --bundle-id-suffix flag (#21) Lets a patched IPA install alongside the original app instead of overwriting it, which is what a consumer needs when it wants the stock build and the patched build on the device at the same time. Ported from feat/bundle-id-suffix, which branched before #17-#19 and so never picked up the verify_sites overload resolution its consumer now depends on. Rebuilding the flag on top of develop keeps the two lines from drifting further apart. uv.lock rides along: develop bumped pyproject to 0.2.0 without regenerating the lock. Co-authored-by: tkgstrator Co-authored-by: Claude Opus 4.7 --- tools/build_patched_ipa.sh | 48 +++++++++++++++++++++++++++++++------- uv.lock | 2 +- 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/tools/build_patched_ipa.sh b/tools/build_patched_ipa.sh index 0782692..b1c7e91 100755 --- a/tools/build_patched_ipa.sh +++ b/tools/build_patched_ipa.sh @@ -30,7 +30,8 @@ # --framework \ # --dylib \ # --input \ -# [--output ] +# [--output ] \ +# [--bundle-id-suffix ] # # The script never distributes the input IPA itself — the operator # supplies one. @@ -50,6 +51,12 @@ Usage: build_patched_ipa.sh --recipe NAME --framework BASENAME --dylib PATH --in NOT distribute the IPA itself). --output IPA Optional; defaults to packages/ipa/-patched.ipa (e.g. Kiou-1.0.1.ipa -> packages/ipa/Kiou-1.0.1-patched.ipa). + --bundle-id-suffix SUFFIX + Optional; if non-empty, append "." to the + Info.plist CFBundleIdentifier so the patched IPA + installs alongside the original app instead of + overwriting it (e.g. "chinlan" turns + com.acme.app into com.acme.app.chinlan). EOF exit 64 } @@ -59,16 +66,18 @@ FRAMEWORK="" DYLIB_SRC="" INPUT_IPA="" OUTPUT_IPA="" +BUNDLE_ID_SUFFIX="" while [ $# -gt 0 ]; do case "$1" in - --recipe) RECIPE="$2"; shift 2;; - --framework) FRAMEWORK="$2"; shift 2;; - --dylib) DYLIB_SRC="$2"; shift 2;; - --input) INPUT_IPA="$2"; shift 2;; - --output) OUTPUT_IPA="$2"; shift 2;; - -h|--help) usage;; - *) echo "error: unknown argument: $1" >&2; usage;; + --recipe) RECIPE="$2"; shift 2;; + --framework) FRAMEWORK="$2"; shift 2;; + --dylib) DYLIB_SRC="$2"; shift 2;; + --input) INPUT_IPA="$2"; shift 2;; + --output) OUTPUT_IPA="$2"; shift 2;; + --bundle-id-suffix) BUNDLE_ID_SUFFIX="$2"; shift 2;; + -h|--help) usage;; + *) echo "error: unknown argument: $1" >&2; usage;; esac done @@ -243,6 +252,29 @@ echo "==> verifying LC_LOAD_DYLIB (recipe: $RECIPE)" echo "==> patching Info.plist (recipe: $RECIPE)" "$PY" -m tools.patch_plist --recipe "$RECIPE" "$INFO_PLIST" +# Optional CFBundleIdentifier rewrite so the patched IPA can live +# side-by-side with the original app instead of overwriting it. Skipped +# when --bundle-id-suffix is empty (the default), so the pipeline stays +# a no-op for the "overwrite the original" workflow. +if [ -n "$BUNDLE_ID_SUFFIX" ]; then + ORIGINAL_BUNDLE_ID="$("$PY" -c "import plistlib,sys; print(plistlib.load(open(sys.argv[1],'rb')).get('CFBundleIdentifier',''))" "$INFO_PLIST")" + if [ -z "$ORIGINAL_BUNDLE_ID" ]; then + echo "error: Info.plist has no CFBundleIdentifier to append suffix to" >&2 + exit 1 + fi + # Idempotent: if the suffix is already present, don't append it twice. + case "$ORIGINAL_BUNDLE_ID" in + *".$BUNDLE_ID_SUFFIX") + echo "==> CFBundleIdentifier already carries suffix .$BUNDLE_ID_SUFFIX — skipping rewrite" + ;; + *) + NEW_BUNDLE_ID="${ORIGINAL_BUNDLE_ID}.${BUNDLE_ID_SUFFIX}" + echo "==> rewriting CFBundleIdentifier: $ORIGINAL_BUNDLE_ID -> $NEW_BUNDLE_ID" + "$PY" -m tools.patch_plist --set "CFBundleIdentifier=${NEW_BUNDLE_ID}" "$INFO_PLIST" + ;; + esac +fi + # --------------------------------------------------------------------------- # 4. inject dylib # --------------------------------------------------------------------------- diff --git a/uv.lock b/uv.lock index edc1e26..835cd8d 100644 --- a/uv.lock +++ b/uv.lock @@ -22,7 +22,7 @@ wheels = [ [[package]] name = "ipa-patch-shared" -version = "0.1.3" +version = "0.2.0" source = { virtual = "." } dependencies = [ { name = "lief" }, From dcf83af3dd6579fedc830aecd9f5750d2c7f68ea Mon Sep 17 00:00:00 2001 From: tkgstrator <29420801+tkgstrator@users.noreply.github.com> Date: Sat, 1 Aug 2026 22:08:59 +0900 Subject: [PATCH 2/2] chore: bump version to 0.3.0 (#22) Minor bump for the --bundle-id-suffix flag on build_patched_ipa. Updates uv.lock alongside pyproject.toml. The 0.2.0 bump moved only pyproject, leaving the lock pinning the old version until a later change happened to refresh it. Co-authored-by: tkgstrator Co-authored-by: Claude Opus 4.7 --- pyproject.toml | 2 +- uv.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 37ee827..2d06c2d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "ipa-patch-shared" -version = "0.2.0" +version = "0.3.0" description = "Kanade — static-patch tooling for IPA-Patch projects (arm64 encoder, Mach-O ops, IPA pipeline)." readme = "README.md" requires-python = ">=3.12" diff --git a/uv.lock b/uv.lock index 835cd8d..5c84d7d 100644 --- a/uv.lock +++ b/uv.lock @@ -22,7 +22,7 @@ wheels = [ [[package]] name = "ipa-patch-shared" -version = "0.2.0" +version = "0.3.0" source = { virtual = "." } dependencies = [ { name = "lief" },