matinzd ec2b536e14 feat(android): support Activity Result API for native modules (#57798)
Summary:
Rendered readme can be found [here](https://github.com/matinzd/react-native/blob/feat/permission_contracts_android/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/activityresult/__docs__/README.md).

Bare React Native has no way for a native module to use AndroidX `ActivityResultContract`s. Modules are stuck with `ActivityEventListener` and self-assigned int request codes, and some contracts (e.g. Health Connect's permission contract) have no `startActivityForResult` equivalent at all. Calling `registerForActivityResult` on `getCurrentActivity()` instead is a dead end: the lifecycle-observing overload crashes with `LifecycleOwner ... is attempting to register while current state is RESUMED. LifecycleOwners must call register before they are STARTED.`, because AndroidX only allows it before the Activity is `STARTED` — and native modules are created lazily, long after that ([https://github.com/react/react-native/issues/33639](https://github.com/facebook/react-native/issues/33639)).

Libraries work around this by demanding glue code in the consumer's `MainActivity`: react-native-health-connect today requires every app to add `HealthConnectPermissionDelegate.setPermissionDelegate(this)`. The proposed alternative — shipping a transparent `Activity` in the library's manifest ([matinzd/react-native-health-connect#266](https://github.com/matinzd/react-native-health-connect/pull/266), still an unreleased PR) — cuts against Google's single-activity guidance ([https://github.com/react/react-native/issues/33639](https://github.com/facebook/react-native/issues/33639), [https://github.com/react/react-native/issues/36377](https://github.com/facebook/react-native/issues/36377)). Expo solved this with [`registerActivityContracts`](https://docs.expo.dev/modules/module-api/#registeractivitycontracts); bare RN has no equivalent.

`ReactActivity` already extends `ComponentActivity`, so it already owns a real `ActivityResultRegistry` and routes results into it. Core just needs to hand modules a path to that registry:

```kotlin
private val getContent = reactContext.registerForActivityResult(
    /* owner = */ this, ActivityResultContracts.GetContent()) { uri -> ... }

getContent.launch("image/*")
```

Design notes:

- API mirrors `ComponentActivity.registerForActivityResult` and returns the real `androidx.activity.result.ActivityResultLauncher<I>`. The one addition is a leading `owner` argument, which scopes the registration key.
- Modules register before an Activity exists (they are created lazily), so the returned launcher binds to the registry on `onHostResume` and queues a `launch()` issued while unbound.
- No changes to `ReactActivity`/`ReactActivityDelegate`/`ReactDelegate`, no new Gradle dependency, no manifest changes, no forked registry. `ActivityEventListener` is untouched.
- Known limitation: on process death, AndroidX redelivers the pending result under the same key, but the module's in-flight state (typically a `Promise`) died with the JS context.

Demos: `SampleTurboModule.requestSamplePermission()` (CAMERA), plus `pickMedia` and `pickMultipleMedia` (photo picker, single and multi select with a JS-controlled limit), surfaced in rn-tester's SampleTurboModule and PhotoPickerAndroid screens.

## Changelog:

[ANDROID] [ADDED] - Add support for Activity Result API for native modules

Pull Request resolved: https://github.com/react/react-native/pull/57798

Test Plan:
- `./gradlew :packages:react-native:ReactAndroid:compileDebugKotlin` and `:compileDebugJavaWithJavac` pass; codegen emits the sample module methods into `NativeSampleTurboModuleSpec`.
- Flow, ESLint, prettier, and ktfmt clean.

## Example App Recording

https://github.com/user-attachments/assets/63750917-2325-4613-9a0d-b7241ae026eb

Reviewed By: javache

Differential Revision: D115622269

Pulled By: Abbondanzo

fbshipit-source-id: ce623a84d3c5b29f1bae57c2c177517d0cd34190
2026-09-25 10:50:37 -07:00
2026-09-24 17:03:47 -07:00
2025-07-15 10:10:35 -07:00
2026-09-24 17:03:47 -07:00
2026-01-06 03:23:09 -08:00
2026-06-08 03:32:23 -07:00
2026-06-04 10:12:52 -07:00
2026-02-10 07:41:08 -08:00
2026-09-24 17:03:47 -07:00
2026-09-24 17:03:47 -07:00

React Native logo

Learn once, write anywhere:
Create native apps for Android, iOS, and more using React

React Native is released under the MIT license Current npm package version Monthly npm downloads Follow @reactnative on X

Getting Started · Learn the Basics · Showcase · Contribute · Community · Support

React Native

React Native lets you build native apps using React. Written in JavaScript, rendered with native code.

  • Native UI. React Native primitives render to native platform UI, meaning your app uses the same native platform APIs other apps do. Gestures, text scaling, and accessibility behave the way users expect on each OS.
  • React, everywhere. Declarative UI, components, hooks, and Suspense, reused across Android, iOS, and other platforms.
  • Developer Velocity. See local changes in seconds. Changes to JavaScript code are applied with Fast Refresh, without rebuilding the native app.
  • Extend it yourself. Native Modules let you call platform code directly from JavaScript, synchronously and type-safe — or reach for thousands of existing libraries.

React Native is developed and supported by many companies and individual core contributors. Find out more on the React Foundation website.

Building your first React Native app

Follow the Getting Started guide for a new app, or Integration with Existing Apps to adopt React Native incrementally.

Using a Framework

We believe that the best way to experience React Native is through a Framework, a toolbox with all the necessary APIs to let you build production ready apps. Expo is a production-grade React Native Framework, with file-based routing, a standard library of native modules, and much more.

To create a new Expo project, run the following in your terminal:

npx create-expo-app@latest

Then follow the rest of Expo's getting started guide to start building.

Without a Framework

You can also use React Native without a Framework, however we've found that most developers benefit from one — navigation, native dependencies, and platform tooling are problems the ecosystem has already solved. If a Framework doesn't suit your app, follow Getting Started Without a Framework.

Documentation

The full documentation for React Native can be found on our website.

The source for the React Native docs and website is hosted on a separate repository, react/react-native-website.

Contributing

The main purpose of this repository is to continue evolving React Native core. We want to make contributing to this project as easy and transparent as possible, and we are grateful to the community for contributing bug fixes and improvements. Read below to learn how you can take part in improving React Native.

Code of Conduct

Meta has adopted a Code of Conduct that we expect project participants to adhere to. Please read the full text so that you can understand what actions will and will not be tolerated.

Contributing Guide

Read our Contributing Guide to learn about our development process, how to propose bugfixes and improvements, and how to build and test your changes to React Native.

Discussions

Larger discussions and proposals are discussed in react-native-community/discussions-and-proposals.

React Native releases are discussed in reactwg/react-native-releases.

License

React Native is MIT licensed, as found in the LICENSE file.

Languages
C++ 34.7%
Kotlin 21.8%
JavaScript 19.8%
Objective-C++ 9.7%
Objective-C 5.5%
Other 8.4%