@@ -10,6 +10,7 @@ BIN_DIR=${BIN_DIR:-"$CWD/../bin/ios"}
1010BUILD_DIR=${BUILD_DIR:- " $CWD /../build" }
1111ANDROID_ABI=${ANDROID_ABI:- " arm64-v8a" }
1212BUILD_TYPE=${BUILD_TYPE:- " apk" }
13+ SIGN_IOS=${SIGN_IOS:- " false" }
1314
1415echo " Building wrapperApp for ${OS} , ${ANDROID_ABI} "
1516
@@ -109,17 +110,161 @@ if [[ "${OS}" == "android" ]]; then
109110 fi
110111 fi
111112else
113+ # Generate timestamp-based build version (seconds * 1000 / 60000 = seconds / 60)
114+ # This gives us minutes since epoch, similar to Android's milliseconds / 60000
115+ BUILD_VERSION=$(( $(date +% s) * 1000 / 60000 ))
116+
117+ # Include PR number in build version if available (for TestFlight visibility)
118+ if [[ -n " ${CHANGE_ID:- } " ]]; then
119+ # Format: PR{number}.{timestamp} -> e.g., 18993.29353586
120+ VERSION_STRING=" ${CHANGE_ID} .${BUILD_VERSION} "
121+ else
122+ # For non-PR builds, just use timestamp
123+ VERSION_STRING=" ${BUILD_VERSION} "
124+ fi
125+
126+ echo " Using version: $VERSION_STRING "
127+
112128 QMAKE_BIN=" ${QMAKE:- qmake} "
113- " $QMAKE_BIN " " $CWD /../wrapperApp/Status.pro" -spec macx-ios-clang CONFIG+=release CONFIG+=" $SDK " CONFIG+=device -after
129+ " $QMAKE_BIN " " $CWD /../wrapperApp/Status.pro" -spec macx-ios-clang CONFIG+=release CONFIG+=" $SDK " CONFIG+=device VERSION=" $VERSION_STRING " -after
130+
114131 # Compile resources
115132 xcodebuild -configuration Release -target " Qt Preprocess" -sdk " $SDK " -arch " $ARCH " CODE_SIGN_IDENTITY=" " CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO | xcbeautify
116133 # Compile the app
117134 xcodebuild -configuration Release -target Status install -sdk " $SDK " -arch " $ARCH " DSTROOT=" $BIN_DIR " INSTALL_PATH=" /" TARGET_BUILD_DIR=" $BIN_DIR " CODE_SIGN_IDENTITY=" " CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO | xcbeautify
118135
119- if [[ -e " $BIN_DIR /Status.app/Info.plist" ]]; then
120- echo " Build succeeded"
121- else
136+ if [[ ! -e " $BIN_DIR /Status.app/Info.plist" ]]; then
122137 echo " Build failed"
123138 exit 1
124139 fi
140+
141+ if [[ " $SIGN_IOS " == " true" ]]; then
142+ echo " Signing iOS app..."
143+
144+ if [[ -z " $IOS_CERT_PATH " || -z " $IOS_CERT_PASSWORD " || -z " $IOS_PROVISIONING_PROFILE " ]]; then
145+ echo " Error: Missing iOS signing credentials"
146+ exit 1
147+ fi
148+
149+ # Import certificate to keychain
150+ KEYCHAIN_NAME=" build.keychain"
151+ KEYCHAIN_PASSWORD=$( openssl rand -base64 16)
152+
153+ # Cleanup function to delete keychain
154+ cleanup_keychain () {
155+ echo " Cleaning up keychain..."
156+ security default-keychain -s login.keychain 2> /dev/null || true
157+ security delete-keychain " $KEYCHAIN_NAME " 2> /dev/null || true
158+ }
159+
160+ # Set trap to cleanup keychain on script exit (success or failure)
161+ trap cleanup_keychain EXIT
162+
163+ # Delete any existing keychain from previous failed builds
164+ security delete-keychain " $KEYCHAIN_NAME " 2> /dev/null || true
165+
166+ security create-keychain -p " $KEYCHAIN_PASSWORD " " $KEYCHAIN_NAME "
167+ security unlock-keychain -p " $KEYCHAIN_PASSWORD " " $KEYCHAIN_NAME "
168+ security set-keychain-settings -t 3600 -u " $KEYCHAIN_NAME "
169+ security list-keychains -s " $KEYCHAIN_NAME " login.keychain
170+ security default-keychain -s " $KEYCHAIN_NAME "
171+
172+ # Import Apple WWDR G3 intermediate certificate to establish trust chain
173+ echo " Importing Apple WWDR G3 certificate..."
174+ WWDR_TEMP_DIR=$( mktemp -d)
175+ curl -sS -o " $WWDR_TEMP_DIR /AppleWWDRCAG3.cer" https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer
176+ security import " $WWDR_TEMP_DIR /AppleWWDRCAG3.cer" -k " $KEYCHAIN_NAME " -T /usr/bin/codesign
177+ rm -rf " $WWDR_TEMP_DIR "
178+ echo " Apple WWDR G3 certificate imported"
179+
180+ # Import user's certificate with private key
181+ security import " $IOS_CERT_PATH " -k " $KEYCHAIN_NAME " -P " $IOS_CERT_PASSWORD " -T /usr/bin/codesign
182+ security set-key-partition-list -S apple-tool:,apple: -s -k " $KEYCHAIN_PASSWORD " " $KEYCHAIN_NAME "
183+
184+ # Install provisioning profile
185+ PROFILE_DIR=" $HOME /Library/MobileDevice/Provisioning Profiles"
186+ mkdir -p " $PROFILE_DIR "
187+
188+ # Extract UUID from provisioning profile and copy with UUID as filename
189+ PROFILE_UUID=$( security cms -D -i " $IOS_PROVISIONING_PROFILE " 2> /dev/null | grep -A1 " <key>UUID</key>" | grep " <string>" | sed ' s/.*<string>\(.*\)<\/string>.*/\1/' )
190+
191+ # Remove existing profile if it exists (may have read-only permissions)
192+ rm -f " $PROFILE_DIR /$PROFILE_UUID .mobileprovision"
193+
194+ cp " $IOS_PROVISIONING_PROFILE " " $PROFILE_DIR /$PROFILE_UUID .mobileprovision"
195+
196+ echo " Installed provisioning profile: $PROFILE_UUID "
197+
198+ # Embed provisioning profile into the app bundle
199+ echo " Embedding provisioning profile into app..."
200+ cp " $IOS_PROVISIONING_PROFILE " " $BIN_DIR /Status.app/embedded.mobileprovision"
201+
202+ # Get signing identity (support both old "iPhone Distribution" and new "Apple Distribution")
203+ echo " Searching for signing identity in keychain..."
204+ security find-identity -v -p codesigning " $KEYCHAIN_NAME "
205+
206+ SIGNING_IDENTITY=$( security find-identity -v -p codesigning " $KEYCHAIN_NAME " | grep -E " iPhone Distribution|Apple Distribution" | head -1 | awk ' {print $2}' )
207+
208+ if [[ -z " $SIGNING_IDENTITY " ]]; then
209+ echo " ERROR: No Distribution certificate found in keychain!"
210+ echo " Available identities:"
211+ security find-identity -v -p codesigning " $KEYCHAIN_NAME "
212+ exit 1
213+ fi
214+
215+ echo " Signing with identity: $SIGNING_IDENTITY "
216+
217+ # Extract entitlements from provisioning profile
218+ echo " Extracting entitlements from provisioning profile..."
219+ ENTITLEMENTS_PLIST=$( mktemp -t entitlements) .plist
220+
221+ # Decode provisioning profile and extract entitlements in one step
222+ security cms -D -i " $IOS_PROVISIONING_PROFILE " | \
223+ plutil -extract Entitlements xml1 - -o " $ENTITLEMENTS_PLIST "
224+
225+ echo " Entitlements extracted to: $ENTITLEMENTS_PLIST "
226+ cat " $ENTITLEMENTS_PLIST "
227+
228+ # Sign all embedded frameworks first (required for App Store submission)
229+ echo " Signing embedded frameworks..."
230+ if [ -d " $BIN_DIR /Status.app/Frameworks" ]; then
231+ find " $BIN_DIR /Status.app/Frameworks" -name " *.framework" -type d | while read framework; do
232+ echo " Signing framework: $( basename " $framework " ) "
233+ codesign --force --sign " $SIGNING_IDENTITY " --timestamp " $framework "
234+ done
235+ fi
236+
237+ # Sign the main app bundle with entitlements from provisioning profile
238+ echo " Signing main app bundle..."
239+ codesign --force --sign " $SIGNING_IDENTITY " --entitlements " $ENTITLEMENTS_PLIST " --timestamp " $BIN_DIR /Status.app"
240+
241+ # Clean up temporary entitlements file
242+ rm -f " $ENTITLEMENTS_PLIST "
243+
244+ # Verify signature
245+ echo " Verifying signature..."
246+ codesign --verify --verbose=4 " $BIN_DIR /Status.app"
247+
248+ # Display signing details for debugging
249+ echo " Signature details:"
250+ codesign -d --entitlements :- " $BIN_DIR /Status.app"
251+
252+ echo " iOS app signed successfully"
253+
254+ # Create IPA file
255+ echo " Creating IPA file..."
256+ IPA_DIR=$( mktemp -d)
257+ mkdir -p " $IPA_DIR /Payload"
258+ cp -R " $BIN_DIR /Status.app" " $IPA_DIR /Payload/"
259+
260+ # Create IPA (which is just a zip with .ipa extension)
261+ cd " $IPA_DIR "
262+ zip -r " $BIN_DIR /Status.ipa" Payload
263+ cd -
264+
265+ rm -rf " $IPA_DIR "
266+ echo " IPA created at $BIN_DIR /Status.ipa"
267+ fi
268+
269+ echo " Build succeeded"
125270fi
0 commit comments