forked from ARK-Builders/Drop
-
Notifications
You must be signed in to change notification settings - Fork 0
Integrate iOS App #3
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
Closed
Closed
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
3920728
Integrate SKIE
mdrlzy b1b32ca
Implement iOS native bindings and fix build configuration
1ba0789
Adressed some bugs
2b98626
Removed unncecessary md file
f72b9be
Add Fastlane CI/CD for iOS builds
b209e6d
Fix CI: remove macOS-specific org.gradle.java.home from gradle.properβ¦
81d157d
Added fastlane build log
efbc14e
Fix iOS CI build errors
d655254
Fix copyFrameworkForXcode for configuration-cache compatibility
2ddc6c1
Use dev.ark-builders.drop bundle ID, add XCFramework Info.plist fallback
b3bc180
Use cp -R for XCFramework copy to preserve full directory structure
466d63f
Set iOS marketing version to 1.1 for App Store upload
b26d388
Add iOS app icons to fix TestFlight upload validation
74d83d0
Fix app icon: replace with non-transparent icon for App Store validatβ¦
d4bda20
Use macos-26 runner and Xcode 26.2 for iOS release
be95e65
Fix OpenSSL 3: add -legacy flag for Apple p12 (RC2-40-CBC) on macos-26
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,373 @@ | ||
| name: Release iOS App | ||
|
|
||
| # Trigger: push tags or manual dispatch | ||
| on: | ||
| push: | ||
| tags: | ||
| - 'v*' | ||
| branches: | ||
| - 'feature/kmp-ios-impl' # TEMPORARY: Remove after testing | ||
| workflow_dispatch: | ||
|
|
||
| jobs: | ||
| build: | ||
| runs-on: macos-26 # macOS 26 Tahoe with Xcode 26.2 (required for App Store from Apr 28, 2026 - ITMS-90725) | ||
| environment: Testflight | ||
|
|
||
| env: | ||
| APP_BUNDLE_ID: dev.ark-builders.drop | ||
| APP_TEAM_ID: SQNXHTL7FT | ||
| IOS_P12_PASSWORD: ${{ secrets.IOS_P12_PASSWORD }} | ||
| ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }} | ||
| ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }} | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| steps: | ||
| # 1οΈβ£ Checkout code | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 | ||
|
|
||
| # π Diagnostic: Check all secrets availability | ||
| - name: Validate Secrets | ||
| run: | | ||
| echo "π Checking which secrets are available..." | ||
| echo "" | ||
|
|
||
| # Check each required secret | ||
| MISSING_SECRETS=() | ||
|
|
||
| if [ -z "${{ secrets.IOS_P12_BASE64 }}" ]; then | ||
| echo "β IOS_P12_BASE64 - MISSING or EMPTY" | ||
| MISSING_SECRETS+=("IOS_P12_BASE64") | ||
| else | ||
| echo "β IOS_P12_BASE64 - Available (${#IOS_P12_BASE64} chars)" | ||
| fi | ||
|
|
||
| if [ -z "${{ secrets.IOS_P12_PASSWORD }}" ]; then | ||
| echo "β IOS_P12_PASSWORD - MISSING or EMPTY" | ||
| MISSING_SECRETS+=("IOS_P12_PASSWORD") | ||
| else | ||
| echo "β IOS_P12_PASSWORD - Available" | ||
| fi | ||
|
|
||
| if [ -z "${{ secrets.IOS_PROFILE_BASE64 }}" ]; then | ||
| echo "β IOS_PROFILE_BASE64 - MISSING or EMPTY" | ||
| MISSING_SECRETS+=("IOS_PROFILE_BASE64") | ||
| else | ||
| echo "β IOS_PROFILE_BASE64 - Available (${#IOS_PROFILE_BASE64} chars)" | ||
| fi | ||
|
|
||
| if [ -z "${{ secrets.ASC_API_KEY_BASE64 }}" ]; then | ||
| echo "β ASC_API_KEY_BASE64 - MISSING or EMPTY" | ||
| MISSING_SECRETS+=("ASC_API_KEY_BASE64") | ||
| else | ||
| echo "β ASC_API_KEY_BASE64 - Available (${#ASC_API_KEY_BASE64} chars)" | ||
| fi | ||
|
|
||
| if [ -z "${{ secrets.ASC_KEY_ID }}" ]; then | ||
| echo "β ASC_KEY_ID - MISSING or EMPTY" | ||
| MISSING_SECRETS+=("ASC_KEY_ID") | ||
| else | ||
| echo "β ASC_KEY_ID - Available" | ||
| fi | ||
|
|
||
| if [ -z "${{ secrets.ASC_ISSUER_ID }}" ]; then | ||
| echo "β ASC_ISSUER_ID - MISSING or EMPTY" | ||
| MISSING_SECRETS+=("ASC_ISSUER_ID") | ||
| else | ||
| echo "β ASC_ISSUER_ID - Available" | ||
| fi | ||
|
|
||
| echo "" | ||
| echo "π Summary: ${#MISSING_SECRETS[@]} secrets missing" | ||
|
|
||
| if [ ${#MISSING_SECRETS[@]} -gt 0 ]; then | ||
| echo "" | ||
| echo "β οΈ Missing secrets need to be added to:" | ||
| echo " Settings β Environments β Testflight β Environment secrets" | ||
| echo "" | ||
| echo "Current repository: ${{ github.repository }}" | ||
| echo "Current environment: Testflight" | ||
| exit 1 | ||
| fi | ||
|
|
||
| echo "" | ||
| echo "β All required secrets are available!" | ||
| env: | ||
| IOS_P12_BASE64: ${{ secrets.IOS_P12_BASE64 }} | ||
| IOS_PROFILE_BASE64: ${{ secrets.IOS_PROFILE_BASE64 }} | ||
| ASC_API_KEY_BASE64: ${{ secrets.ASC_API_KEY_BASE64 }} | ||
|
|
||
| # 2οΈβ£ Setup Ruby and Fastlane | ||
| - name: Setup Ruby | ||
| uses: ruby/setup-ruby@v1 | ||
| with: | ||
| ruby-version: "3.2" | ||
| bundler-cache: true | ||
|
|
||
| - name: Install gems | ||
| run: bundle install | ||
|
|
||
| # 3οΈβ£ Build Kotlin framework before Xcode (required for KMP - Xcode expects it at XCFrameworks/debug) | ||
| - name: Build Kotlin framework for Release | ||
| run: | | ||
| export JAVA_HOME=$(/usr/libexec/java_home -v 17) | ||
| ./gradlew :shared:assembleSharedReleaseXCFramework | ||
| mkdir -p shared/build/XCFrameworks/debug | ||
| cp -R shared/build/XCFrameworks/release/shared.xcframework shared/build/XCFrameworks/debug/ | ||
|
|
||
| # 3b Ensure XCFramework has Info.plist (Kotlin may not create it; Xcode requires it) | ||
| - name: Ensure XCFramework Info.plist | ||
| run: | | ||
| XCF_DIR="shared/build/XCFrameworks/debug/shared.xcframework" | ||
| if [ ! -f "$XCF_DIR/Info.plist" ]; then | ||
| echo "Creating Info.plist for XCFramework..." | ||
| cp shared/build/XCFrameworks/release/shared.xcframework/Info.plist "$XCF_DIR/" 2>/dev/null || \ | ||
| cp shared/XCFramework-Info.plist "$XCF_DIR/Info.plist" | ||
| echo "β Info.plist ready" | ||
| else | ||
| echo "β Info.plist already exists" | ||
| fi | ||
|
|
||
| # 4οΈβ£ Setup Xcode 26.2 (macos-26 has it pre-installed) | ||
| - name: Select Xcode version | ||
| uses: maxim-lobanov/setup-xcode@v1 | ||
| with: | ||
| xcode-version: '26.2' | ||
|
|
||
| # 4οΈβ£ Decode certificate (Fastlane will import it) | ||
| - name: Decode iOS certificate | ||
| run: | | ||
| # Check if the secret exists and is not empty | ||
| if [ -z "$IOS_P12_BASE64" ]; then | ||
| echo "β ERROR: IOS_P12_BASE64 secret is missing or empty!" | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Decode certificate | ||
| echo "$IOS_P12_BASE64" | base64 --decode > cert.p12 | ||
|
|
||
| # Verify the .p12 file was created and has content | ||
| FILE_SIZE=$(stat -f%z cert.p12) | ||
| echo "β Certificate file size: $FILE_SIZE bytes" | ||
|
|
||
| if [ "$FILE_SIZE" -lt 100 ]; then | ||
| echo "β ERROR: Certificate file is too small, likely corrupted" | ||
| exit 1 | ||
| fi | ||
| env: | ||
| IOS_P12_BASE64: ${{ secrets.IOS_P12_BASE64 }} | ||
|
|
||
| # 6οΈβ£ Validate iOS certificate contains private key | ||
| - name: Validate iOS certificate contains private key | ||
| run: | | ||
| set +e # Don't exit on openssl failure - we need to show the error | ||
| echo "π Validating p12 certificate contents..." | ||
| echo "" | ||
|
|
||
| # Check if p12 file exists | ||
| if [ ! -f cert.p12 ]; then | ||
| echo "β ERROR: cert.p12 file not found!" | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Test 1: Check for PRIVATE KEY in p12 structure | ||
| # -legacy: OpenSSL 3.x on macos-26 disables RC2-40-CBC; Apple p12 often uses it | ||
| echo "π Test 1: Checking p12 structure for private key..." | ||
| CERT_CONTENTS=$(openssl pkcs12 -in cert.p12 -legacy -nodes -passin env:IOS_P12_PASSWORD 2>&1) | ||
| OPENSSL_EXIT=$? | ||
| set -e | ||
|
|
||
| if [ $OPENSSL_EXIT -ne 0 ]; then | ||
| echo "β ERROR: OpenSSL failed to read p12 (exit code $OPENSSL_EXIT)" | ||
| echo "" | ||
| echo "Output: $CERT_CONTENTS" | ||
| echo "" | ||
| echo "π‘ Possible causes: wrong IOS_P12_PASSWORD, or OpenSSL 3 on macos-26 (we use -legacy for Apple p12)" | ||
| exit 1 | ||
| fi | ||
|
|
||
| HAS_PRIVATE_KEY=true | ||
|
|
||
| if echo "$CERT_CONTENTS" | grep -q "PRIVATE KEY"; then | ||
| echo "β Private key found in p12 certificate structure" | ||
| else | ||
| echo "β ERROR: p12 certificate does NOT contain a private key in its structure!" | ||
| HAS_PRIVATE_KEY=false | ||
| fi | ||
|
|
||
| # Test 2: Check if private key can be extracted (nocerts flag) - informational only | ||
| echo "" | ||
| echo "π Test 2: Attempting to extract private key only (nocerts)..." | ||
| if openssl pkcs12 -in cert.p12 -legacy -nocerts -passin pass:"$IOS_P12_PASSWORD" >/dev/null 2>&1; then | ||
| echo "β Private key can be extracted separately" | ||
| else | ||
| echo "β οΈ Note: nocerts extraction failed (this is OK if Test 1 passed)" | ||
| fi | ||
|
|
||
| # Test 3: Alternative private key check using env variable - informational only | ||
| echo "" | ||
| echo "π Test 3: Alternative private key extraction test..." | ||
| if openssl pkcs12 -in cert.p12 -legacy -nocerts -passin env:IOS_P12_PASSWORD >/dev/null 2>&1; then | ||
| echo "β Alternative extraction succeeded" | ||
| else | ||
| echo "β οΈ Note: Alternative extraction failed (this is OK if Test 1 passed)" | ||
| fi | ||
|
|
||
| # Test 4: Show certificate details | ||
| echo "" | ||
| echo "π Test 4: Certificate details (subject and validity):" | ||
| CERT_SUBJECT=$(echo "$CERT_CONTENTS" | openssl x509 -noout -subject 2>/dev/null || echo "Could not extract subject") | ||
| CERT_DATES=$(echo "$CERT_CONTENTS" | openssl x509 -noout -dates 2>/dev/null || echo "Could not extract dates") | ||
| echo "$CERT_SUBJECT" | ||
| echo "$CERT_DATES" | ||
|
|
||
| # Check if this is the correct certificate (Apple Distribution) | ||
| if echo "$CERT_SUBJECT" | grep -q "Apple Distribution"; then | ||
| echo "β Certificate type confirmed: Apple Distribution" | ||
| else | ||
| echo "β οΈ WARNING: Certificate may not be 'Apple Distribution' type" | ||
| fi | ||
|
|
||
| # Test 5: List certificate and key components (double-check private key presence) | ||
| echo "" | ||
| echo "π Test 5: Certificate and key components found in p12:" | ||
| COMPONENTS=$(echo "$CERT_CONTENTS" | grep -E "BEGIN|END") | ||
| echo "$COMPONENTS" | ||
|
|
||
| # Final validation: Ensure private key is present in the structure | ||
| if echo "$COMPONENTS" | grep -q "BEGIN PRIVATE KEY"; then | ||
| echo "" | ||
| echo "β FINAL CHECK: Private key structure confirmed in p12" | ||
| HAS_PRIVATE_KEY=true | ||
| elif echo "$COMPONENTS" | grep -q "BEGIN RSA PRIVATE KEY"; then | ||
| echo "" | ||
| echo "β FINAL CHECK: RSA private key structure confirmed in p12" | ||
| HAS_PRIVATE_KEY=true | ||
| elif [ "${HAS_PRIVATE_KEY}" = "false" ]; then | ||
| echo "" | ||
| echo "β VALIDATION FAILED: p12 does not contain a valid private key" | ||
| echo "" | ||
| echo "β οΈ Possible issues:" | ||
| echo " 1. The p12 was exported without including the private key" | ||
| echo " 2. Wrong password is being used (IOS_P12_PASSWORD)" | ||
| echo " 3. The certificate file is corrupted" | ||
| echo "" | ||
| echo "π‘ To fix: Export the certificate from Keychain Access ensuring:" | ||
| echo " - Expand the certificate (click the triangle/arrow)" | ||
| echo " - Select both the certificate AND its private key (you should see 2 items)" | ||
| echo " - Right-click and choose 'Export 2 items...'" | ||
| echo " - Save as .p12 format" | ||
| exit 1 | ||
| fi | ||
|
|
||
| echo "" | ||
| echo "β All validation tests passed - p12 contains a valid private key" | ||
| echo "" | ||
| echo "π Note: After Fastlane imports this certificate into the keychain," | ||
| echo " additional checks will verify:" | ||
| echo " - security find-certificate (certificate in keychain)" | ||
| echo " - security find-key (private key in keychain)" | ||
| echo " - security find-identity (valid signing identity)" | ||
| env: | ||
| IOS_P12_PASSWORD: ${{ secrets.IOS_P12_PASSWORD }} | ||
|
|
||
| # 7οΈβ£ Decode provisioning profile (Fastlane will install it) | ||
| - name: Decode provisioning profile | ||
| run: | | ||
| # Check if the secret exists | ||
| if [ -z "$IOS_PROFILE_BASE64" ]; then | ||
| echo "β ERROR: IOS_PROFILE_BASE64 secret is missing or empty!" | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Decode provisioning profile | ||
| echo "$IOS_PROFILE_BASE64" | base64 --decode > profile.mobileprovision | ||
|
|
||
| FILE_SIZE=$(stat -f%z profile.mobileprovision) | ||
| echo "β Provisioning profile size: $FILE_SIZE bytes" | ||
| env: | ||
| IOS_PROFILE_BASE64: ${{ secrets.IOS_PROFILE_BASE64 }} | ||
|
|
||
| # 8οΈβ£ Setup App Store Connect API Key | ||
| - name: Setup App Store Connect API Key | ||
| run: | | ||
| # Check if secrets exist | ||
| if [ -z "$ASC_API_KEY_BASE64" ]; then | ||
| echo "β ERROR: ASC_API_KEY_BASE64 secret is missing or empty!" | ||
| exit 1 | ||
| fi | ||
|
|
||
| if [ -z "${{ secrets.ASC_KEY_ID }}" ] || [ -z "${{ secrets.ASC_ISSUER_ID }}" ]; then | ||
| echo "β ERROR: ASC_KEY_ID or ASC_ISSUER_ID secret is missing!" | ||
| exit 1 | ||
| fi | ||
|
|
||
| mkdir -p ~/.fastlane | ||
| echo "$ASC_API_KEY_BASE64" | base64 --decode > ~/.fastlane/AuthKey.p8 | ||
| chmod 600 ~/.fastlane/AuthKey.p8 | ||
|
|
||
| # Verify the key file was created | ||
| if [ ! -f ~/.fastlane/AuthKey.p8 ]; then | ||
| echo "β ERROR: Failed to create AuthKey.p8" | ||
| exit 1 | ||
| fi | ||
|
|
||
| echo "β App Store Connect API key configured" | ||
| env: | ||
| ASC_API_KEY_BASE64: ${{ secrets.ASC_API_KEY_BASE64 }} | ||
|
|
||
| # 8b Set build number (Config.xcconfig overrides agvtool; must be > previous TestFlight build) | ||
| - name: Set build number for TestFlight | ||
| run: | | ||
| BUILD_NUM=$(date +%s) | ||
| sed -i.bak "s/CURRENT_PROJECT_VERSION=.*/CURRENT_PROJECT_VERSION=$BUILD_NUM/" iosApp/Configuration/Config.xcconfig | ||
| rm -f iosApp/Configuration/Config.xcconfig.bak | ||
| echo "Set CURRENT_PROJECT_VERSION to $BUILD_NUM" | ||
|
|
||
| # 9οΈβ£ Build & Upload to TestFlight via Fastlane (includes verification inside) | ||
| - name: Build & Upload to TestFlight | ||
| run: bundle exec fastlane beta | ||
| env: | ||
| IOS_P12_PASSWORD: ${{ secrets.IOS_P12_PASSWORD }} | ||
| APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.ASC_KEY_ID }} | ||
| APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }} | ||
|
|
||
| # 9οΈβ£ Upload build artifacts | ||
| - name: Upload IPA artifact | ||
| uses: actions/upload-artifact@v4 | ||
| if: success() | ||
| with: | ||
| name: ARK-Drop-${{ github.run_number }}.ipa | ||
| path: build/ARK-Drop.ipa | ||
| retention-days: 30 | ||
|
|
||
| # π Show build errors if build failed | ||
| - name: Show Build Log Tail | ||
| if: failure() | ||
| run: | | ||
| echo "π Last 200 lines of build log:" | ||
| find build/logs -name "*.log" -exec tail -200 {} \; 2>/dev/null || echo "No build log found" | ||
|
|
||
| echo "" | ||
| echo "π Checking for error lines:" | ||
| find build/logs -name "*.log" -exec grep -i "error:" {} \; 2>/dev/null || echo "No errors found in log" | ||
|
|
||
| # π Upload build logs for debugging | ||
| - name: Upload Build Logs | ||
| uses: actions/upload-artifact@v4 | ||
| if: always() | ||
| with: | ||
| name: xcode-build-logs | ||
| path: | | ||
| ~/Library/Logs/gym/ | ||
| build/ | ||
| retention-days: 7 | ||
|
|
||
| # π Cleanup | ||
| - name: Cleanup | ||
| if: always() | ||
| run: | | ||
| # Clean up certificate and profile files | ||
| rm -f cert.p12 profile.mobileprovision ~/.fastlane/AuthKey.p8 | ||
| # Fastlane's setup_ci will clean up its own keychain automatically | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Remove before merge