CI/CD Explained: Boost iOS App Development Stability and Efficiency|Tool Selection Guide
iOS app teams struggle with unstable builds and slow releases; discover how implementing CI/CD improves development speed and reliability, and learn which tools optimize your workflow for consistent delivery.
点击这里查看本文章简体中文版本。
點擊這裡查看本文章正體中文版本。
This post was translated with AI assistance — let me know if anything sounds off!
Practical Guide to CI/CD (Part 1): What is CI/CD? How to Build a Stable and Efficient Development Team with CI/CD? Tool Selection?
Using the App (iOS) Team as an example, this will guide you from zero to understanding CI/CD and the tangible value it brings after implementation.
Photo by Leif Christoph Gottwald
Preface
After experiencing building App CI/CD with two different development teams, I finally have time to organize the journey from “why to do it” to “how to do it.” I can’t guarantee this is the most standard CI/CD workflow, but it is definitely a valuable starting point to help your team begin implementation, improve product stability, and enhance overall development efficiency.
Chapter
This series will start with “What is CI/CD and what value it brings,” then move on to a hands-on guide on “How to set up a CI/CD environment using GitHub Actions + self-hosted Runner.” Using app development as an example, it will demonstrate how to implement CI and CD in practice. Finally, it will introduce how to “use Google Apps Script Web App combined with GitHub Actions to create a convenient app packaging platform for cross-team use.” I hope this series will be helpful to you.
CI/CD Practical Guide (Part 2): Comprehensive Use and Setup of GitHub Actions and Self-hosted Runner
Final Outcome
No more nonsense, here is the final result.
CI/CD — Entirely developed using GitHub Actions, easy to maintain and extend.
CI:
Trigger Unit Tests Automatically on PR Submission
Run corresponding tests based on the scope of the changed files
Merge PR only after the test has passed.
CD:
Google Apps Script Web App (CD Packaging Interface) allows engineers, QA, and PMs to package apps on computers or mobile devices through this website.
GitHub Actions Self-hosted Runner: Using Your Own Machine for Unlimited CI/CD Usage
Integrate Firebase App Distribution API to Directly Obtain the Packaged Beta Download Link
Automation :
Auto-Assign Self on PR Submission
Assign Reviewers Automatically and Randomly When Creating a PR
Mark PR Size Label
Demo Web App/Project
Sign in Edit description script.google.com
What is CI/CD?
Story — Development Process Without CI/CD
Before discussing what CI/CD actually is, let’s set aside the term “CI/CD” and first recall how a startup development team without any workflow implemented would operate. The general process can be roughly summarized in the diagram below:
The product has a bug. Developer T created a branch fix/bug-c from the main branch to fix it. After the fix, the branch was merged back into the main branch.
Next, Developer Z branched off feature/a from the main branch to work on requirement A. Halfway through, they noticed the feature was acting strange. After checking, they found the current feature was broken, and the tests were failing. They then informed Developer T to fix it.
After all development is complete, Developer Z uses his computer to package the version for QA testing, repeatedly fixing and packaging. Once there are no issues, the feature is merged back into the main branch.
The sprint quickly came to an end, and it was time to package and release to users; Developer Z put aside current tasks to help package from the main branch for QA to perform regression testing, similarly going back and forth fixing issues and repackaging, then finally packaged and submitted the app for review.
After Apple/Google review is complete, release it to users.
Question
In the above story, we can summarize two major issues.
Question 1: There is no unified inspection mechanism for current correct functional changes.
Code That Does Not Meet the Coding Style Can Also Be Merged
Even if the build fails, I can still merge.
After changes, basic Unit Tests and important checkpoints failed but still merged
My environment functions correctly, but it may not work properly for others.
Affecting other developers currently working on the project
Question 2: A lot of manpower and time are spent on packing work.
Packaging requires engineers’ manpower, interrupting ongoing development work.
Switching between packaging and development causes high cognitive switching costs.
Waiting for packaging delays other development tasks.
Engineers’ time costs money.
Manual operations can lead to errors.
QA must ask engineers to package, causing back-and-forth communication.
CI — Continuous Integration
For Question 1, “Continuous Integration” aims to ensure that all changes automatically undergo Build & Test in a unified environment, guaranteeing that all modifications pass every test case and meet team standards before entering the production environment — “continuously and automatically ensuring correct code integration into production.”
You can also add Nightly Build and more automated testing stages to ensure stability.
CD — Continuous Delivery / Deployment Continuous Delivery / Deployment
Corresponding to Question 2, “Continuous Deployment” aims to automatically complete the packaging and deployment process of code changes after passing the CI stage without errors, delivering them to internal testing (QA, Debug, Staging, Beta…) or external release (Production, Release…).
Continuous Deployment: Fully automated direct deployment to the Production environment
Continuous Delivery: Automatically deploy only to Staging/Debug environments; manual verification is required before deploying to Production environment.
In the context of app development, it leans more towards Continuous Delivery, where we want a manual check to confirm everything is perfect before the app is officially released, ensuring the release timing and functionality are accurate.
Story — Building a Stable and Efficient Development Team Through CI/CD
Looking back at our story, after implementing CI/CD:
CI
All adjustments must pass automated testing verification before merging into the main branch. Add a Nightly Build scheduled automated testing phase to improve stability.CD
Using CD packaging consistently allows Developer T and Developer Z to fully focus on business development, reducing manual communication and operational errors.
Team Work Efficiency and Product Stability 🚀🚀🚀🚀🚀
The Value of CI/CD
Combining the core Agile development principle of “small steps, fast iteration,” CI/CD provides the foundation for stability and efficiency during frequent continuous feature iterations.
Automated Unified Verification of Iteration Results
- Ensure all adjustments meet the expected results, do not affect other functions, and do not impact other team members.
Automate Tedious Deployment Processes
- Enable team members to focus on core business development and reduce manual operation errors
The Effectiveness of CI/CD
Looking back at the 2021 Pinkoi talk “2021 Pinkoi Tech Career Talk — Secrets of High-Efficiency Engineering Teams,” the content was essentially the same: focusing on “automation, reducing dependence on people, and concentrating on core business.” Implementing CI/CD perfectly aligns with these three goals, allowing us to use the same approach to estimate its effectiveness.
Another point that needs to be highlighted again is the cost of flow switching:
After working continuously for a period, we enter a “flow” state, where our thoughts and productivity peak, allowing us to produce the most effective output. However, if interrupted, it takes time to return to this flow state—here, we use 30 minutes as an example.
In scenarios without CI/CD, it might be: spending a lot of time only to find out something was broken and then going back to communicate and adjust (CI), QA/PM asking engineers to help package the test version of the app (CD).
CI/CD Effectiveness Estimation
Team size: 6 people / calculated per month
Here, we use a monthly basis. Assuming no CI/CD process, there are 4 unexpected breaks in the main branch each month, causing about 720 minutes of repair and communication costs. Adding the time for packaging test and official versions and errors from manual operations, the total is about 1,010 minutes. With an engineer’s monthly salary of 80,000, this results in a monthly cost waste of about 13,000.
CI/CD Build Costs
Labor Cost:
Based on this series of articles, it is estimated that 1 person needs 10 days = 4,800 minutes to complete the work. (~= NT$36,384)Equipment and Execution Costs:
Using GitHub Actions self-hosted Runner only requires purchasing 1–2 Mac Minis initially or directly using existing retired MacBook Pros as CI/CD Runners to provide services.
For example, a 6-person team purchasing a brand new Mac Mini: 32G RAM M4 Mini (= NT$40,900)
The total cost is about NT$80,000, and benefits can be enjoyed starting around six months later.
Disclaimer: This is just one method to calculate benefits and may not be the most accurate; it is intended to provide a concept for everyone to expand on, enabling management to understand the benefits of CI/CD and thus approve the promotion and completion of the entire workflow.
Tool Selection for CI/CD
Cloud Services Bitrise / XCode Cloud
Bitrise: One of the earliest cloud services focused on App CI/CD. My first experience with CI/CD was using Bitrise. It offers a user-friendly and intuitive step editor, allowing quick setup of App CI/CD workflows.
Drawback: Initially, it was $99 for unlimited usage. When Apple M-series processors first came out, they switched to usage-based billing (lock-in strategy), and our team’s monthly cost was at least $500. So we migrated to GitHub Actions.
However, recently on their official site, they now offer 1 App / 1 Concurrent / unlimited usage / $89 per month.XCode Cloud: 100 hours / 1 month / $50, advantage is high integration with XCode and app development; however, the downside is it does not support Android and customizing some steps can be difficult. For small pure iOS apps, I would consider using it again.
Really worried about cloud services being a trap, so I prefer to keep control in my own hands and consider on-premise services instead.
On-Premises Services Jenkins / GitHub Actions / Gitlab CI/CD
Gitlab CI/CD:
It was launched earlier and has more complete features than GitHub Actions, but since our project is hosted on GitHub, we won’t consider using Gitlab CI/CD. However, both have similar functions, and this series will use GitHub Actions as an example.GitHub Actions
GitHub launched its CI/CD service in 2018, directly integrated with GitHub projects. It has continuously improved over the years, offering many pre-built steps (Marketplace) ready to use. It supports self-hosted runners, allowing unlimited use of your own machines (effectively a hybrid cloud).Jenkins:
An open-source, free tool specialized in CI/CD, old but powerful; it covers everything from application-level task design and permission management to backend service dispatch and execution. Jenkins is all-inclusive. It also offers Plugins for direct integration and is an essential tool for early DevOps CI/CD.
Jenkins v.s. GitHub Actions
TL;DR
In app teams without dedicated DevOps, expecting app developers to set up and maintain a Jenkins environment from scratch is too challenging. Few know how to do it, and it can lead to network security issues. Choosing GitHub Actions allows app developers to focus solely on designing the CI/CD process. By briefly reviewing the official documentation on writing workflows and starting runners, they can quickly build a free, stable, and secure CI/CD service.
The following comparison is based solely on setting up App CI/CD and does not apply to all technical scenarios.
Setup and Maintenance Difficulty Jenkins »> GitHub Actions
Here is a simple layered diagram to explain the difference between the two. As mentioned before, Jenkins covers all functions from top to bottom, making self-hosting much more complex. In contrast, GitHub Actions only requires writing YAML workflows on GitHub. On the local machine, you just need to register the GitHub self-hosted Runner (completed with 5 commands), and GitHub will automatically dispatch tasks to the local machine. Other issues, such as GitHub Actions/Runner version upgrades or task dispatch problems, are maintained by GitHub, so we don’t need to handle them.
Another more troublesome point is that Jenkins is a service independent of Git, and communication between them must be done through APIs (e.g., GitHub API/WebHook), making the setup even more complex.
I previously surveyed about 30 iOS developers around me. Only a few (2) understood Jenkins, while more than 10 were using GitHub Actions. After all, writing a bit of YAML can complete CI/CD tasks.
Learning Difficulty Jenkins »> GitHub Actions
Just refer to the official documentation to learn the available YAML commands for GitHub Actions and how to set up your own Runner locally.
Stability: GitHub Actions > Jenkins
I think GitHub Actions slightly outperforms Jenkins in this aspect.
Jenkins may crash due to system upgrades or conflicting plugins (however, if it’s running smoothly, it generally has no issues as long as you don’t interfere).
GitHub Actions depends on GitHub Service Status (if GitHub is down, it will be down too), but outages are rare, with an average uptime of 99.9%. If a problem occurs, just wait for it to be fixed.
Security: GitHub Actions > Jenkins
Considering that GitHub Actions/Runner is maintained and automatically updated by GitHub itself, it may be safer than Jenkins, which requires manual updates.
Additionally, opening API/WebHook ports for communication between Jenkins and GitHub is relatively risky. GitHub and GitHub Actions integrate seamlessly, and the relationship between GitHub Actions and the self-hosted Runner is observer-based. The self-hosted Runner requests tasks from GitHub, so the Runner itself does not need to expose any external interfaces.
But in a fully closed network environment, Jenkins is more secure than GitHub Actions.
Permission Control Jenkins »> GitHub Actions
This point needs special comparison: Jenkins allows setting up account login permissions for control; GitHub Actions is directly tied to the GitHub Repo, so only those with Repo permissions can use it.
Therefore, the following article uses GAS Web App to build a cross-team operation platform.
Using Jenkins Extensively »> GitHub Actions
For teams with a full DevOps team, Jenkins is undoubtedly the preferred choice. After all, in other fields (such as Web, backend, Java…), Jenkins has been running the longest, offers the most useful plugins, and allows building a unified CI/CD system for all teams, making management easier. It also supports complex CI/CD scenarios like deploying the backend first and then automatically deploying the frontend.
GitHub Actions later also supports cross-repo Actions/Runners.
Richness of Third-Party Plugins Jenkins > GitHub Actions
In terms of quantity, GitHub Actions outnumbers Jenkins, but Jenkins offers deeper and more powerful CI/CD capabilities. Many features of GitHub Actions are primarily automation functions.
Feature Depth Jenkins »> GitHub Actions
This aspect is unmatched. Jenkins has been around for nearly 20 years, while GitHub Actions still needs to add many features; for example: permission management, secret management (currently only supports plain text, key files must be converted to plain text first), cache/artifact support is currently limited to the cloud, and so on.
Additionally, GitHub Self-hosted Runner also supports Docker or k8s.
Customized Deep Jenkins »> GitHub Actions
Jenkins is fully controlled by yourself, offering greater customization of permissions that can affect the entire system. GitHub Actions can only customize different steps at the application level.
For example, since the built-in Artifacts in GitHub Actions do not support self-hosted runners, you can only change the step to use sh to copy files to another directory, and cannot customize your own Artifacts implementation.
App CI/CD scenarios do not require very advanced features.
Usability GitHub Actions »> Jenkins
On the interface, GitHub Actions is a newer tool and is easier to use than Jenkins;
In terms of script configuration, Jenkins uses Pipeline Scripts stored on Jenkins, while GitHub Actions uses YAML files managed with the project’s Git, making it easier to set up than Jenkins.
Cost Risk Jenkins > GitHub Actions
Jenkins is fully open-source and free to use, while GitHub Actions is partially open-source but its task dispatching and execution are part of GitHub’s closed SAAS service. Currently, GitHub Actions is completely free; you only pay for using GitHub Runners (Private Repo), but self-hosted runners are free.
Uses of Google Apps Script Web App and Why Choose It
Another tool option is Google Apps Script Web App. The reason for needing this is that GitHub Actions’ built-in form feature is too basic (the interface is too technical and static) and its execution permissions are tied to the GitHub repo. This makes it very inconvenient if we want to provide access to other functional partners.
As follows:
CD packaging often requires the operator to fill in some information, such as Release Notes.
Therefore, we need an “interface” tool for other partners to use or even for our own engineers to use more conveniently.
Required Scenario:
Fill in the required information on this more user-friendly “interface,” connect to project management tools (e.g., Jira, Asana) to fetch Tasks, or directly retrieve the PR list from GitHub. Then select from the dropdown menu and submit, triggering GitHub Actions through the GitHub API to perform packaging.
Slack
When we first implemented CI/CD, we chose to integrate the Slack API to achieve an effect like the following:
https://slack.com/intl/zh-tw/blog/productivity/workflow-builder-tools-automation-examples
- Partners can fill out forms directly in Slack to submit information, trigger CD packaging, and receive Slack notifications.
The operation is smooth and unified within daily office tools (SSOT), requiring no relearning; however, the underlying issue is that development and maintenance costs are very high. One reason is that the Slack Outgoing-Webhook API demands a very fast response (within 3 seconds), which basically rules out using FAAS services for simple integration (e.g., Cloud Functions, GAS, Lambda…).
Previously, a team member interested in automation and backend development created a complete backend service using Kotlin+ktor, then deployed the server on GCP for Slack integration.
Development and maintenance costs are extremely high, and handover is very difficult.
Google Apps Script — Web App
Previously shared “Using Google Apps Script Web App Form to Integrate with Github Action CI/CD Workflow”:
Advantages of Using Google Apps Script — Web App:
Website Web
Similar to Google Workspace enterprise account permission management, you can set access so that only Google accounts within the organization are allowed.
Completely Free
Function as a Service Does Not Require Setting Up or Maintaining Servers
Easier to maintain and hand over
Can be operated on a mobile phone
AI Can Help!
Whether it’s ChatGPT or other AI tools, they are very familiar with GAS and can directly help us create packaged forms and connect to the GitHub API.Can also integrate with Jira, Asana, Slack notification APIs
For the second promotion, I switched to using a GAS Web App for the team, which also received great feedback. The only difference from Slack is that you need to bookmark an additional URL. When packaging is needed, open the URL and operate the packaging through the web form.
Complete App CI/CD Tool Workflow
Here is the complete workflow. In the next article, I will gradually explain how to use and integrate each tool.
Tool Role:
GitHub Actions: CI/CD logic script code
GitHub Actions — Self-hosted Runner: The actual environment where CI/CD runs. Using your own hosted runner means you only pay for the machine, enabling unlimited task executions.
Google Apps Script Web App: Since packaging is not always done by engineers, a platform is needed for cross-functional partners; GAS Web App can quickly create a web tool and share the URL for others to use.
Asana/Jira: Project management tools that integrate with GAS Web App, allowing QA/PM to directly select tasks for packaging.
Slack: Handles receiving execution result notifications
Scenario:
End-User (QA/PM/PD/Developer): Use GAS Web App to submit the packaging form (fetch the Branch corresponding to the Jira or Asana task) -> GAS calls GitHub API -> trigger CD packaging GitHub Actions <- GitHub self-hosted runner listens to the task and pulls it to the machine for execution -> upon completion, send Slack notification and update the packaging status in GAS Web App.
End-User (Developer): Open PR, push new commit to PR -> trigger CI test process <- GitHub self-hosted runner listens for task, pulls it to the machine for execution -> after completion, comment test results and update Checks.
Summary
This article mainly provides an introduction to what CI/CD is and its benefits. The next article will dive into the technical aspects, guiding you step-by-step to understand and implement GitHub Actions CI/CD, leading to the final outcome discussed earlier.
Series Articles:
Buy me a coffee
If you have any questions or feedback, feel free to contact me.
This post was originally published on Medium (View original post), and automatically converted and synced by ZMediumToMarkdown.