# Version 8 - 28112022(DDMMYYYY)
#!/usr/bin/env bash
function show_error() {
message="$1"
printf "$message. Exiting..."
exit 1
}
function check_status() {
if [ $? -ne 0 ]; then
show_error "Error occurred"
fi
}
function manage_existing_file_to_resign() {
echo "Validating $ORIGINAL_FILE..."
if [ "${ORIGINAL_FILE##*.}" = "ipa" ]; then
# Unzip the old ipa quietly
unzip -q "$ORIGINAL_FILE" -d temp
check_status
else
show_error "Error: Resign require a .ipa file"
fi
}
function set_target_app() {
# Set the name of the original app, used as global variable in this script
TARGET_APP=$(ls temp/Payload/)
}
function set_display_name() { ## Replace AppName, usually not changed from resign process
if [ ! -z "$DISPLAY_NAME" ]; then
/usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName $DISPLAY_NAME" "temp/Payload/$TARGET_APP/Info.plist"
echo "New Display Name: $DISPLAY_NAME"
fi
}
function set_app_id_prefix() { ## Replace APP_ID, specific of the Developer account
OLD_APP_ID_PREFIX=$(grep 'application-identifier' "temp/Payload/$TARGET_APP/embedded.mobileprovision" -A 1 --binary-files=text | sed -E -e '// d' -e 's/(^.*)//' -e 's/([A-Z0-9]*)(.*)/\1/')
check_status
NEW_APP_ID_PREFIX=$(grep 'application-identifier' "$PROVISION_FILE" -A 1 --binary-files=text | sed -E -e '// d' -e 's/(^.*)//' -e 's/([A-Z0-9]*)(.*)/\1/')
check_status
echo "New app id: $NEW_APP_ID_PREFIX"
}
function set_bundle_id() {
OLD_BUNDLE_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "temp/Payload/$TARGET_APP/Info.plist")
check_status
NEW_BUNDLE_ID=$(egrep -a -A 2 application-identifier "${PROVISION_FILE}" | grep string | sed -e 's///' -e 's/<\/string>//' -e 's/ //' | awk '{split($0,a,"."); i = length(a); for(ix=2; ix <= i;ix++){ s=s a[ix]; if(i!=ix){s=s "."};} print s;}')
if [[ "${NEW_BUNDLE_ID}" == *\** ]]; then
show_error "Bundle Identifier contains a *"
fi
check_status
echo "New bundle id: $NEW_BUNDLE_ID"
### Replace bundle identifier and BundleURLSchema contained inside Info.plist
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $NEW_BUNDLE_ID" "temp/Payload/$TARGET_APP/Info.plist"
/usr/libexec/PlistBuddy -c "Set :CFBundleURLTypes:1:CFBundleURLSchemes:0 $NEW_BUNDLE_ID" "temp/Payload/$TARGET_APP/Info.plist"
## Update GoogleSignin URL schema
NEW_CLIENT_ID=$(/usr/libexec/PlistBuddy -c "Print :REVERSED_CLIENT_ID" "temp/Payload/$TARGET_APP/GoogleService-Info.plist")
if [[ ! -z $NEW_CLIENT_ID ]]; then
/usr/libexec/PlistBuddy -c "set :CFBundleURLTypes:0:CFBundleURLSchemes:0 $NEW_CLIENT_ID" "temp/Payload/$TARGET_APP/Info.plist"
echo "Schema replaced with $NEW_CLIENT_ID"
fi
## End of update GoogleSignin URL schema
# Uncomment to convert Info.plist to binary format
# plutil -convert binary1 "temp/Payload/$TARGET_APP/Info.plist"
}
function replace_provisioning_profile() {
cp "$PROVISION_FILE" "temp/Payload/$TARGET_APP/embedded.mobileprovision"
check_status
}
function resign_app() {
# PP enable all domains via a non-AppStore-compliant '*' value, must use App entitlements value
# similar fix on Fastlane repository https://github.com/fastlane/fastlane/blob/master/sigh/lib/assets/resign.sh#L707
associatedDomainKey="com.apple.developer.associated-domains"
# This is the only way to get the entitlement values in a signed ipa file! The returned value is a String.
APP_ENTITLEMENTS="$(/usr/bin/codesign -d --entitlements :- "temp/Payload/$TARGET_APP")"
# save string value inside a temp file
echo $APP_ENTITLEMENTS > temp/appEntitlements.plist
# Print the values with PlistBuddy and save the values in a new Array.
declare -a FILE_ARRAY=($(/usr/libexec/PlistBuddy -c "Print :$associatedDomainKey" "temp/appEntitlements.plist" | sed -e 1d -e '$d'))
# Create a new entitlement file with the provisioning profile values!
security cms -D -i "$PROVISION_FILE" > "provisioning.plist"
# Copy all the new entlitements values inside a new temp file. This is a mandatory step!
/usr/libexec/PlistBuddy -x -c 'Print:Entitlements' "provisioning.plist" > "temp/entitlements.plist"
# delete the '*' value of the com.apple.developer.associated-domains. The default value of the provisioning is '*'
/usr/libexec/PlistBuddy -c "delete $associatedDomainKey" "temp/entitlements.plist"
index=0
# iterate over FILE_ARRAY if populated
for element in "${FILE_ARRAY[@]}"
do
# Add every array values of associatedDomainKey of the old entitlements inside the new entitlements file!
/usr/libexec/PlistBuddy -c "add :$associatedDomainKey array" -c "add :$associatedDomainKey:$index string $element" "temp/entitlements.plist"
((index++))
done
# Print the entitlement file content
cat temp/entitlements.plist
xattr -cr "temp/Payload/$TARGET_APP"
/usr/bin/codesign -vvvvvvv -f -s "$CERTIFICATE" "temp/Payload/$TARGET_APP/Frameworks/hermes.framework/hermes"
/usr/bin/codesign -vvvvvvv -f -s "$CERTIFICATE" "temp/Payload/$TARGET_APP/Frameworks/Pendo.framework/Pendo"
/usr/bin/codesign -vvvvvvv -f -s "$CERTIFICATE" --entitlements="temp/entitlements.plist" "temp/Payload/$TARGET_APP"
check_status
}
function finalize() {
cd temp/
zip -qr ../app-resigned.ipa Payload/ BCSymbolMaps/ SwiftSupport/
cd ..
rm -rf "temp"
}
if [[ ${#3} -eq 0 ]]; then
show_error "\nHow to use: \n $ ${0##*/} path/to/ipa_or_app_to_sign path/to/profile Certificate(='iPhone Distribution: Name') \n\nTry again"
fi
ORIGINAL_FILE="$1"
PROVISION_FILE="$2"
CERTIFICATE="$3"
DISPLAY_NAME="$4"
manage_existing_file_to_resign
set_target_app
set_display_name
set_app_id_prefix
set_bundle_id
echo "Resigning..."
replace_provisioning_profile
echo "Creating resigned ipa..."
resign_app
finalize
echo "Created app-resigned.ipa"