mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-26 06:08:40 +01:00
Two fixes that together address the 'There is no XCFramework found at...'
build failure:
1) ios/Runner.xcodeproj/project.pbxproj: remove 10 lines referencing
ZanoWallet.xcframework + WarpApiFFI.xcframework (zcash). Those were
stale — both chains were removed in commit 4eb7db0b7 weeks ago, but
the Xcode project still listed them in BuildFile, CopyFiles, FileReference,
and Group sections. xcode error referenced them as missing.
2) Both iOS workflows now run scripts/ios/gen_framework.sh after staging
the monero_c bundle. The script reads
aarch64-apple-ios/lib<wallet>_wallet2_api_c.dylib and
aarch64-apple-ios-simulator/lib<wallet>_wallet2_api_c.dylib from the
bundle, wraps each as a .framework with an Info.plist, then bundles
device + simulator into ios/MoneroWallet.xcframework +
ios/WowneroWallet.xcframework via xcodebuild -create-xcframework.
These are exactly the paths project.pbxproj's CopyFiles phase
references.
The 'Inspect iOS targets' debug step was expanded to print bundle
subdirs + sample target contents, so if the monero_c bundle doesn't
actually ship those exact dirs we'll see it in the log.
349 lines
13 KiB
YAML
349 lines
13 KiB
YAML
name: Hash Bags iOS TestFlight build
|
|
|
|
# Phase 2 of iOS CI: full signed build that uploads to TestFlight.
|
|
# Phase 1 (build-ios-sim.yml) validates the Mac runner with no signing —
|
|
# run that first if TestFlight blows up unexpectedly.
|
|
#
|
|
# Required Gitea Actions secrets (all account/app credentials):
|
|
# APPLE_TEAM_ID — 10-char (D8PL9F7X33)
|
|
# APPLE_KEY_ID — 10-char (CHK6B69G58)
|
|
# APPLE_ISSUER_ID — UUID
|
|
# APPLE_API_KEY_P8_BASE64 — base64 of AuthKey_<KeyID>.p8
|
|
# APPLE_DIST_CERT_P12_BASE64 — base64 of distribution.p12
|
|
# APPLE_DIST_CERT_P12_PASSWORD — password set during openssl pkcs12 export
|
|
# APPLE_PROVISIONING_PROFILE_BASE64 — base64 of Hash_Wallet.mobileprovision
|
|
# APPLE_KEYCHAIN_PASSWORD — any string, used to create the temp keychain
|
|
# TROCADOR_* — reused from Linux/Android
|
|
|
|
on:
|
|
# Don't auto-trigger on every push — TestFlight uploads are slow and use
|
|
# build numbers. Manual trigger only; later we can add a workflow_dispatch
|
|
# input for build number or auto-bump.
|
|
workflow_dispatch:
|
|
|
|
concurrency:
|
|
group: ios-testflight-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
defaults:
|
|
run:
|
|
shell: bash
|
|
|
|
jobs:
|
|
build:
|
|
runs-on: macos-latest
|
|
env:
|
|
APP_IOS_TYPE: cakewallet
|
|
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
|
|
# CocoaPods needs UTF-8; Gitea runner shell defaults to ASCII-8BIT.
|
|
LANG: en_US.UTF-8
|
|
LC_ALL: en_US.UTF-8
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 1
|
|
|
|
- name: Check Flutter 3.32.0
|
|
id: flutter_check
|
|
run: |
|
|
if command -v flutter >/dev/null && flutter --version 2>/dev/null | grep -q "3\.32\.0"; then
|
|
echo "installed=true" >> "$GITHUB_OUTPUT"
|
|
flutter --version
|
|
else
|
|
echo "installed=false" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
- name: Install Flutter 3.32.0 (if missing)
|
|
if: steps.flutter_check.outputs.installed != 'true'
|
|
uses: subosito/flutter-action@v2
|
|
with:
|
|
flutter-version: '3.32.0'
|
|
channel: stable
|
|
cache: true
|
|
|
|
- name: Install CocoaPods (if missing)
|
|
run: |
|
|
if command -v pod >/dev/null; then
|
|
pod --version
|
|
exit 0
|
|
fi
|
|
if command -v brew >/dev/null; then
|
|
brew install cocoapods
|
|
else
|
|
export GEM_HOME="$HOME/.gem"
|
|
export PATH="$GEM_HOME/bin:$PATH"
|
|
echo "GEM_HOME=$HOME/.gem" >> "$GITHUB_ENV"
|
|
echo "$HOME/.gem/bin" >> "$GITHUB_PATH"
|
|
gem install --user-install cocoapods --no-document
|
|
fi
|
|
pod --version
|
|
|
|
- name: Install Go + gomobile (if missing)
|
|
run: |
|
|
if ! command -v go >/dev/null; then
|
|
if command -v brew >/dev/null; then
|
|
brew install go
|
|
else
|
|
echo "Go missing and brew not available"; exit 1
|
|
fi
|
|
fi
|
|
go version
|
|
GOPATH=$(go env GOPATH)
|
|
echo "$GOPATH/bin" >> "$GITHUB_PATH"
|
|
export PATH="$PATH:$GOPATH/bin"
|
|
if ! command -v gomobile >/dev/null; then
|
|
go install golang.org/x/mobile/cmd/gomobile@latest
|
|
go install golang.org/x/mobile/cmd/gobind@latest
|
|
fi
|
|
which gomobile && gomobile version || true
|
|
|
|
- name: Show toolchain
|
|
run: |
|
|
set -x
|
|
flutter --version
|
|
xcodebuild -version
|
|
pod --version
|
|
uname -m
|
|
|
|
# ---- External prebuilt deps -----------------------------------------
|
|
# macOS doesn't ship wget; using curl everywhere.
|
|
- name: Fetch prebuilt torch_dart
|
|
run: |
|
|
set -x -e
|
|
pushd scripts
|
|
rm -rf torch_dart torch_dart.tar.gz
|
|
curl -fsSL -o torch_dart.tar.gz https://github.com/MrCyjaneK/torch_dart/releases/download/v1.0.17/torch_dart-v1.0.17.tar.gz
|
|
mkdir torch_dart
|
|
tar -xzf torch_dart.tar.gz -C torch_dart
|
|
rm torch_dart.tar.gz
|
|
popd
|
|
|
|
- name: Fetch prebuilt reown_flutter
|
|
run: |
|
|
set -x -e
|
|
pushd scripts
|
|
rm -rf reown_flutter reown_flutter.tar.gz
|
|
curl -fsSL -o reown_flutter.tar.gz https://github.com/cake-tech/reown_flutter/releases/download/v0.0.4/reown_flutter-v0.0.4.tar.gz
|
|
mkdir reown_flutter
|
|
tar -xzf reown_flutter.tar.gz -C reown_flutter
|
|
rm reown_flutter.tar.gz
|
|
popd
|
|
|
|
- name: Clone BitBox Flutter (iOS — skip Android bindings)
|
|
run: |
|
|
# See note in build-ios-sim.yml — iOS uses bitbox's native plugin,
|
|
# not the .aar that build_bindings.sh generates.
|
|
set -x -e
|
|
pushd scripts
|
|
if [[ ! -d bitbox_flutter ]]; then
|
|
git clone https://github.com/konstantinullrich/bitbox_flutter
|
|
fi
|
|
cd bitbox_flutter
|
|
git fetch -a
|
|
git reset --hard
|
|
git checkout 5a6e6dd388ef64003f86094af80d5453518b601d
|
|
git reset --hard
|
|
popd
|
|
|
|
- name: Fetch prebuilt monero_c bundle
|
|
run: |
|
|
set -x -e
|
|
./scripts/prepare_moneroc.sh
|
|
MONERO_C_TAG=$(cd scripts/monero_c && git describe --tags)
|
|
mkdir -p "scripts/monero_c/release/$MONERO_C_TAG"
|
|
pushd "scripts/monero_c/release/$MONERO_C_TAG"
|
|
curl -fsSL -O https://github.com/MrCyjaneK/monero_c/releases/download/v0.18.4.6-RC1/release-bundle.zip
|
|
unzip -q release-bundle.zip
|
|
rm release-bundle.zip
|
|
popd
|
|
|
|
- name: Build MoneroWallet + WowneroWallet XCFrameworks
|
|
run: |
|
|
set -x -e
|
|
pushd scripts/ios
|
|
bash ./gen_framework.sh
|
|
popd
|
|
ls -la ios/MoneroWallet.xcframework ios/WowneroWallet.xcframework
|
|
|
|
# ---- Configure: pubspec.yaml, Info.plist, etc. ----------------------
|
|
- name: Run iOS configure (cakewallet profile)
|
|
run: |
|
|
set -x -e
|
|
pushd scripts/ios
|
|
source ./app_env.sh cakewallet
|
|
./app_config.sh
|
|
popd
|
|
|
|
# ---- Secrets ---------------------------------------------------------
|
|
- name: Generate per-module secrets.g.dart files (empty defaults)
|
|
run: dart run tool/generate_new_secrets.dart
|
|
|
|
- name: Inject Trocador affiliate secrets
|
|
env:
|
|
TROCADOR_API_KEY: ${{ secrets.TROCADOR_API_KEY }}
|
|
TROCADOR_MONERO_API_KEY: ${{ secrets.TROCADOR_MONERO_API_KEY }}
|
|
TROCADOR_EXCHANGE_MARKUP: ${{ secrets.TROCADOR_EXCHANGE_MARKUP }}
|
|
run: |
|
|
sed -i '' \
|
|
-e "s|const trocadorApiKey = '';|const trocadorApiKey = '${TROCADOR_API_KEY}';|" \
|
|
-e "s|const trocadorMoneroApiKey = '';|const trocadorMoneroApiKey = '${TROCADOR_MONERO_API_KEY}';|" \
|
|
-e "s|const trocadorExchangeMarkup = '';|const trocadorExchangeMarkup = '${TROCADOR_EXCHANGE_MARKUP:-1}';|" \
|
|
lib/.secrets.g.dart
|
|
|
|
# ---- Apple signing setup --------------------------------------------
|
|
- name: Create temp keychain + import distribution cert
|
|
env:
|
|
APPLE_DIST_CERT_P12_BASE64: ${{ secrets.APPLE_DIST_CERT_P12_BASE64 }}
|
|
APPLE_DIST_CERT_P12_PASSWORD: ${{ secrets.APPLE_DIST_CERT_P12_PASSWORD }}
|
|
APPLE_KEYCHAIN_PASSWORD: ${{ secrets.APPLE_KEYCHAIN_PASSWORD }}
|
|
run: |
|
|
set -e
|
|
KEYCHAIN_PATH="$RUNNER_TEMP/build.keychain-db"
|
|
# Create + unlock dedicated keychain so we don't touch the user's login keychain
|
|
security create-keychain -p "$APPLE_KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
|
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" # 6 hours
|
|
security unlock-keychain -p "$APPLE_KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
|
# Add to user search list so codesign can find it
|
|
security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | sed 's/"//g')
|
|
# Import the .p12
|
|
P12="$RUNNER_TEMP/dist.p12"
|
|
echo "$APPLE_DIST_CERT_P12_BASE64" | base64 -d > "$P12"
|
|
security import "$P12" -k "$KEYCHAIN_PATH" -P "$APPLE_DIST_CERT_P12_PASSWORD" \
|
|
-T /usr/bin/codesign -T /usr/bin/security
|
|
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$APPLE_KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
|
# Sanity-check: list identities the keychain offers
|
|
security find-identity -v -p codesigning "$KEYCHAIN_PATH"
|
|
rm -f "$P12"
|
|
|
|
- name: Install provisioning profile + parse name/UUID for ExportOptions
|
|
env:
|
|
APPLE_PROVISIONING_PROFILE_BASE64: ${{ secrets.APPLE_PROVISIONING_PROFILE_BASE64 }}
|
|
run: |
|
|
set -e
|
|
PROFILES_DIR="$HOME/Library/MobileDevice/Provisioning Profiles"
|
|
mkdir -p "$PROFILES_DIR"
|
|
PROFILE="$RUNNER_TEMP/Hash_Wallet.mobileprovision"
|
|
echo "$APPLE_PROVISIONING_PROFILE_BASE64" | base64 -d > "$PROFILE"
|
|
|
|
# Parse the .mobileprovision to get its UUID + Name (CMS-decoded plist).
|
|
PROFILE_UUID=$(security cms -D -i "$PROFILE" | plutil -extract UUID raw -o - -)
|
|
PROFILE_NAME=$(security cms -D -i "$PROFILE" | plutil -extract Name raw -o - -)
|
|
echo "Profile UUID: $PROFILE_UUID"
|
|
echo "Profile name: $PROFILE_NAME"
|
|
echo "PROFILE_UUID=$PROFILE_UUID" >> "$GITHUB_ENV"
|
|
echo "PROFILE_NAME=$PROFILE_NAME" >> "$GITHUB_ENV"
|
|
|
|
# Xcode looks profiles up by UUID filename.
|
|
cp "$PROFILE" "$PROFILES_DIR/$PROFILE_UUID.mobileprovision"
|
|
ls -la "$PROFILES_DIR" | head -10
|
|
|
|
- name: Install App Store Connect API key for altool
|
|
env:
|
|
APPLE_API_KEY_P8_BASE64: ${{ secrets.APPLE_API_KEY_P8_BASE64 }}
|
|
APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
|
|
run: |
|
|
set -e
|
|
mkdir -p "$HOME/.appstoreconnect/private_keys"
|
|
echo "$APPLE_API_KEY_P8_BASE64" | base64 -d > "$HOME/.appstoreconnect/private_keys/AuthKey_${APPLE_KEY_ID}.p8"
|
|
ls -la "$HOME/.appstoreconnect/private_keys/"
|
|
|
|
# ---- Flutter init + codegen + pod install ---------------------------
|
|
- name: Initialize Flutter SDK (iOS precache)
|
|
run: |
|
|
flutter --version
|
|
flutter precache --ios --no-linux --no-android --no-macos --no-windows --no-fuchsia --no-web || true
|
|
|
|
- name: Build generated code
|
|
run: bash model_generator.sh
|
|
|
|
- name: Generate localization
|
|
run: dart run tool/generate_localization.dart
|
|
|
|
- name: Compile SVG assets (res/pictures/*.svg → assets/new-ui/*.svg.vec)
|
|
run: ./compile_graphics.sh
|
|
|
|
- name: pod install
|
|
run: |
|
|
cd ios
|
|
pod install --repo-update
|
|
|
|
# ---- Generate ExportOptions.plist + build IPA -----------------------
|
|
- name: Write ExportOptions.plist
|
|
env:
|
|
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
run: |
|
|
cat > ios/ExportOptions.plist <<EOF
|
|
<?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>${APPLE_TEAM_ID}</string>
|
|
<key>signingStyle</key>
|
|
<string>manual</string>
|
|
<key>signingCertificate</key>
|
|
<string>Apple Distribution</string>
|
|
<key>provisioningProfiles</key>
|
|
<dict>
|
|
<key>com.suchsoftware.hashwallet</key>
|
|
<string>${PROFILE_NAME}</string>
|
|
</dict>
|
|
<key>uploadBitcode</key>
|
|
<false/>
|
|
<key>uploadSymbols</key>
|
|
<true/>
|
|
<key>destination</key>
|
|
<string>export</string>
|
|
<key>stripSwiftSymbols</key>
|
|
<true/>
|
|
</dict>
|
|
</plist>
|
|
EOF
|
|
cat ios/ExportOptions.plist
|
|
|
|
- name: Build IPA
|
|
run: |
|
|
set -x -e
|
|
flutter build ipa --release \
|
|
--dart-define-from-file=env.json \
|
|
--export-options-plist=ios/ExportOptions.plist
|
|
ls -la build/ios/ipa/
|
|
|
|
- name: Upload IPA artifact
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: hash-wallet-ios-${{ github.sha }}
|
|
path: build/ios/ipa/*.ipa
|
|
retention-days: 30
|
|
|
|
# ---- Upload to TestFlight -------------------------------------------
|
|
- name: Upload to TestFlight via altool
|
|
env:
|
|
APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
|
|
APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }}
|
|
run: |
|
|
set -e
|
|
IPA=$(ls build/ios/ipa/*.ipa | head -1)
|
|
echo "Uploading $IPA to TestFlight..."
|
|
xcrun altool --upload-app \
|
|
--type ios \
|
|
--file "$IPA" \
|
|
--apiKey "$APPLE_KEY_ID" \
|
|
--apiIssuer "$APPLE_ISSUER_ID"
|
|
|
|
# ---- Cleanup keychain so we don't leak it across builds -------------
|
|
- name: Cleanup
|
|
if: always()
|
|
env:
|
|
APPLE_KEYCHAIN_PASSWORD: ${{ secrets.APPLE_KEYCHAIN_PASSWORD }}
|
|
run: |
|
|
set +e
|
|
KEYCHAIN_PATH="$RUNNER_TEMP/build.keychain-db"
|
|
security delete-keychain "$KEYCHAIN_PATH" 2>/dev/null
|
|
rm -rf "$HOME/.appstoreconnect/private_keys"
|
|
rm -f "$HOME/Library/MobileDevice/Provisioning Profiles"/*.mobileprovision
|
|
true
|