Docs
Build iOS and Android apps on GitHub Actions
No Mac needed on your side and no build service minutes to buy: your own GitHub repository builds the app on its Actions minutes. iOS builds are signed with your App Store Connect key and go to AppForShare for your testers or to TestFlight. Android builds are signed with your upload keystore and go to AppForShare or to a Google Play track. Pro and Team; iOS needs an App Store Connect connection, Google Play needs a Google Play connection.
1. Install the AppForShare Builds app
From Dashboard, Builds, Build on GitHub. You choose the GitHub account or organization and which repositories the app can see. It can open pull requests, set Actions secrets and start workflows; it never pushes to your branches and never merges.
2. Set up a repository
Pick iOS or Android, the repository and the branch to build. For iOS: the App Store Connect key, the bundle ID (the Apple Team ID is filled in when Apple knows it), the .xcworkspace or .xcodeproj, the scheme, where the build goes, how it is signed and how the build number is set. For Android, see the Android section below. AppForShare stores encrypted Actions secrets in the repository and opens a pull request with the workflow file. A repository can have one iOS and one Android setup. When you build a branch other than the default one, a second pull request adds the same file to the default branch, because GitHub only starts a workflow by hand when it is there too; it never runs on a push.
3. Review and merge the pull request
The workflow is a normal file in your repository: .github/workflows/appforshare-ios.yml or appforshare-android.yml. Read it before you merge, and change it later if you need to. AppForShare only starts it and reads its runs.
4. Start builds
Anyone in the workspace with the Developer role or higher starts a build with optional release notes, a channel and a build number. The run uses your repository's GitHub Actions minutes, on a macOS runner for iOS and a Linux runner for Android. AppForShare shows its progress, the person who started it, the log link and, for builds sent to AppForShare, the new build with its install link, or for Google Play, the version code and track.
Signing
- Xcode's automatic signing with your App Store Connect key makes or updates the provisioning profile. Ad hoc builds include every device registered on your Apple account, so register your testers' devices first (Dashboard, Devices).
- Without a certificate of its own, Xcode asks Apple for a cloud managed distribution certificate, and Apple allows that only for keys with wide access. We recommend adding your distribution certificate as two more secrets instead, so the key keeps a smaller role:
APPFORSHARE_CERT_P12(the .p12 file in base64) andAPPFORSHARE_CERT_PASSWORD. - Or pick "My own Apple Distribution certificate": the workflow sets manual signing on the app target only, so CocoaPods and other targets keep their own settings (one override for every target breaks Pods). Add the two certificate secrets above. Before each build, AppForShare reads the newest App Store (TestFlight) or ad hoc profile of the bundle ID from Apple, or makes one with your valid distribution certificates (and, for ad hoc, every enabled iPhone and iPad), and stores it as the
APPFORSHARE_PROFILEsecret. If the app has push notifications, the build uses the production push environment. Apps with extensions (widgets, notification service) need automatic signing for now. - The key is written to the runner's temporary folder for the build and removed at the end of every run.
Secrets AppForShare sets
APPFORSHARE_TOKEN: an upload token made only for this repositoryAPPFORSHARE_ASC_KEY_ID,APPFORSHARE_ASC_ISSUER_ID,APPFORSHARE_ASC_KEY_P8: your App Store Connect key
GitHub encrypts them and never shows them again, but workflows in the repository, and people who can change workflows, can use them. When you remove the setup, AppForShare deletes the secrets and revokes the token. A client's key connected through an invite link is never copied into a repository.
Build number and version
App Store Connect needs a new, higher build number for each upload. Keep the project's own, or let each run use the date and time (like 2611011430) or the workflow's run number. A number given when you start a build wins. You can also set the version (like 1.4.0); empty keeps the project's.
Android
- Give the folder with gradlew (android for React Native and Flutter, empty for a native app at the root), the app module (app) and the variant, like release or prodRelease when you use flavors. Pick Java 17 or 21 and, for React Native, a Node.js version.
- Signing with your upload keystore: add four secrets in GitHub,
APPFORSHARE_ANDROID_KEYSTORE(the keystore file in base64),APPFORSHARE_ANDROID_KEYSTORE_PASSWORD,APPFORSHARE_ANDROID_KEY_ALIASandAPPFORSHARE_ANDROID_KEY_PASSWORD(for a PKCS12 keystore this is the keystore password). The build signs with them the way Android Studio does, so your Gradle files stay as they are. AppForShare never receives them. Or pick your own Gradle signing if the release build already signs. - To AppForShare: the run builds an .apk and uploads it with the AppForShare GitHub Action, so testers install it from a link.
- To Google Play: the run builds an .aab and sends it to AppForShare, which uploads it to the track you picked (internal, closed or open testing, or production) with your workspace's Google Play connection. The Play key is never copied into the repository. A production release is always left as a draft for you to roll out in Play Console, and an app that was never published only takes drafts. AppForShare never cancels changes that are already in review at Google.
- Version code: the project's own, or the workflow's run number, and a number given when you start a build wins. Google Play needs a new, higher code for every upload. You can also set the version name. Both are set for the build only, without changing your Gradle files.
- AppForShare sets one secret for Android,
APPFORSHARE_ANDROID_TOKEN, an upload token made only for this setup, so an iOS setup on the same repository keeps its own.
# React Native (Gradle folder: android)
npm ci
# React Native in a monorepo (Gradle folder: apps/mobile/android)
cd apps/mobile
npm ci
# Make the keystore secret on your computer
base64 -i upload-keystore.jks | pbcopy # macOS
base64 -w0 upload-keystore.jks # LinuxFor Flutter, add a Flutter setup step to the workflow file (for example subosito/flutter-action) and flutter pub get as a setup command, then point the setup at the android folder.
Flutter, React Native and CocoaPods
Add the commands that prepare the iOS project as setup commands, for example:
# Flutter
flutter pub get
flutter build ios --release --no-codesign --config-only
# React Native
npm ci
cd ios && pod install
# React Native in a monorepo (app in apps/mobile)
cd apps/mobile
npm ci
cd ios && pod installThen point the setup at ios/Runner.xcworkspace (Flutter) or ios/YourApp.xcworkspace (React Native). The .xcworkspace may be made by pod install; it does not need to be in the repository. Pick a Node.js version in the setup for React Native, Expo and Capacitor apps; add a Flutter setup step to the workflow file if your runner needs a specific Flutter version.