- GitHub
- GitHub Actions
- Flutter
- iOS
While developing your Flutter project hosted on GitHub you can easily set up a GitHub Actions to regularly build and distribute your application to your users.
To achieve your goal you have to follow these steps:
.xarchive
.ipa
from the .xarchive
To be able to complete this tutorial you need to:
.p12
) with the associated passwordWith that ready, let’s get started!
The idea is to automate this process using GitHub Actions, this process is called continuous integration.
The interest of using GitHub Actions is that:
We will create something called a GitHub Action that will allow you to generate your ipa
with just single click.
Let’s create our first workflow
!
Inside your project, you need to create a workflows
folder inside the .github
folder and then create a new file called: ios-release.yml
for instance. This file will contain our first job
called build_ios
:
name: Flutter_iOS
on:
push:
branches: [main]
jobs:
build_ios:
runs-on: macos-latest
steps:
- name: Checkout the code
uses: actions/checkout@v2
This job
will be triggered when you push new changes on the main
branch. The first step
that we will do is to check out the code of our branch.
You need to use something called secrets
. This allows you to store these files securely in order to access your .p12
certificate and your provisioning profile for your application. If you haven’t used secrets
before, checkout this previous article.
Let’s define one for the .p12
certificate called P12_BASE64
and one for the associated password called P12_PASSWORD
.
Next step is to install your Apple Certificate, to do so we will use an action from the community called apple-actions/import-codesign-certs@v1
and use our previously defined secrets
:
- name: Install Apple Certificate
uses: apple-actions/import-codesign-certs@v1
with:
p12-file-base64: ${{ secrets.P12_BASE64 }}
p12-password: ${{ secrets.P12_PASSWORD }}
To sign the application we also need to have our provisioning profile installed:
- name: Install the provisioning profile
env:
PROVISIONING_CERTIFICATE_BASE64: ${{ secrets.PROVISIONING_PROFILE_BASE64 }}
run: |
PP_PATH=$RUNNER_TEMP/build_pp.mobileprovision
echo -n "$PROVISIONING_CERTIFICATE_BASE64" | base64 --decode --output $PP_PATH
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles
As you can see above, this script has 3 operations:
secrets
To be able to use Flutter in our workflow
we need to install it. In order to reach this we will use another action from the community:
- name: Install and set Flutter version
uses: subosito/flutter-action@v1.4.0
with:
flutter-version: '2.0.1'
We need to add this action and specify the version of Flutter we want to use. It’s recommanded to fix this version instead of using stable
as value to avoid potential breaking changes when a new version is published.
Now we are able to restore the packages for our application:
- name: Restore packages
run: flutter pub get
Once they have been retrieved, we can build the application in release
mode without signing it:
- name: Build Flutter
run: flutter build ios --release --no-codesign
In fact we will apply our certificates previously installed in the next step!
First thing, open your iOS project using XCode and select the target
and inside Signing & Capabilities
make sure Automatically manage signing
is unchecked so we can sign it using the certificates we want without editing the XCode project.
Next, when you sign an iOS application you don’t sign the pods
associated to it so you need to specify it inside your Podfile
like this:
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
config.build_settings['CODE_SIGNING_REQUIRED'] = "NO"
config.build_settings['CODE_SIGNING_ALLOWED'] = "NO"
end
end
end
Before we can generate our xarchive
, we need to resolve the Swift
dependencies of our project. This is useful specially when you have some Flutter iOS plugins written in Swift
.
- name: Build resolve Swift dependencies
run: xcodebuild -resolvePackageDependencies -workspace ios/Runner.xcworkspace -scheme Runner -configuration Release
Now to create an xarchive
you need to find some information that can be found in your Provisioning Profile or in your Apple Certificate:
With all of that done, we can use it like this:
- name: Build xArchive
run: |
xcodebuild -workspace ios/Runner.xcworkspace -scheme Runner -configuration Release DEVELOPMENT_TEAM=YOUR_TEAM_ID -sdk 'iphoneos' -destination 'generic/platform=iOS' -archivePath build-output/app.xcarchive PROVISIONING_PROFILE=YOUR_UUID clean archive CODE_SIGN_IDENTITY="Apple Distribution: Damien Aicheh"
With the xarchive
generated we are able to export it as an ipa
. To achieve that we need to add a new file called ExportOptions.plist
to our project to specify the export options.
<?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> <!-- app-store, ad-hoc, enterprise, development -->
<key>teamID</key>
<string>YOUR_TEAM_ID</string>
<key>signingStyle</key>
<string>manual</string>
<key>provisioningProfiles</key>
<dict>
<key>YOUR_BUNDLE_ID</key>
<string>YOUR_UUID</string>
</dict>
</dict>
</plist>
Depending on your project configurations, you may have to add some more options to this file. You can have one ExportOptions.plist
file for each environment of your project if you need that.
Then just run this command line and your ipa
will be generated:
- name: Export ipa
run: xcodebuild -exportArchive -archivePath build-output/app.xcarchive -exportPath build-output/ios -exportOptionsPlist ios/ExportOptions.plist
To get access to the ipa
generated previously from the GitHub interface let’s add this final action:
- name: Publish iOS Artefacts
uses: actions/upload-artifact@v1
with:
name: release-ios
path: build-output/ios
This will publish the ios
folder that contain our package. Then you can install it on your device.
Now you are ready to share your application with your users depending on the context of your project! You will find an example code in this Github repository.