Skip to content

Build iOS

Build iOS #304

Workflow file for this run

name: Build iOS
on:
workflow_dispatch:
inputs:
use-published-plugins:
description: 'Boolean indicating whether to use a published plugin for the Breez SDK - Native (Greenlight Implementation). Default = false.'
required: false
type: boolean
default: false
greenlight-sdk-plugin-version:
description: 'Version for the published Breez SDK - Native (Greenlight Implementation) plugin "v(MAJOR.MINOR.BUILD)". Defaults to latest published version on "breez/breez-sdk-flutter"'
required: false
type: string
default: ''
greenlight-sdk-ref:
description: 'Breez SDK - Native (Greenlight Implementation) commit/tag/branch reference when not using a published plugin. Default = "main"'
required: false
type: string
default: 'main'
jobs:
pre-setup:
name: Pre-setup
runs-on: ubuntu-latest
outputs:
# These outputs mimic the inputs for the workflow.
# Their only purpose is to be able to test this workflow if you make
# changes that you won't want to commit to main yet.
# You can set these values manually, to test how the CI behaves with
# certain inputs.
use-published-plugins: ${{ inputs.use-published-plugins }}
greenlight-sdk-plugin-version: ${{ inputs.greenlight-sdk-plugin-version }}
greenlight-sdk-ref: ${{ inputs.greenlight-sdk-ref }}
steps:
- name: Checkout repository
if: ${{ inputs.use-published-plugins == true && inputs.greenlight-sdk-plugin-version == ''}}
uses: actions/checkout@v4
with:
repository: 'breez/breez-sdk-flutter'
- name: Get the latest tag and set 'greenlight-sdk-plugin-version'
if: ${{ inputs.use-published-plugins == true && inputs.greenlight-sdk-plugin-version == ''}}
run: |
latest_tag=$(git describe --tags `git rev-list --tags --max-count=1`)
echo "greenlight-sdk-plugin-version=$latest_tag" >> "$GITHUB_OUTPUT"
- run: echo "set pre-setup output variables"
- name: Disk Cleanup
run: |
echo "::group::Free space before cleanup"
df -h --total
echo "::endgroup::"
echo "::group::Cleaned Files"
sudo rm -rf /usr/local/.ghcup
sudo rm -rf /opt/hostedtoolcache/CodeQL
sudo rm -rf /usr/local/lib/android/sdk/ndk
sudo rm -rf /usr/share/dotnet
sudo rm -rf /opt/ghc
sudo rm -rf /usr/local/share/boost
sudo apt-get clean
echo "::endgroup::"
echo "::group::Free space after cleanup"
df -h --total
echo "::endgroup::"
setup:
name: Setup
needs: pre-setup
runs-on: ubuntu-latest
outputs:
# Careful, a boolean input is not a boolean output. A boolean input is
# actually a boolean, but these outputs are strings. All the boolean
# checks in this file have the format `boolean == 'true'`. So feel free
# to set these variables here to `true` or `false`
# (e.g. bindings-windows: true) if you want to test something.
use-published-plugins: ${{ needs.pre-setup.outputs.use-published-plugins }}
greenlight-sdk-plugin-version: ${{ needs.pre-setup.outputs.greenlight-sdk-plugin-version }}
greenlight-sdk-ref: ${{ needs.pre-setup.outputs.greenlight-sdk-ref }}
steps:
- run: echo "set setup output variables"
build-ios:
name: Build iOS
needs: setup
runs-on: macOS-15
env:
SCHEME: Runner
BUILD_CONFIGURATION: Release
TESTFLIGHT_USERNAME: ${{secrets.TESTFLIGHT_USERNAME}}
TESTFLIGHT_PASSWORD: ${{secrets.TESTFLIGHT_PASSWORD}}
IOS_VERSION_STRING: 1.2.0
DISTRIBUTION_CERT: ${{secrets.DISTRIBUTION_CERT}}
P12_BASE64: ${{secrets.P12_BASE64}}
P12_PASSWORD: ${{secrets.P12_PASSWORD}}
GOOGLE_SERVICES_IOS: ${{secrets.GOOGLE_SERVICES_IOS}}
steps:
- name: Disk Cleanup
run: |
echo "::group::Free space before cleanup"
df -hI
echo "::endgroup::"
echo "::group::Cleaned Files"
sudo rm -rf /Users/runner/Library/Android/sdk
sudo rm -rf /Applications/Xcode_15.4.app
sudo rm -rf /Applications/Xcode_16.1.app
sudo rm -rf /Applications/Xcode_16.2.app
sudo rm -rf /Applications/Xcode_16.3_Release_Candidate_2.app
echo "::endgroup::"
echo "::group::Free space after cleanup"
df -hI
echo "::endgroup::"
- name: πŸ—οΈ Check-out c-breez repository
uses: actions/checkout@v4
with:
path: 'cbreez'
- name: Set Breez SDK - Native (Greenlight Implementation) plugin version
if: ${{ needs.setup.outputs.use-published-plugins == 'true' }}
working-directory: cbreez
run: |
mv pubspec_overrides.yaml.workflow pubspec_overrides.yaml
sed -i.bak -e 's/ref:.*/ref: ${{ needs.setup.outputs.greenlight-sdk-plugin-version }}/' pubspec_overrides.yaml
rm pubspec_overrides.yaml.bak
- name: Install rust
if: ${{ needs.setup.outputs.use-published-plugins == 'false' }}
run: |
rustup set auto-self-update disable
rustup toolchain install stable --profile minimal
- name: πŸ—οΈ Setup Java
uses: actions/setup-java@v4
with:
distribution: 'zulu'
java-version: '17'
- name: πŸ—οΈ Setup Flutter
uses: subosito/flutter-action@v2
with:
channel: 'stable'
flutter-version: 3.32.1
cache: true
- name: πŸ” Install Keychain keys
run: |
KEYCHAIN_PATH=$RUNNER_TEMP/ios-build.keychain
security create-keychain -p ci $KEYCHAIN_PATH
security default-keychain -s $KEYCHAIN_PATH
security unlock-keychain -p ci $KEYCHAIN_PATH
security set-keychain-settings -t 6400 -l $KEYCHAIN_PATH
CERT_PATH=$RUNNER_TEMP/apple_distribution.cer
echo -n "$DISTRIBUTION_CERT" | base64 --decode -o $CERT_PATH
security import $CERT_PATH -k $KEYCHAIN_PATH -A
P12_KEY_PATH=$RUNNER_TEMP/key.p12
echo -n "$P12_BASE64" | base64 --decode -o $P12_KEY_PATH
security import $P12_KEY_PATH -k $KEYCHAIN_PATH -P "$P12_PASSWORD" -A
security set-key-partition-list -S apple-tool:,apple: -s -k ci $KEYCHAIN_PATH > /dev/null
- name: πŸ—οΈ Copy Firebase configuration file
working-directory: cbreez
run: echo "$GOOGLE_SERVICES_IOS" > ios/Runner/GoogleService-Info.plist
- name: πŸ—οΈ Setup breez-sdk-greenlight repository
if: ${{ needs.setup.outputs.use-published-plugins == 'false' }}
uses: actions/checkout@v4
with:
repository: 'breez/breez-sdk-greenlight'
ssh-key: ${{secrets.REPO_SSH_KEY}}
path: 'breez-sdk-greenlight'
ref: ${{ needs.setup.outputs.greenlight-sdk-ref }}
- name: πŸ—οΈ Rust cache
if: ${{ needs.setup.outputs.use-published-plugins == 'false' }}
uses: Swatinem/rust-cache@v2
with:
workspaces: breez-sdk-greenlight/libs
cache-all-crates: true
- name: Set iOS deployment target
if: ${{ needs.setup.outputs.use-published-plugins == 'false' }}
run: |
echo 'Setting iOS deployment target environment variables'
echo 'IPHONEOS_DEPLOYMENT_TARGET=12.0' >> $GITHUB_ENV
- name: πŸ“¦ Install Breez SDK - Native (Greenlight Implementation) dependencies
if: ${{ needs.setup.outputs.use-published-plugins == 'false' }}
working-directory: breez-sdk-greenlight/libs/
run: |
brew install protobuf
cd sdk-flutter
make init
cd ../sdk-bindings
make init
- name: πŸ”’ Install SSH Key
if: ${{ needs.setup.outputs.use-published-plugins == 'false' }}
env:
SSH_PRIVATE_KEY: ${{secrets.REPO_SSH_KEY}}
run: |
mkdir -p ~/.ssh
echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
sudo chmod 600 ~/.ssh/id_rsa
ssh-add ~/.ssh/id_rsa
- name: πŸ”¨ Build Breez SDK - Native (Greenlight Implementation)
if: ${{ needs.setup.outputs.use-published-plugins == 'false' }}
working-directory: breez-sdk-greenlight/libs/sdk-flutter
run: |
rm -rf ../target
cargo check
make ios
- name: πŸ—‚οΈ Populate Flutter tool's cache of binary artifacts.
working-directory: cbreez
run: flutter precache
- name: πŸ“¦ Install Flutter dependencies
working-directory: cbreez
run: flutter pub get
- name: πŸ” Perform static analysis
working-directory: cbreez
run: dart analyze --fatal-infos
- name: βš™οΈ Setup compile-time variables
env:
CONFIG_FILE: ${{secrets.CONFIG_FILE}}
run: echo "$CONFIG_FILE" > ./cbreez/config.json
- name: πŸ“ Install the Provisioning Profile
env:
PROVISIONING_PROFILE_BASE64: ${{ secrets.PROVISIONING_PROFILE_BASE64 }}
NOTIFICATION_PROVISIONING_PROFILE_BASE64: ${{ secrets.NOTIFICATION_PROVISIONING_PROFILE_BASE64 }}
run: |
set -euo pipefail
# Define paths
PP_PATH=$RUNNER_TEMP/build_pp.mobileprovision
NOTIFICATIONS_PP_PATH=$RUNNER_TEMP/build_notifications_pp.mobileprovision
PROFILES_DIR=~/Library/MobileDevice/Provisioning\ Profiles
# Decode and save provisioning profiles
echo "Decoding main provisioning profile..."
echo -n "$PROVISIONING_PROFILE_BASE64" | base64 --decode > $PP_PATH
echo "Decoding notification provisioning profile..."
echo -n "$NOTIFICATION_PROVISIONING_PROFILE_BASE64" | base64 --decode > $NOTIFICATIONS_PP_PATH
# Verify provisioning profile validity
echo "Verifying provisioning profile validity..."
for profile in "$PP_PATH" "$NOTIFICATIONS_PP_PATH"; do
if ! security cms -D -i "$profile" > /dev/null 2>&1; then
echo "Error: Invalid provisioning profile: $(basename $profile)" >&2
exit 1
fi
# Check expiration date
expiration=$(security cms -D -i "$profile" | plutil -extract ExpirationDate raw -)
expiration_epoch=$(date -j -f "%Y-%m-%dT%H:%M:%SZ" "$expiration" "+%s" 2>/dev/null)
current_epoch=$(date "+%s")
if [ -z "$expiration_epoch" ] || [ "$expiration_epoch" -lt "$current_epoch" ]; then
echo "Error: Expired or invalid date in provisioning profile: $(basename $profile)" >&2
echo "Expiration date: $expiration" >&2
exit 1
fi
echo "Provisioning profile $(basename $profile) is valid and not expired."
done
# Apply provisioning profiles
echo "Creating profiles directory..."
mkdir -p "$PROFILES_DIR"
echo "Copying provisioning profiles..."
cp "$PP_PATH" "$PROFILES_DIR"
cp "$NOTIFICATIONS_PP_PATH" "$PROFILES_DIR"
# Verify copying was successful
echo "Verifying provisioning profiles are installed..."
if [ ! -f "$PROFILES_DIR/$(basename $PP_PATH)" ]; then
echo "Error: Main provisioning profile copy failed!" >&2
exit 1
fi
if [ ! -f "$PROFILES_DIR/$(basename $NOTIFICATIONS_PP_PATH)" ]; then
echo "Error: Notification provisioning profile copy failed!" >&2
exit 1
fi
echo "Listing installed provisioning profiles:"
ls -l "$PROFILES_DIR"
echo "Provisioning profile details:"
for profile in "$PROFILES_DIR"/*; do
echo "Profile: $(basename "$profile")"
security cms -D -i "$profile" | grep -A1 -E "Name|UUID|TeamIdentifier" | sed 's/^[[:space:]]*//' | sed 'N;s/\n/ /'
echo "Entitlements:"
security cms -D -i "$profile" | sed -n '/Entitlements/,/<\/dict>/p' | grep -v "Entitlements" | sed 's/^[[:space:]]*//' | sed 'N;s/\n/ /'
done
# Cleanup temporary files
echo "Cleaning up temporary files..."
rm -f "$PP_PATH" "$NOTIFICATIONS_PP_PATH"
echo "Provisioning profiles installed successfully."
- name: πŸš€ Build app
working-directory: cbreez
run: |
flutter build ios \
--release \
--split-debug-info=./obsfucated/debug \
--obfuscate \
--no-config-only \
--no-pub \
--no-codesign \
--dart-define-from-file=config.json
- name: πŸ“¦ Resolve Swift package dependencies
working-directory: cbreez
run: |
xcodebuild \
-resolvePackageDependencies \
-workspace ios/Runner.xcworkspace \
-scheme ${{ env.SCHEME }} \
-configuration ${{ env.BUILD_CONFIGURATION }}
- name: πŸ”¨ Build application and generate xcarchive file
working-directory: cbreez
run: |
buildNumber=$(($GITHUB_RUN_NUMBER + 6000)).1
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" ios/Runner/Info.plist
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString ${{ env.IOS_VERSION_STRING }}" ios/Runner/Info.plist
xcodebuild \
-workspace ios/Runner.xcworkspace \
-scheme ${{ env.SCHEME }} \
-configuration ${{ env.BUILD_CONFIGURATION }} \
-sdk 'iphoneos' \
-destination 'generic/platform=iOS' \
-archivePath build-output/app.xcarchive \
clean \
archive
- name: πŸ“€ Export the archive to an ipa file
working-directory: cbreez
run: |
xcodebuild \
-exportArchive -archivePath build-output/app.xcarchive \
-exportPath build-output/ios \
-exportOptionsPlist ios/ExportOptions.plist
- name: πŸ—ƒοΈ Compress build folder
if: github.event_name == 'release'
uses: TheDoctor0/zip-release@master
with:
filename: build.zip
directory: cbreez/build/ios/iphoneos
type: zip
- name: πŸ“€ Upload release
if: github.event_name == 'release'
uses: svenstaro/upload-release-action@v2
with:
asset_name: release-iOS-${{ github.run_number }}.zip
file: cbreez/build/ios/iphoneos/build.zip
overwrite: true
repo_token: ${{ secrets.GITHUB_TOKEN }}
- name: πŸ“€ Upload artifact
if: github.event_name != 'release'
uses: actions/upload-artifact@v4
with:
name: release-iOS-${{ github.run_number }}
path: cbreez/build/ios/iphoneos
- name: πŸ“± Publish to TestFlight
run: |
altool="$(dirname "$(xcode-select -p)")/Developer/usr/bin/altool"
ipa="$PWD/cbreez/build-output/ios/c_breez.ipa"
"$altool" --upload-app --type ios --file "$ipa" --username $TESTFLIGHT_USERNAME --password $TESTFLIGHT_PASSWORD