Resigner is a Go library for re-signing iOS .ipa/.app files, mainly for Appium/WebDriverAgentRunner workflows.
Please do not use this for production app signing.
- Windows, macOS, Linux
- go 1.26.1 or later
curl -LO https://github.com/KazuCocoa/resigner/releases/download/<version>/darwin-amd64.tar.gzcurl -LO https://github.com/KazuCocoa/resigner/releases/download/<version>/darwin-arm64.tar.gzcurl -LO https://github.com/KazuCocoa/resigner/releases/download/<version>/linux-amd64.tar.gzcurl -LO https://github.com/KazuCocoa/resigner/releases/download/<version>/linux-386.tar.gzInvoke-WebRequest -Uri "https://github.com/KazuCocoa/resigner/releases/download/<version>/windows-386.zip" -OutFile "resigner-windows-386.zip"Invoke-WebRequest -Uri "https://github.com/KazuCocoa/resigner/releases/download/<version>/windows-amd64.zip" -OutFile "resigner-windows-amd64.zip"Note: Replace <version> with the latest version from Releases
resigner \
--p12-file "<path to p12 file>" \
--p12-password "<password of p12>" \
--profile "<path to provisioning profiles>" \
--force \
--bundle-id-remap "com.facebook.WebDriverAgentRunner=<valid bundle id for the profile>" \
--bundle-id-remap "com.facebook.WebDriverAgentRunner.xctrunner=<valid bundle id for the profile>" \
--bundle-id-remap "com.facebook.WebDriverAgentLib=<valid bundle id for the profile>" \
/path/to/WebDriverAgentRunner-Runner.appYou can provide the password via an environment variable instead of --p12-password:
P12_PASSWORD="<password of p12>" resigner \
--p12-file "<path to p12 file>" \
--profile "<path to provisioning profiles>" \
--force \
--bundle-id-remap "com.facebook.WebDriverAgentRunner=<valid bundle id for the profile>" \
--bundle-id-remap "com.facebook.WebDriverAgentRunner.xctrunner=<valid bundle id for the profile>" \
--bundle-id-remap "com.facebook.WebDriverAgentLib=<valid bundle id for the profile>" \
/path/to/WebDriverAgentRunner-Runner.app<valid bundle id for the profile> should match the provisioning profile app identifier.
resigner --inspect /path/to/WebDriverAgentRunner-Runner.app
resigner --inspect /path/to/WebDriverAgentRunner-Runner.ipaThis prints each discovered bundle path with:
- current Info.plist bundle identifier
- current signed code identifier
- team identifier
- leaf signing certificate common name
Use the .p12 with --p12-file, and its password with --p12-password or P12_PASSWORD.
- Open Keychain Access.
- Find your Apple Development certificate with a private key.
- Export as
Personal Information Exchange (.p12). - Set an export password.
openssl x509 -in certificate.cer -inform DER -out certificate.pem
openssl pkcs12 -export \
-in certificate.pem \
-inkey private.key \
-out sign.p12 \
-passout pass:mypassword- Add your Apple ID in
Xcode > Settings > Accounts. - Enable
Automatically manage signingfor your target and personal team. - Build once on a real device to generate an Apple Development cert and profile.
- In Keychain Access (
login > My Certificates), export the Apple Development certificate as.p12.
Tips:
- If the certificate is missing in Keychain, run another real-device build in Xcode.
- Free-account profiles are usually in
~/Library/Developer/Xcode/UserData/Provisioning Profiles.
security export -t identities exports all exportable identities from the specified keychain.
# generate a strong random password
P12_PASSWORD="$(openssl rand -base64 24 | tr -d '\n')"
# export identities to p12 using that password
security export \
-k ~/Library/Keychains/login.keychain-db \
-t identities \
-f pkcs12 \
-P "$P12_PASSWORD" \
-o ~/sign/mysign.p12
# show it once so you can store it in your secret manager
echo "$P12_PASSWORD"Use this if you want a .p12 that contains exactly one identity from security find-identity.
# choose SHA-1 from: security find-identity -v -p codesigning ~/Library/Keychains/login.keychain-db
TARGET_SHA1="PUT_SHA1_HERE"
# passwords for temporary operations and final p12
TMP_PASS="$(openssl rand -base64 24 | tr -d '\n')"
P12_PASSWORD="$(openssl rand -base64 24 | tr -d '\n')"
# create temporary workspace
TMP_DIR="$(mktemp -d /tmp/resigner-p12.XXXXXX)"
TMP_KC="$TMP_DIR/one.keychain-db"
# export from login keychain, then import into temporary keychain
security export -k ~/Library/Keychains/login.keychain-db -t identities -f pkcs12 -P "$TMP_PASS" -o "$TMP_DIR/all.p12"
security create-keychain -p "$TMP_PASS" "$TMP_KC"
security unlock-keychain -p "$TMP_PASS" "$TMP_KC"
security import "$TMP_DIR/all.p12" -k "$TMP_KC" -P "$TMP_PASS"
# keep only TARGET_SHA1
for s in $(security find-identity -v -p codesigning "$TMP_KC" | awk '/"/ {print $2}'); do
[ "$s" = "$TARGET_SHA1" ] || security delete-identity -Z "$s" "$TMP_KC"
done
# export the remaining identity as p12
security export -k "$TMP_KC" -t identities -f pkcs12 -P "$P12_PASSWORD" -o ~/sign/mysign-specific.p12
# show outputs once, then clean up temp files
echo "P12: ~/sign/mysign-specific.p12"
echo "PASSWORD: $P12_PASSWORD"
security delete-keychain "$TMP_KC" 2>/dev/null || true
rm -rf "$TMP_DIR"openssl pkcs12 -info -in mysign.p12 -noout- Xcode auto-generated (including free account):
~/Library/Developer/Xcode/UserData/Provisioning Profiles - System-cached profiles:
~/Library/MobileDevice/Provisioning Profiles
Recommended to copy the target profile to a separate directory and point --profile there,
to avoid accidentally using an unintended profile.
security cms -D -i /path/to/profile.mobileprovision > /tmp/profile.plist/usr/libexec/PlistBuddy -c "Print :ExpirationDate" /tmp/profile.plist
# Output example: Sat Apr 04 22:12:21 PST 2026/usr/libexec/PlistBuddy -c "Print :Entitlements:application-identifier" /tmp/profile.plist# Check development flag (should be true for free accounts)
/usr/libexec/PlistBuddy -c "Print :Entitlements:get-task-allow" /tmp/profile.plist
# Check team identifier
/usr/libexec/PlistBuddy -c "Print :TeamIdentifier:0" /tmp/profile.plist
# List provisioned device UDIDs (must include target device)
/usr/libexec/PlistBuddy -c "Print :ProvisionedDevices" /tmp/profile.plist# Scan for matching profiles and show expiration status
BUNDLE_ID_SUBSTR="com.kazucocoa.WebDriverAgentRunner"
for f in /path/to/profiles/*; do
[ -f "$f" ] || continue
security cms -D -i "$f" > /tmp/p.plist 2>/dev/null || continue
appid=$(/usr/libexec/PlistBuddy -c "Print :Entitlements:application-identifier" /tmp/p.plist 2>/dev/null)
if [[ "$appid" == *"$BUNDLE_ID_SUBSTR"* ]]; then
echo "FILE:$f"
/usr/libexec/PlistBuddy -c "Print :Name" /tmp/p.plist
/usr/libexec/PlistBuddy -c "Print :ExpirationDate" /tmp/p.plist
echo "---"
fi
donemakemake allgo test ./...# Update CHANGELOGS.md and commit it.
git tag <new_version> # please add `v` prefix, e.g. `v0.1.1`
git push origin <new_version>