# 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"