🌅 Good Morning Guys ☕️
⏰ 25th March 2022 08:15 hrs IST
I know you have read lots of tutorials same like this. But for me, this is my latest achievement from the last 4 days to learn CI/CD which I have been procrastinating on for a long time. Here is the simplest way to automate uploading iOS build to AppCenter with Fastlane and Github Actions.
Let’s make a list we needed.
-
Apple Account Mandatory for code signing. If you are in a team/organization, you ask for a testing bundle and certificates.
-
Xcode 13.3/13.2.1, well that is independent but I’m using both so just to mention for clarifying any confusion.
-
Github, AppCenter, Apple accounts.
-
Cocoapods, Fastlane lib. No worries I have added steps where ever required.
P.S.: We are pushing build with a development profile to AppCenter and NOT for AppStore because of limited access 😅.
Let’s start with some lazy steps.
Account Setup
Github: https://github.com/signup
AppCenter: https://appcenter.ms/create-account
Apple Account: I feel that is already provided by your organization. But still here: https://support.apple.com/en-in/HT204316
Xcode: Download Xcode from here https://developer.apple.com/xcode/ Open Xcode, go to top menu Xcode > Preferences. A dialogue will open, on the bottom left tap on the ’+’ button, Select Apple Id. Add your credentials and after that when you see your account tap on download profiles.
AppCenter Setup
Here is the helping doc for the dashboard. Login to AppCenter and you will see a dashboard like below.
Top right you will see Add new app button, A side menu will appear to ask below details
- App Name: AppCenterDemo-iOS
- Release Type: Beta
- OS: iOS
- Platform: Objective-C / Swift.
Tap on Add new app button on the bottom right and it will redirect you to the app’s dashboard page. There you will get app secret and cocoapods installation link as well. Save the app secret for the next section.
Xcode Project Setup
Open Xcode, create a new project any name let’s say AppCenterDemo. You can learn from here as well just in case. Click on Project and you will general settings, tap on signing and capabilities, uncheck automatic sign in and
-
Choose your organization’s team in the dropdown.
-
Setup your bundle id like com.organization.appname.
-
Update your .gitignore file before pushing your code to GitHub Like below. We are removing pods, DeriveData, Fastlane some files which are not required in the repo.
xcuserdata/
*.xcscmblueprint
*.xccheckout
build/
DerivedData/
*.moved-aside
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
*.hmap
*.ipa
*.dSYM.zip
*.dSYM
timeline.xctimeline
playground.xcworkspace
.build/
Pods/
Carthage/Build/
Dependencies/
.accio/
fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots/**/*.png
fastlane/test_output
iOSInjectionProject/
- Download the provisioning profile and keep a soft copy of the same as well for later usage in Fastlane.
-
Open Keychain, and check the Apple Development certificate provided by your organization or your developer account, tap on to see the dropdown.
-
You will see a private key. right-click on it and select the export option
- Save the .p12 file for later use. Here I have created ios_dev_certificate.p12. Use the password when prompted for a password and save it for later use in this tutorial.
The hard part is done 😅
- Setup cocoapods from here if not done in past. Open podfile and add like below. Here we are integrating the AppCenter.
target 'AppCenterDemo' do
pod 'AppCenter'
end
Go to the terminal inside the root directory and run pod install in the terminal. You will observe a workspace is created like a project file. Open workspace project.
- In the AppDelegate file or in the main file for SwiftUI projects, add the code below. Declare a constant variable for appSecret. AppSecret is the same I mentioned at the end of the previous section.
AppCenter.start(withAppSecret: appSecret, services:[
Analytics.self,
Crashes.self
])
- Run/Build your project in order to check everything is working.
Fastlane Setup Part 1
For all further steps, I will recommend VS Code Editor. As we will get the project structure and terminal in a single window and we can access .extension files as well.
Install fastlane via running below command.
sudo gem install fastlane
Open terminal, navigate to project root directory and run
fastlane init
Helping Doc for iOS Setup.
You will see a Fastlane folder with Gemfile, AppFile, Fastfile and plugin files. Now add AppCenter Plugin for Fastlane via command fastlane add_plugin appcenter.
Now initial Fastlane setup add these in Gemfile and run bundle install. Here is the Gemfile setup at the end of the doc.
source "https://rubygems.org"
gem 'dotenv-rails', groups: [:development, :test]
gem "fastlane"
gem "xcode-install"
gem "cocoapods"
plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
eval_gemfile(plugins_path) if File.exist?(plugins_path)
These are libraries will be used by Fastlane as an initial setup. Dotenv-rails is used to load the environment while running Fastlane.
To specify the ruby version, add .ruby-version file and inside that add a single line string 2.6.8
. This will be used by Fastlane.
Now add .env
file like below
# General
WORKSPACE=AppCenterDemo.xcworkspace
PROJECT_PATH=AppCenterDemo.xcodeproj
BUILD_CONFIGURATION=Debug
SCHEME=AppCenterDemo
EXPORT_METHOD=development
VERSION_BUMP_TYPE=patch
APP_AUTHOR=Abhishek Thapliyal
# Appcenter
APP_CENTER_OWNER_NAME="thapliyal-fueled.com"
APP_CENTER_APP_NAME="AppCenterDemo-iOS"
APP_CENTER_DISTRIBUTION_GROUPS="Collaborators"
APP_CENTER_NOTIFY_TESTERS=true
APP_CENTER_API_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
APP_CENTER_API_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
#CodeSignIn
PROVSIONING_PROFILE_REPO_PATH="./fastlane/provision/Dev_Profile.mobileprovision"
KEYCHAIN_NAME="CodeSignInData"
These are environment variables used in shell script and Fastfile later in the tutorial.
Check the Parameters section for more details of the export method, scheme, workspace, Project Path and build configuration.
To get the APP_CENTER_APP_NAME and APP_CENTER_OWNER_NAME here is the link:
APP_CENTER_API_KEY: This is the same used previously in AppDelegate. Update here as well. APP_CENTER_API_TOKEN: https://appcenter.ms/settings/apitokens Use this link to get API Token.
Github Repo
You need to create a new repository in order to proceed further. Beginner, please follow these docs for the Github repository setup.
Now add a new folder name provision inside fastlane folder and move the earlier Dev_Profile.mobileprovision file inside. Now push the code to the repo.
Github Secrets
Now we have to setup Github Secrets in order to secure the .p12 file and credentials. Follow this doc for encrypted secrets and create as follow
Github Deploying Xcode Applications Doc
- Go to the directory where ios_dev_certificate.p12 is saved earlier. Open terminal in the same directory and run
base64 -i ios_dev_certificate.p12 | pbcopy
This will copy the base64 string in the pasteboard. You can check it via cmd+v. Save it in Github Secrets with the key name IOS_DEVELOPMENT.
-
The password we have saved while creating the above certificate will be saved in Github Secrets with the key name P12_PASSWORD.
-
Add one more value KEYCHAIN_PASSWORD for the keychain that will be used in Fastlane. I recommend make it strong.
Github Actions
Now in the root directory of the project.
-
Add nested folder .github/workflows.
-
Add yml file name gh_actions.yml inside the workflows folder. There is no specific name you can choose any name.
-
Update your above yml file like below.
name: iOS App Center Deployment
on: [push]
jobs:
build:
runs-on: macos-11
steps:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Run Fastlane for iOS
env:
IOS_DEVELOPMENT: ${{ secrets.IOS_DEVELOPMENT }}
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
run: bundle exec fastlane beta_app_upload
name: Workflow name.
on: on which event it will be triggered. Here I have added push i.e. on every push a build will be triggered.
jobs: Series of actions that will be executed.
build: Action Name.
runs-on: OS Name in which actions will be executed.
uses: actions/checkout@v2: Use to checkout branch
uses: ruby/setup-ruby@v1: Ruby setup with bundler-cache: true so that Gemfile libraries can be used.
name: Specifying name.
run: to run shell script command
env: Here we will mention environment variables that will be used in Fastlane and Github actions from Github Secrets.
Here is the reference doc for actions. More details for the workflow file are here.
Well, It’s afternoon 13:30 hrs IST. Have lunch and come back 😅
Fastlane Setup Part 2
Here is the most important section that will actually deploy our app.
Below are the documented fastlane actions. Please go through once before using.
Now open fastfile inside fastlane folder. Update the code like below. from this blog I have taken reference to certificates setup. Our agenda is divided in three setps.
-
Add action to generate KeyChain for code signIn.
-
Add action to generate iOS Build.
-
Add action to upload build to AppCenter.
default_platform(:ios)
platform :ios do
private_lane :setup_certificates do
create_keychain(
name: ENV["CodeSignInData"],
password: ENV["KEYCHAIN_PASSWORD"],
default_keychain: true,
unlock: true,
timeout: 3600,
lock_when_sleeps: false
)
install_provisioning_profile(path: ENV["PROVSIONING_PROFILE_REPO_PATH"])
setup_ios_profiles
import_certificate(
certificate_path: "fastlane/certificates/ios_dev_certificate.p12",
certificate_password: ENV["P12_PASSWORD"],
keychain_name: ENV["CodeSignInData"],
keychain_password: ENV["KEYCHAIN_PASSWORD"]
)
end
desc "AppCenter iOS App. Upload"
lane :beta_app_upload do
xcversion(version: "13.2.1")
setup_certificates
clear_derived_data
xcclean(scheme: ENV["SCHEME"])
cocoapods(repo_update: true)
build_ios_app(
workspace: ENV["WORKSPACE"],
configuration: ENV["BUILD_CONFIGURATION"],
scheme: ENV["SCHEME"],
silent: true,
clean: false,
disable_xcpretty: false,
export_options: {
method: ENV['EXPORT_METHOD']
}
)
appcenter_upload(
api_token: ENV["APP_CENTER_API_TOKEN"],
owner_name: ENV["APP_CENTER_OWNER_NAME"],
owner_type: "user",
app_name: ENV["APP_CENTER_APP_NAME"],
notify_testers: ENV["APP_CENTER_NOTIFY_TESTERS"]
)
end
end
-
create_keychain
: use to create keychain in github runner environment. Doc -
install_provisioning_profile
: use to install provision profiles for code sign in. Doc -
import_certificate
: use to import .p12 certificate from github secrets mentioned in env file inside github actions yml file previously. Doc -
setup_ios_profiles
: It’s the custom Fastlane action created by me. Doc Example -
Open terminal and run
bundle exec fastlane new_action
It will ask you name for action. I have added setup_ios_profiles. A setup_ios_profiles.rb will be generated inside fastlane folder. Add below code.
module Fastlane
module Actions
class SetupIosProfilesAction < Action
def self.run(params)
UI.message "Setup Keychain"
sh "./fastlane/actions/setup_code_signin.sh"
end
def self.is_supported?(platform)
platform == :ios
end
end
end
end
Now create new file setup_code_signin.sh
, open terminal in same directory and run
chmod u+x ./setup_code_signin.sh
This command will make file executable for user. After that update code below
DEV_CERTIFICATE_PATH=./fastlane/certificates/ios_dev_certificate.p12
mkdir -p ./fastlane/certificates
echo "$IOS_DEVELOPMENT" | base64 -d -o $DEV_CERTIFICATE_PATH
This script will convert saved base64 string from github secrets, mentioned in yml file, to .p12 file.
-
xcversion
: use to specify Xcode version. -
clear_derived_data
: use to clear derive data use to clear derive data -
xcclean
: use to clean project with specified scheme. -
cocoapods
: use to install cocoapods with repo update if specified.
Now code signIn and fastlane project in github action is almost setup. We have to configure rest two setps. As shown above fastfile code build_ios_app will generate build for iOS (Reference Doc). It will take values mentioned in .env file. Have a closer to export method, you can change to as per doc
export_method // Method used to export the archive. Valid values are: app-store, validation, ad-hoc, package, enterprise, development, developer-id and mac-application.
And the last part upload to AppCenter i.e. appcenter_upload
: This method will take App. Name, API Token and Owner Name from .env file. We have discussed earlier as well. As per doc
owner_type: "user" // # Default is user - set to organization for appcenter organizations
app_name: "<appcenter app name (as seen in app URL)>",
notify_testers: true // # Set to false if you don't want to notify testers of your new release (default: `false`)
Now push your code and see the magic. If all goes well then in a sample logs for successful app upload to AppCenter will looks like below.
You can cmd+click the link to navigate app center release page as well.
I hope you will get an idea CI/CD works. You can explore more yourself for TestFlight builds as well as managing several environments.
HAPPY CODING 😃😃
Good Night 😴 🛌