CI: signed iOS build and TestFlight upload on Release tags
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
f6407c447e
commit
ca4afb2ed7
@@ -0,0 +1,26 @@
|
|||||||
|
# CI-only: switches the Release configuration of the Runner and ShareExtension
|
||||||
|
# targets to manual signing with the App Store profiles. The committed project
|
||||||
|
# stays on Automatic signing so local development is unaffected; this edit
|
||||||
|
# happens only inside the CI checkout. Run from the repo root:
|
||||||
|
# ruby .gitea/scripts/ios_ci_signing.rb
|
||||||
|
require "xcodeproj"
|
||||||
|
|
||||||
|
TEAM = "Q3JLTAG9PV"
|
||||||
|
PROFILES = {
|
||||||
|
"Runner" => "NooProfile",
|
||||||
|
"ShareExtension" => "NooShareSheetProfile",
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
project = Xcodeproj::Project.open("ios/Runner.xcodeproj")
|
||||||
|
PROFILES.each do |target_name, profile|
|
||||||
|
target = project.targets.find { |t| t.name == target_name } or abort("no target #{target_name}")
|
||||||
|
target.build_configurations.select { |c| c.name == "Release" }.each do |config|
|
||||||
|
settings = config.build_settings
|
||||||
|
settings["CODE_SIGN_STYLE"] = "Manual"
|
||||||
|
settings["DEVELOPMENT_TEAM"] = TEAM
|
||||||
|
settings["CODE_SIGN_IDENTITY"] = "Apple Distribution"
|
||||||
|
settings["CODE_SIGN_IDENTITY[sdk=iphoneos*]"] = "Apple Distribution"
|
||||||
|
settings["PROVISIONING_PROFILE_SPECIFIER"] = profile
|
||||||
|
end
|
||||||
|
end
|
||||||
|
project.save
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
name: Build iOS
|
||||||
|
|
||||||
|
# Same trigger as the Play Store bundle (release.yml): a real release tag.
|
||||||
|
# git tag Release-1.0.0 && git push origin Release-1.0.0
|
||||||
|
# Builds a signed .ipa, attaches it to the Gitea release, and uploads it to
|
||||||
|
# TestFlight. Needs a Mac runner registered with the `macos` label (act_runner
|
||||||
|
# in host mode) with Xcode installed; Linux runners cannot build iOS.
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "Release-*"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: macos
|
||||||
|
steps:
|
||||||
|
- name: Check out code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Flutter
|
||||||
|
uses: subosito/flutter-action@v2
|
||||||
|
with:
|
||||||
|
channel: stable
|
||||||
|
|
||||||
|
- name: Check tag matches pubspec version
|
||||||
|
run: |
|
||||||
|
VERSION=$(grep '^version:' pubspec.yaml | sed 's/version: //' | cut -d'+' -f1)
|
||||||
|
if [ "${GITHUB_REF_NAME}" != "Release-${VERSION}" ]; then
|
||||||
|
echo "Tag ${GITHUB_REF_NAME} does not match pubspec version ${VERSION}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: flutter pub get
|
||||||
|
|
||||||
|
- name: Analyze
|
||||||
|
run: flutter analyze
|
||||||
|
|
||||||
|
- name: Install signing certificate and profiles
|
||||||
|
# A throwaway keychain keeps the distribution key off the runner's
|
||||||
|
# login keychain; it is deleted again in the cleanup step.
|
||||||
|
env:
|
||||||
|
CERT_P12_BASE64: ${{ secrets.IOS_DIST_CERT_P12_BASE64 }}
|
||||||
|
CERT_PASSWORD: ${{ secrets.IOS_DIST_CERT_PASSWORD }}
|
||||||
|
APP_PROFILE_BASE64: ${{ secrets.IOS_APP_PROFILE_BASE64 }}
|
||||||
|
EXT_PROFILE_BASE64: ${{ secrets.IOS_EXT_PROFILE_BASE64 }}
|
||||||
|
run: |
|
||||||
|
KEYCHAIN="${{ runner.temp }}/ci-signing.keychain-db"
|
||||||
|
KEYCHAIN_PASSWORD=$(uuidgen)
|
||||||
|
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN"
|
||||||
|
security set-keychain-settings -lut 21600 "$KEYCHAIN"
|
||||||
|
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN"
|
||||||
|
echo "$CERT_P12_BASE64" | base64 -d > "${{ runner.temp }}/dist.p12"
|
||||||
|
security import "${{ runner.temp }}/dist.p12" -P "$CERT_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN"
|
||||||
|
security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN"
|
||||||
|
security list-keychains -d user -s "$KEYCHAIN" $(security list-keychains -d user | tr -d '"')
|
||||||
|
rm -f "${{ runner.temp }}/dist.p12"
|
||||||
|
|
||||||
|
PROFILES_DIR="$HOME/Library/MobileDevice/Provisioning Profiles"
|
||||||
|
mkdir -p "$PROFILES_DIR"
|
||||||
|
echo "$APP_PROFILE_BASE64" | base64 -d > "$PROFILES_DIR/NooProfile.mobileprovision"
|
||||||
|
echo "$EXT_PROFILE_BASE64" | base64 -d > "$PROFILES_DIR/NooShareSheetProfile.mobileprovision"
|
||||||
|
|
||||||
|
- name: Switch Release config to manual signing
|
||||||
|
run: ruby .gitea/scripts/ios_ci_signing.rb
|
||||||
|
|
||||||
|
- name: Build signed IPA
|
||||||
|
run: flutter build ipa --release --export-options-plist=ios/ExportOptions.plist
|
||||||
|
|
||||||
|
- name: Rename IPA to Noo-<version>.ipa
|
||||||
|
run: |
|
||||||
|
VERSION=$(grep '^version:' pubspec.yaml | sed 's/version: //' | cut -d'+' -f1)
|
||||||
|
mkdir -p release
|
||||||
|
cp build/ios/ipa/*.ipa "release/Noo-${VERSION}.ipa"
|
||||||
|
echo "IPA_PATH=release/Noo-${VERSION}.ipa" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
|
- name: Upload to TestFlight
|
||||||
|
env:
|
||||||
|
ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
|
||||||
|
ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
|
||||||
|
ASC_KEY_P8_BASE64: ${{ secrets.ASC_KEY_P8_BASE64 }}
|
||||||
|
run: |
|
||||||
|
mkdir -p "$HOME/.appstoreconnect/private_keys"
|
||||||
|
echo "$ASC_KEY_P8_BASE64" | base64 -d > "$HOME/.appstoreconnect/private_keys/AuthKey_${ASC_KEY_ID}.p8"
|
||||||
|
xcrun altool --upload-app -f "$IPA_PATH" -t ios \
|
||||||
|
--apiKey "$ASC_KEY_ID" --apiIssuer "$ASC_ISSUER_ID"
|
||||||
|
|
||||||
|
- name: Cleanup signing material
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
security delete-keychain "${{ runner.temp }}/ci-signing.keychain-db" || true
|
||||||
|
rm -f "$HOME/Library/MobileDevice/Provisioning Profiles/NooProfile.mobileprovision" \
|
||||||
|
"$HOME/Library/MobileDevice/Provisioning Profiles/NooShareSheetProfile.mobileprovision"
|
||||||
|
rm -rf "$HOME/.appstoreconnect/private_keys"
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<?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-connect</string>
|
||||||
|
<key>teamID</key>
|
||||||
|
<string>Q3JLTAG9PV</string>
|
||||||
|
<key>signingStyle</key>
|
||||||
|
<string>manual</string>
|
||||||
|
<key>signingCertificate</key>
|
||||||
|
<string>Apple Distribution</string>
|
||||||
|
<key>provisioningProfiles</key>
|
||||||
|
<dict>
|
||||||
|
<key>dev.ayushya.noo</key>
|
||||||
|
<string>NooProfile</string>
|
||||||
|
<key>dev.ayushya.noo.ShareExtension</key>
|
||||||
|
<string>NooShareSheetProfile</string>
|
||||||
|
</dict>
|
||||||
|
<key>uploadSymbols</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -86,5 +86,7 @@
|
|||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
</array>
|
</array>
|
||||||
|
<key>ITSAppUsesNonExemptEncryption</key>
|
||||||
|
<false/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
Reference in New Issue
Block a user