-
Notifications
You must be signed in to change notification settings - Fork 225
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Automate build of iOS signed ipa file for App Store submission #2625
base: main
Are you sure you want to change the base?
Changes from 2 commits
2e5acc4
5da2236
57e7f6e
2806482
1ad1d31
731e46c
1f3fe64
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,17 +30,76 @@ setup() { | |
fi | ||
} | ||
|
||
|
||
prepare_signing() { | ||
[[ "${SIGN_IF_POSSIBLE:-0}" == "1" ]] || return 1 | ||
|
||
# Signing was requested, now check all prerequisites: | ||
[[ -n "${IOSDIST_CERTIFICATE:-}" ]] || return 1 | ||
[[ -n "${IOSDIST_CERTIFICATE_ID:-}" ]] || return 1 | ||
[[ -n "${IOSDIST_CERTIFICATE_PWD:-}" ]] || return 1 | ||
[[ -n "${NOTARIZATION_PASSWORD:-}" ]] || return 1 | ||
[[ -n "${IOS_PROV_PROFILE_B64:-}" ]] || return 1 | ||
[[ -n "${KEYCHAIN_PASSWORD:-}" ]] || return 1 | ||
|
||
echo "Signing was requested and all dependencies are satisfied" | ||
|
||
# use this as filename for Provisioning Profile | ||
IOS_PP_PATH="embedded.mobileprovision" | ||
|
||
## Put the cert to a file | ||
# IOSDIST_CERTIFICATE - iOS Distribution | ||
echo "${IOSDIST_CERTIFICATE}" | base64 --decode > iosdist_certificate.p12 | ||
|
||
## Echo Provisioning Profile to file | ||
echo -n "${IOS_PROV_PROFILE_B64}" | base64 --decode > $IOS_PP_PATH | ||
|
||
# Set up a keychain for the build: | ||
security create-keychain -p "${KEYCHAIN_PASSWORD}" build.keychain | ||
security default-keychain -s build.keychain | ||
security unlock-keychain -p "${KEYCHAIN_PASSWORD}" build.keychain | ||
security import iosdist_certificate.p12 -k build.keychain -P "${IOSDIST_CERTIFICATE_PWD}" -A -T /usr/bin/codesign | ||
# security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "${KEYCHAIN_PASSWORD}" build.keychain | ||
security set-key-partition-list -S apple-tool:,apple: -s -k "${KEYCHAIN_PASSWORD}" build.keychain | ||
# set lock timeout on keychain to 6 hours | ||
security set-keychain-settings -lut 21600 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As in the macOS case - maybe this is no longer needed. |
||
|
||
# apply provisioning profile | ||
#FIXME - maybe redundant? | ||
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles | ||
cp $IOS_PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles | ||
|
||
# for debug | ||
echo "Checking found identities..." | ||
security find-identity -v | ||
|
||
# Tell Github Workflow that we need notarization & stapling: | ||
echo "::set-output name=macos_signed::true" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should be renamed to apple_signed if we merge this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. or maybe ios_signed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ann0see it is actually possible to upload the binary to the App Store, using "altool" as outlined here: https://help.apple.com/app-store-connect/#/devb1c185036 However, as the App Store submission process involves a number of manual setup steps anyway (ie creating the actual submission on the App Store Connect website, adding screenshots, descriptions, compliance details and all sorts) and you likely only want to upload specific versions to the App Store (rather than having it run automatically), I thought the generation of the signed, verifiable IPA is a big enough win for this automation. Quick note: the only manual step remaining once you have the signed IPA is to drag and drop the IPA file into Transporter (on macOS), and click the Upload button. If I have time today though I will experiment with adding the upload directly using xcrun altool. |
||
return 0 | ||
} | ||
|
||
build_app_as_ipa() { | ||
# Add the Qt binaries to the PATH: | ||
export PATH="${QT_DIR}/${QT_VERSION}/ios/bin:${PATH}" | ||
./ios/deploy_ios.sh | ||
|
||
# Mac's bash version considers BUILD_ARGS unset without at least one entry: | ||
BUILD_ARGS=("") | ||
if prepare_signing; then | ||
BUILD_ARGS=("-s" "${IOSDIST_CERTIFICATE_ID}" "-k" "${KEYCHAIN_PASSWORD}") | ||
fi | ||
./ios/deploy_ios.sh "${BUILD_ARGS[@]}" | ||
} | ||
|
||
pass_artifact_to_job() { | ||
local artifact="jamulus_${JAMULUS_BUILD_VERSION}_iOSUnsigned${ARTIFACT_SUFFIX:-}.ipa" | ||
local artifact="jamulus_${JAMULUS_BUILD_VERSION}_iOS_unsigned${ARTIFACT_SUFFIX:-}.ipa" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure how much a signed IPA on the web without the app store helps? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think there's any point to that, no - the signed IPA is purely for App Store submission. So it's really for @emlynmac or whoever is managing the Jamulus App Store account to have a ready-built file for submission. I assume the unsigned IPA is useful for general testing purposes so obviously I've kept that in. |
||
echo "Moving build artifact to deploy/${artifact}" | ||
mv ./deploy/Jamulus.ipa "./deploy/${artifact}" | ||
mv ./deploy/Jamulus_unsigned.ipa "./deploy/${artifact}" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably not worth keeping this around, only signed version would be useful past making sure the build works. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, I left a note above, I wasn't sure if people were maybe using the unsigned IPA for local testing or somesuch. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should not be removed IMO. |
||
echo "::set-output name=artifact_1::${artifact}" | ||
|
||
local artifact2="jamulus_${JAMULUS_BUILD_VERSION}_iOS_signed${ARTIFACT_SUFFIX:-}.ipa" | ||
echo "Moving build artifact to deploy/${artifact2}" | ||
mv ./deploy/Jamulus_signed.ipa "./deploy/${artifact2}" | ||
echo "::set-output name=artifact_2::${artifact2}" | ||
} | ||
|
||
case "${1:-}" in | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -149,13 +149,13 @@ jobs: | |
|
||
- config_name: iOS (artifacts) | ||
target_os: ios | ||
building_on_os: macos-10.15 | ||
base_command: QT_VERSION=5.15.2 ./.github/autobuild/ios.sh | ||
building_on_os: macos-11 | ||
base_command: QT_VERSION=5.15.2 SIGN_IF_POSSIBLE=1 ./.github/autobuild/ios.sh | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you use the presence of a certificate in the environment to determine whether to sign, so not needing another parameter? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would rather follow the lead as being done for macOS, which uses that flag. Or we can remove from both macOS and iOS but to have in just one feels weird. |
||
# Build failed with CodeQL enabled when last tested 03/2022 (#2490). | ||
# There are no hints that iOS is supposed to be supported by CodeQL. | ||
# Therefore, disable it: | ||
run_codeql: false | ||
xcode_version: 12.1.1 | ||
xcode_version: 13.2.1 | ||
|
||
- config_name: Windows (artifact+codeQL) | ||
target_os: windows | ||
|
@@ -232,6 +232,10 @@ jobs: | |
MACOS_CERTIFICATE: ${{ secrets.MACOS_CERT}} | ||
MACOS_CERTIFICATE_PWD: ${{ secrets.MACOS_CERT_PWD }} | ||
MACOS_CERTIFICATE_ID: ${{ secrets.MACOS_CERT_ID }} | ||
IOSDIST_CERTIFICATE: ${{ secrets.IOSDIST_CERT}} | ||
IOSDIST_CERTIFICATE_PWD: ${{ secrets.IOSDIST_CERT_PWD }} | ||
IOSDIST_CERTIFICATE_ID: ${{ secrets.IOSDIST_CERT_ID }} | ||
IOS_PROV_PROFILE_B64: ${{ secrets.IOS_PROVISIONING_PROFILE }} | ||
NOTARIZATION_PASSWORD: ${{ secrets.NOTARIZATION_PASSWORD }} | ||
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
<plist version="1.0"> | ||
<dict> | ||
<key>CFBundleExecutable</key> | ||
<string>@EXECUTABLE@</string> | ||
<key>CFBundleIdentifier</key> | ||
<string>@BUNDLEIDENTIFIER@</string> | ||
<key>CFBundleInfoDictionaryVersion</key> | ||
<string>6.0</string> | ||
<key>CFBundleName</key> | ||
<string>@EXECUTABLE@</string> | ||
<key>CFBundlePackageType</key> | ||
<string>APPL</string> | ||
<key>CFBundleShortVersionString</key> | ||
<string>1.0</string> | ||
<key>CFBundleVersion</key> | ||
<string>1</string> | ||
<key>LSRequiresIPhoneOS</key> | ||
<true/> | ||
<key>NSMicrophoneUsageDescription</key> | ||
<string>We need access to your microphone to let others hear you.</string> | ||
<key>UIApplicationSceneManifest</key> | ||
<dict> | ||
<key>UIApplicationSupportsMultipleScenes</key> | ||
<false/> | ||
</dict> | ||
<key>UIApplicationSupportsIndirectInputEvents</key> | ||
<true/> | ||
<key>UIBackgroundModes</key> | ||
<array> | ||
<string>audio</string> | ||
</array> | ||
<key>UILaunchScreen</key> | ||
<dict/> | ||
<key>UILaunchStoryboardName</key> | ||
<string>LaunchScreen</string> | ||
<key>UIRequiredDeviceCapabilities</key> | ||
<array> | ||
<string>armv7</string> | ||
</array> | ||
<key>UISupportedInterfaceOrientations</key> | ||
<array> | ||
<string>UIInterfaceOrientationPortrait</string> | ||
<string>UIInterfaceOrientationLandscapeLeft</string> | ||
<string>UIInterfaceOrientationLandscapeRight</string> | ||
</array> | ||
<key>UISupportedInterfaceOrientations~ipad</key> | ||
<array> | ||
<string>UIInterfaceOrientationPortrait</string> | ||
<string>UIInterfaceOrientationPortraitUpsideDown</string> | ||
<string>UIInterfaceOrientationLandscapeLeft</string> | ||
<string>UIInterfaceOrientationLandscapeRight</string> | ||
</array> | ||
|
||
</dict> | ||
</plist> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
<plist version="1.0"> | ||
<dict> | ||
<key>CFBundleDevelopmentRegion</key> | ||
<string>$(DEVELOPMENT_LANGUAGE)</string> | ||
<key>CFBundleExecutable</key> | ||
<string>$(EXECUTABLE_NAME)</string> | ||
<key>CFBundleIdentifier</key> | ||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> | ||
<key>CFBundleInfoDictionaryVersion</key> | ||
<string>6.0</string> | ||
<key>CFBundleName</key> | ||
<string>$(PRODUCT_NAME)</string> | ||
<key>CFBundlePackageType</key> | ||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string> | ||
<key>CFBundleShortVersionString</key> | ||
<string>1.0</string> | ||
<key>CFBundleVersion</key> | ||
<string>1</string> | ||
<key>LSRequiresIPhoneOS</key> | ||
<true/> | ||
<key>NSMicrophoneUsageDescription</key> | ||
<string>We need access to your microphone to let others hear you.</string> | ||
<key>UIApplicationSceneManifest</key> | ||
<dict> | ||
<key>UIApplicationSupportsMultipleScenes</key> | ||
<false/> | ||
</dict> | ||
<key>UIApplicationSupportsIndirectInputEvents</key> | ||
<true/> | ||
<key>UIBackgroundModes</key> | ||
<array> | ||
<string>audio</string> | ||
</array> | ||
<key>UILaunchScreen</key> | ||
<dict/> | ||
<key>UILaunchStoryboardName</key> | ||
<string>LaunchScreen</string> | ||
<key>UIRequiredDeviceCapabilities</key> | ||
<array> | ||
<string>armv7</string> | ||
</array> | ||
<key>UISupportedInterfaceOrientations</key> | ||
<array> | ||
<string>UIInterfaceOrientationPortrait</string> | ||
<string>UIInterfaceOrientationLandscapeLeft</string> | ||
<string>UIInterfaceOrientationLandscapeRight</string> | ||
</array> | ||
<key>UISupportedInterfaceOrientations~ipad</key> | ||
<array> | ||
<string>UIInterfaceOrientationPortrait</string> | ||
<string>UIInterfaceOrientationPortraitUpsideDown</string> | ||
<string>UIInterfaceOrientationLandscapeLeft</string> | ||
<string>UIInterfaceOrientationLandscapeRight</string> | ||
</array> | ||
|
||
</dict> | ||
</plist> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,113 @@ | ||
#!/bin/bash | ||
set -eu | ||
|
||
## Builds an ipa file for iOS. Should be run from the repo-root | ||
root_path="$(pwd)" | ||
project_path="${root_path}/Jamulus.pro" | ||
iosdeploy_path="${root_path}/ios" | ||
resources_path="${root_path}/src/res" | ||
build_path="${root_path}/build" | ||
deploy_path="${root_path}/deploy" | ||
iosdist_cert_name="" | ||
keychain_pass="" | ||
|
||
# Create Xcode file and build | ||
qmake -spec macx-xcode Jamulus.pro | ||
/usr/bin/xcodebuild -project Jamulus.xcodeproj -scheme Jamulus -configuration Release clean archive -archivePath "build/Jamulus.xcarchive" CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO CODE_SIGN_ENTITLEMENTS="" | ||
while getopts 'hs:k:' flag; do | ||
case "${flag}" in | ||
s) | ||
iosdist_cert_name=$OPTARG | ||
if [[ -z "$iosdist_cert_name" ]]; then | ||
echo "Please add the name of the certificate to use: -s \"<name>\"" | ||
fi | ||
;; | ||
k) | ||
keychain_pass=$OPTARG | ||
if [[ -z "$keychain_pass" ]]; then | ||
echo "Please add keychain password to use: -k \"<name>\"" | ||
fi | ||
;; | ||
h) | ||
echo "Usage: -s <cert name> for signing ios build" | ||
exit 0 | ||
;; | ||
*) | ||
exit 1 | ||
;; | ||
esac | ||
done | ||
|
||
# Generate ipa by copying the .app file from the xcarchive directory | ||
mkdir build/Payload | ||
cp -r build/Jamulus.xcarchive/Products/Applications/Jamulus.app build/Payload/ | ||
cd build | ||
zip -0 -y -r Jamulus.ipa Payload/ | ||
cleanup() | ||
{ | ||
# Clean up previous deployments | ||
rm -rf "${build_path}" | ||
rm -rf "${deploy_path}" | ||
mkdir -p "${build_path}" | ||
mkdir -p "${build_path}/Exports" | ||
mkdir -p "${deploy_path}" | ||
} | ||
|
||
# Make a deploy folder and copy file | ||
mkdir ../deploy | ||
mv Jamulus.ipa ../deploy | ||
build_ipa() | ||
{ | ||
## Builds an ipa file for iOS. Should be run from the repo-root | ||
|
||
# Create Xcode project file | ||
qmake -spec macx-xcode Jamulus.pro | ||
|
||
# disable deprecation warnings re legacy build system - XCode 13 errors on this | ||
/usr/libexec/PlistBuddy -c "Add :DisableBuildSystemDeprecationDiagnostic bool" Jamulus.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings | ||
/usr/libexec/PlistBuddy -c "Set :DisableBuildSystemDeprecationDiagnostic true" Jamulus.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings | ||
|
||
# Build | ||
if [[ -z "$iosdist_cert_name" ]]; then | ||
# Build unsigned | ||
/usr/bin/xcodebuild -project Jamulus.xcodeproj -scheme Jamulus -configuration Release clean archive \ | ||
-archivePath "build/Jamulus.xcarchive" \ | ||
CODE_SIGN_IDENTITY="" \ | ||
CODE_SIGNING_REQUIRED=NO \ | ||
CODE_SIGNING_ALLOWED=NO \ | ||
CODE_SIGN_ENTITLEMENTS="" | ||
else | ||
# Build signed ipa file | ||
# Ref: https://developer.apple.com/forums/thread/70326 | ||
# // Builds the app into an archive | ||
/usr/bin/xcodebuild -project Jamulus.xcodeproj -scheme Jamulus -configuration Release clean archive \ | ||
-archivePath "build/Jamulus.xcarchive" \ | ||
DEVELOPMENT_TEAM="XXXXXXXXXX" \ | ||
CODE_SIGN_IDENTITY="" \ | ||
CODE_SIGNING_REQUIRED=NO \ | ||
CODE_SIGNING_ALLOWED=NO | ||
|
||
#FIXME this may be redundant - since provisioning profile is specified in exportOptionsRelease.plist | ||
cp ~/Library/MobileDevice/Provisioning\ Profiles/embedded.mobileprovision build/Jamulus.xcarchive/Products/Applications/Jamulus.app/ | ||
|
||
# // Exports the archive according to the export options specified by the plist | ||
# export signed installer to build/Exports/Jamulus.ipa | ||
/usr/bin/xcodebuild -exportArchive \ | ||
-archivePath "build/Jamulus.xcarchive" \ | ||
-exportPath "build/Exports/" \ | ||
-exportOptionsPlist "ios/exportOptionsRelease.plist" \ | ||
DEVELOPMENT_TEAM="XXXXXXXXXX" \ | ||
CODE_SIGN_IDENTITY="${iosdist_cert_name}" \ | ||
CODE_SIGNING_REQUIRED=YES \ | ||
CODE_SIGNING_ALLOWED=YES \ | ||
CODE_SIGN_STYLE="Manual" | ||
fi | ||
|
||
# Generate unsigned ipa by copying the .app structure from the xcarchive directory | ||
cd ${root_path} | ||
mkdir -p build/unsigned/Payload | ||
cp -r build/Jamulus.xcarchive/Products/Applications/Jamulus.app build/unsigned/Payload/ | ||
cd build/unsigned | ||
zip -0 -y -r Jamulus.ipa Payload/ | ||
|
||
# copy files | ||
cd ${root_path} | ||
# unsigned IPA | ||
mv build/unsigned/Jamulus.ipa deploy/Jamulus_unsigned.ipa | ||
# signed IPA | ||
mv build/Exports/Jamulus.ipa deploy/Jamulus_signed.ipa | ||
} | ||
|
||
# Cleanup previous deployments | ||
cleanup | ||
|
||
# Build ipa file for App Store submission (eg via Transporter etc) | ||
build_ipa |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
<plist version="1.0"> | ||
<dict> | ||
<key>method</key> | ||
<string>app-store</string> | ||
<key>teamID</key> | ||
<string>XXXXXXXXXX</string> | ||
<key>provisioningProfiles</key> | ||
<dict> | ||
<key>io.jamulus.Jamulus</key> | ||
<string>UUID_GOES_HERE</string> | ||
</dict> | ||
</dict> | ||
</plist> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As in the macOS case, probably worth putting distribution related stuff in an if.