Skip to content

[SDK-800] Provision and prove React Native apps on Android and iOS - #31

Merged
franco-zalamena-iterable merged 6 commits into
mainfrom
feat/rn-provision-verify
Oct 22, 2026
Merged

franco-zalamena-iterable merged 6 commits into
mainfrom
feat/rn-provision-verify

Conversation

@franco-zalamena-iterable

@franco-zalamena-iterable franco-zalamena-iterable commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Ticket

SDK-800

Summary

React Native apps, bare and Expo, now go through the same provisioning and verification tools as native apps, on both platforms. An RN integration is finished when both platforms have been proved: Android first, then iOS.

  • iterable-react-native routes a two-platform app through Android before iOS:

    • Android: provision, integrate, iterable-android-verify green.
    • iOS: then provision, integrate, iterable-ios-verify green.

    It also:

    • owns the bare iOS native push code: the AppDelegate token and handlers, a native notification-permission request at launch, and universal links in the 0.88 SceneDelegate;
    • gives the exact Release Simulator build and install commands, with signing on;
    • loads the Mobile key the way provisioning delivers it;
    • resolves the SDK version with one npm view that works with a scoped private registry, and never prints an npmrc;
    • says the New Architecture is always on from RN 0.82;
    • pins the corpus to SDK 3.2.1.
  • iterable-provision (iOS) works from an RN or Expo app:

    • Finds the app. A shared resolver locates the app root, the Xcode project (ios/) and the framework.
    • Reuses the Android setup. Both Iterable keys, the region, No JWT and the test email, all validated again for iOS. It finds that setup in a parent folder when the app is in a monorepo.
    • Carries over the scope the RN skill confirmed. The developer sees it on the import and final confirmation screens before anything is written.
    • Delivers the Mobile key to a gitignored file the app reads: .iterable/rn/iterable.local.ts on bare RN, EXPO_PUBLIC_ITERABLE_API_KEY in .env.local on Expo.
    • Binds a fresh build: restart --app-path attaches a new build to an existing proof run.
  • iterable-ios-verify understands RN and Expo:

    • It reads the integration signals where each kind of app keeps them, and prunes node_modules, Pods and build output.

    • Proof requires a Release Simulator build, because a Debug build has no embedded main.jsbundle.

    • Before any push advice, it checks the app actually installed on the Simulator (I6, and an ios-prove preflight):

      • it contains the Iterable SDK, and for RN its bundle references RNIterableAPI;
      • it carries aps-environment;
      • it matches the recorded build;
      • it isn't older than the source.

      Each failure names its cause and the rebuild command, and nothing is sent.

    • It warns when an Expo app never asks for notification permission.

  • Android provisioning screens put their steps, links, values and the list of changes being approved in the prompt itself, as iOS does, and link to app.eu.iterable.com for an EU project. The package screens recommend the RN app's applicationId.

It also fixes the Android and RN deep-link guidance found by an audit against the SDK sources:

  • the urlHandler → ACTION_VIEW / Linking.openURL redirect loop;
  • only https being implicit in allowed protocols;
  • wrong routing rows;
  • App Links autoVerify;
  • the Expo plugin configuring no deep links.

Stacked on #30.

Reviewing it

Six commits, grouped by area. Each file appears in exactly one commit, and the suites pass at the tip.

  1. Fix Android deep-link guidance found by the SDK audit. iterable-android/.
  2. Route React Native through Android first, then iOS. iterable-react-native/ (skill, pitfalls 16–22, regenerated corpus) and INTENDED-FLOW.md.
  3. Prove iOS push for React Native and Expo apps. The shared resolver (bin/ios-project.sh), the installed-app checks (bin/ios-app-check.sh), ios-verify, ios-prove, the iOS actors, and their tests.
  4. Provision React Native and Expo iOS from the Android setup. bin/ios-provision, bin/ios-questions.sh, iterable-provision/, and their tests.
  5. Show each Android provisioning screen's steps in its prompt. bin/questions.sh, bin/iterable-keys, and the Android package detection in bin/config.sh.
  6. Bump the plugin to 26.10.3-beta.

How it was tested

  • Suites: the full tests/run-all.sh was run locally (macOS, bash 3.2). Results: 46 suites ok (898 checks); one is skipped (it needs a green live project) and two are opt-in network suites. The opt-in skill-snippets-ios.sh passes too. The new checks are mutation-tested: removing each guard makes a test fail.
    • One live-Google suite fails: wizard-decline.exp. CI skips it, and it fails the same way on the base commit, so it's a pre-existing terminal-wizard bug rather than a change here. When no gate is red (for example, two devices attached), the wizard skips the Google consent even though the service-account gates are still pending. It will be fixed separately.
  • Live, bare RN (a Dog Shelter clone, RN 0.88, an API 36 Android emulator with Play services and an iOS 26.2 Simulator), run by a fresh agent session on an earlier build of this branch:
    • Android:
      • Provisioning was green from G0 to G10.
      • The token was registered in Iterable (G15).
      • The first proof push reached the device: the SDK logged it as received. It wasn't displayed while the app was in the foreground.
      • The session then backgrounded the app and sent a second push, which displayed. That is outside the verifier's rules (no UI operation, no second send), so display is proved only on the second push.
    • iOS:
      • Provisioning was completed: the Android import, the carried-over scope, the guided Apple steps, the APNs key, and the Iterable iOS app and credential.
      • The final ios-prove observed this run's push, and ios-verify status returned done.
      • That run used react-native-permissions for the permission prompt. The skill now prescribes the native at-launch request instead, which is compiled but has not been run live.
    • What the run found, all fixed in this PR:
      • Android screens whose steps the agent never showed (commit 5).
      • An install that printed a credential file and fought a scoped registry 401 (commit 2).
      • A stale pre-integration build installed four times, plus a build with code signing off (commits 2 and 3).
      • An invented Iterable.registerForPush() (commit 2).
  • Live, Expo: TODO

