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.

React Native (bare) · Framework guide | buildtree docs