React Native (bare)
Configure the build
Add a buildtree.config.json at your project root:
{
"builds": {
"ios": {
"command": "cd ios && fastlane build_adhoc",
"artifact": "ios/build/MyApp.ipa"
},
"android": {
"command": "cd android && ./gradlew assembleRelease",
"artifact": "android/app/build/outputs/apk/release/app-release.apk"
}
}
}
Adjust MyApp.ipa to match your scheme name. Then:
buildtree publish ios --env dev
buildtree publish android --env dev
The artifact field must be a single, exact file path. No globs.
Upload builds by branch
# Feature branch (pre-merge QA build)
buildtree publish ios --env dev --branch feature/payments
# Develop checkpoint after merge
buildtree publish ios --env dev
See the pre-merge QA workflow for how env + branch fits a trunk-based dev cycle.
Fastlane on iOS
lane :build_adhoc do
build_app(
workspace: "MyApp.xcworkspace",
scheme: "MyApp",
export_method: "ad-hoc",
output_directory: "./build",
output_name: "MyApp.ipa",
clean: true
)
end
export_method: "ad-hoc" is load-bearing. Ad-hoc IPAs are the kind that work with the UDID-based device flow. App Store or development IPAs do not install via a buildtree install URL.
Gradle on Android
assembleRelease produces an APK at android/app/build/outputs/apk/release/app-release.apk. Configure signing in android/app/build.gradle:
signingConfigs {
release {
storeFile file('release.keystore')
storePassword System.getenv('STORE_PASSWORD')
keyAlias 'release'
keyPassword System.getenv('KEY_PASSWORD')
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
Skip the build step
If your CI already builds the IPA / APK in a separate step, skip publish and call upload directly:
buildtree upload ios/build/MyApp.ipa --env dev --branch feature/payments
buildtree upload android/app/build/outputs/apk/release/app-release.apk --env dev --branch feature/payments
This avoids the buildtree config requirement entirely; the file path is enough.
Parallel branch installs
Two builds that share a bundle identifier overwrite each other on the same test device. Use a Fastlane lane that takes a suffix:
lane :build_adhoc do |options|
suffix = options[:suffix] || ""
update_app_identifier(
xcodeproj: "MyApp.xcodeproj",
plist_path: "MyApp/Info.plist",
app_identifier: "com.yourcompany.app#{suffix}"
)
build_app(
workspace: "MyApp.xcworkspace",
scheme: "MyApp",
export_method: "ad-hoc",
output_directory: "./build",
output_name: "MyApp.ipa",
clean: true
)
end
Invoke with a per-branch suffix:
fastlane build_adhoc suffix:.preview
Each variant bundle identifier needs its own ad-hoc provisioning profile registered with the same UDIDs.