Known limitations

  • Monorepos: Android package auto-detection doesn't support them yet; the developer types the package name.
  • Expo permission warning: it matches the request call by name only, so an unrelated requestPermissionsAsync() silences it.
  • XcodeGen-only projects (a project.yml and no .xcodeproj): the printed Release build command is empty.
  • Physical iPhone, production and TestFlight: not proved, as in [SDK-597] Native iOS v1: integrate, provision, and prove push on the Simulator #30.

🤖 Generated with Claude Code

A urlHandler that returns false re-opens the URL: Android fires ACTION_VIEW
pinned to the app itself, so a link on the app's own scheme or tracking
domain loops, offline too, because a failed redirect passes the tracking URL
on. The allowed-protocols pitfall claimed http was implicit; only https is,
and the match is case-sensitive on the text before "://". The routing rows
sent allowed protocols to the UUA article and deep links to the
Branch/AppsFlyer stub.

The skill now has a compiled App Links snippet with the 3.7.0 names,
autoVerify, and the Iterable prerequisites, and new pitfalls 24-25.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A React Native app now finishes Android (provisioned, integrated, and proved
by iterable-android-verify) before iOS starts. The iOS phase reuses the
Android setup and the scope confirmed in Step 0, which the skill passes as
--features. The app is integrated when every platform in scope has passed
its verifier.

For bare iOS the skill owns the native push code: the AppDelegate token and
notification callbacks, a native notification-permission request at launch,
and universal links in the 0.88 template's SceneDelegate. It gives the exact
Release Simulator build and install commands, with signing on, because a live
trial installed a stale build found with find and built with code signing
off, which strips aps-environment. It loads the Mobile key the way
provisioning delivers it: an optional require on bare React Native and
EXPO_PUBLIC_ITERABLE_API_KEY on Expo, where push sets
requestPermissionsForPushNotifications.

Install resolves the latest version with one npm view that survives a scoped
private registry, and never prints an npmrc. The New Architecture is always on
from 0.82, so the installing article's opt-out is skipped. Deep links no
longer loop through Linking.openURL. The Xcode 27 notes live in pitfall 12,
and the skill and its regenerated corpus are pinned to SDK 3.2.1. New pitfalls
16-22.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bin/ios-project.sh answers where the app is, where its Xcode project is, and
which kind of app it is: native, react-native, or expo. Every iOS actor
resolves through it. Source scans prune node_modules, Pods and build output,
so the SDK's own sources no longer pass for the app's integration, and
inspect reads React Native signals where they live.

The proof artifact for React Native is a Release build: a Debug Simulator
build has no main.jsbundle and runs only while Metro serves it.

Before giving any push advice, I6 and ios-prove now check the app actually
installed on the Simulator. It must contain the Iterable SDK (and, for
React Native, a bundle that references RNIterableAPI), carry aps-environment,
match the recorded build, and not be older than the source. A live trial
reinstalled a pre-integration build four times, and ios-prove's first answer
sent it hunting for a permission problem. inspect warns when an Expo app
never asks for notification permission.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The iOS provisioning path writes the Mobile key where a JavaScript app reads
it: .iterable/rn/iterable.local.ts on bare React Native, and
EXPO_PUBLIC_ITERABLE_API_KEY in a gitignored .env.local on Expo. Native apps
keep the xcconfig.

When the Android program already ran, iOS offers import-from-android. One
Mobile and one Server-side key serve both platforms, with the Android region,
No JWT and test email, validated again for iOS. The search walks up to the git
toplevel, so a monorepo app finds the workspace kept at the root.

The scope the React Native skill confirmed arrives as --features. It is shown
on the import and confirmation screens before anything is written, and
recorded with its source. restart --app-path now binds a fresh build to an
existing proof run, and a missing .app is refused before anything is
archived.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A live trial's agent never printed context on any Android screen, so the
developer saw "Which key is on your clipboard?" with no steps. The Firebase
approval also asked them to agree to "the changes listed above" with no list
on screen. The steps, links, values, and the list of changes being approved
now go in the prompt, with the question last, as on iOS. Steps 1 and 2 link to
app.eu.iterable.com for an EU base, and "show again" re-asks the question
instead of printing into a tool result nobody sees.

The package screens recommend the applicationId read from the app's app.json
or build.gradle.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@franco-zalamena-iterable franco-zalamena-iterable changed the title Provision and prove React Native apps on Android and iOS [SDK-800] Provision and prove React Native apps on Android and iOS Oct 21, 2026
Base automatically changed from feat/ios-v1 to main October 22, 2026 12:20
@franco-zalamena-iterable
franco-zalamena-iterable marked this pull request as ready for review October 22, 2026 12:20
@franco-zalamena-iterable
franco-zalamena-iterable deleted the feat/rn-provision-verify branch October 22, 2026 12:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant