Skip to content

add result to popToNative #111

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,11 @@ ReactNativeBrownfield.setNativeBackGestureAndButtonEnabled(true);

**popToNative(animated[iOS only]: boolean)**

A method to pop to native screen used to push React Native experience.
A method to pop to back to the native screen.
Can also pass back data through the second param.

```js
ReactNativeBrownfield.popToNative(true);
ReactNativeBrownfield.popToNative(true, { result: '👋' });
```

> NOTE: Those methods works only with native components provided by this library.
Expand Down
15 changes: 14 additions & 1 deletion android/src/newarch/ReactNativeBrownfieldModule.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
package com.callstack.reactnativebrownfield

import android.app.Activity;
import android.content.Intent

import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactMethod
import com.facebook.react.bridge.ReadableMap

class ReactNativeBrownfieldModule(reactContext: ReactApplicationContext) :
NativeReactNativeBrownfieldModuleSpec(reactContext) {
Expand All @@ -10,7 +15,15 @@ class ReactNativeBrownfieldModule(reactContext: ReactApplicationContext) :
}

@ReactMethod
override fun popToNative(animated: Boolean) {
override fun popToNative(animated: Boolean, result: ReadableMap?) {
if (result != null) {
val bundle = Arguments.toBundle(result)
if (bundle != null) {
val intent = Intent()
intent.putExtras(bundle)
reactApplicationContext.currentActivity?.setResult(Activity.RESULT_OK, intent)
}
}
shouldPopToNative = true
onBackPressed()
}
Expand Down
15 changes: 14 additions & 1 deletion android/src/oldarch/ReactNativeBrownfieldModule.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package com.callstack.reactnativebrownfield

import android.app.Activity;
import android.content.Intent

import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
import com.facebook.react.bridge.ReadableMap

class ReactNativeBrownfieldModule(reactContext: ReactApplicationContext) :
ReactContextBaseJavaModule(reactContext) {
Expand All @@ -11,7 +16,15 @@ class ReactNativeBrownfieldModule(reactContext: ReactApplicationContext) :
}

@ReactMethod
fun popToNative(animated: Boolean) {
fun popToNative(animated: Boolean, result: ReadableMap?) {
if (result != null) {
val bundle = Arguments.toBundle(result)
if (bundle != null) {
val intent = Intent()
intent.putExtras(bundle)
reactApplicationContext.currentActivity?.setResult(Activity.RESULT_OK, intent)
}
}
shouldPopToNative = true
onBackPressed()
}
Expand Down
4 changes: 3 additions & 1 deletion example/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ function HomeScreen({ navigation, route }: Props) {
if (navigation.canGoBack()) {
navigation.goBack();
} else {
ReactNativeBrownfield.popToNative(true);
ReactNativeBrownfield.popToNative(true, {
result: `Hello World ${Math.random()}`,
});
}
}}
color={colors.secondary}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package com.callstack.kotlinexample

import android.app.Activity
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.FragmentActivity
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.compose.setContent
import androidx.activity.result.ActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
Expand All @@ -15,6 +20,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.viewinterop.AndroidView
Expand Down Expand Up @@ -76,6 +82,24 @@ fun HomeScreen(
onStartReactNativeFragment: () -> Unit,
onStartReactNativeFragmentActivity: () -> Unit
) {
val context = LocalContext.current
val launcher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult(),
onResult = { result ->
val message = if (result.resultCode == Activity.RESULT_OK) {
"Result: ${result.data?.getExtras()?.get("result")}"
} else {
"Activity cancelled or failed. ${result.resultCode}"
}
AlertDialog.Builder(context)
.setTitle("Activity Result")
.setMessage(message)
.setPositiveButton("OK") { dialog, _ ->
dialog.dismiss()
}
.show()
}
)
Column(
modifier = Modifier
.fillMaxSize()
Expand Down Expand Up @@ -106,6 +130,17 @@ fun HomeScreen(
) {
Text("Navigate to React Native Fragment Activity")
}

Button(
onClick = {
val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
setClass(context, ReactNativeFragmentActivity::class.java)
}
launcher.launch(intent)
}
) {
Text("Navigate to React Native Fragment Activity with Result")
}
}
}

Expand Down
28 changes: 26 additions & 2 deletions example/swift/App.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,47 @@ struct MyApp: App {
print("loaded")
}
}

var body: some Scene {
WindowGroup {
ContentView()
}
}
}

class NotificationHandler: ObservableObject{
init() {
NotificationCenter.default.addObserver(
self,
selector: #selector(handlePopToNative(_:)),
name: NSNotification.Name.popToNative,
object: nil
)
}

@objc func handlePopToNative(_ notification: Notification) {
if let result = notification.userInfo?["result"] as? Any {
print("Received popToNative notification with result: \(result)")
} else {
print("Received popToNative notification without result")
}
}

deinit {
NotificationCenter.default.removeObserver(self)
}
}

struct ContentView: View {
@StateObject var notificationHandler = NotificationHandler()
var body: some View {
NavigationView {
VStack {
Text("React Native Brownfield App")
.font(.title)
.bold()
.padding()

NavigationLink("Push React Native Screen") {
ReactNativeView(moduleName: "ReactNative")
.navigationBarHidden(true)
Expand Down
4 changes: 2 additions & 2 deletions ios/ReactNativeBrownfieldModule.mm
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ @implementation ReactNativeBrownfieldModule
[ReactNativeBrownfieldModuleImpl setPopGestureRecognizerEnabled:enabled];
}

RCT_EXPORT_METHOD(popToNative:(BOOL)animated) {
[ReactNativeBrownfieldModuleImpl popToNativeWithAnimated:animated];
RCT_EXPORT_METHOD(popToNative:(BOOL)animated result:(NSDictionary *)result) {
[ReactNativeBrownfieldModuleImpl popToNativeWithAnimated:animated result:result];
}

- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params {
Expand Down
7 changes: 5 additions & 2 deletions ios/ReactNativeBrownfieldModule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ public class ReactNativeBrownfieldModuleImpl: NSObject {
}
}

static public func popToNative(animated: Bool) {
let userInfo = ["animated": animated]
static public func popToNative(animated: Bool, result: [String: Any]?) {
var userInfo: [String : Any] = ["animated": animated]
if result != nil {
userInfo["result"] = result
}
DispatchQueue.main.async {
NotificationCenter.default.post(name: Notification.Name.popToNative, object: nil, userInfo: userInfo)
}
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"license": "MIT",
"author": "Michal Chudziak <[email protected]>",
"contributors": [
"Piotr Drapich <[email protected]>"
"Piotr Drapich <[email protected]>",
"Samuel Wall <[email protected]>"
],
"homepage": "https://github.com/callstack/react-native-brownfield",
"description": "Brownfield helpers for React Native",
Expand Down
8 changes: 7 additions & 1 deletion src/NativeReactNativeBrownfieldModule.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';

export type Primitive = string | number | boolean | bigint;

export type PrimitiveObject = {
[key: string]: Primitive | PrimitiveObject | Primitive[] | PrimitiveObject[];
};

export interface Spec extends TurboModule {
/**
* Navigate back to the native part of the application.
*/
popToNative(animated: boolean): void;
popToNative(animated: boolean, result?: PrimitiveObject): void;

/**
* Enable or disable the iOS swipe back gesture.
Expand Down
10 changes: 6 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { Platform } from 'react-native';
import ReactNativeBrownfieldModule from './NativeReactNativeBrownfieldModule';
import ReactNativeBrownfieldModule, {
type PrimitiveObject,
} from './NativeReactNativeBrownfieldModule';

const ReactNativeBrownfield = {
popToNative: (animated?: boolean): void => {
popToNative: (animated?: boolean, result?: PrimitiveObject): void => {
if (Platform.OS === 'ios') {
ReactNativeBrownfieldModule.popToNative(!!animated);
ReactNativeBrownfieldModule.popToNative(!!animated, result);
} else if (Platform.OS === 'android') {
ReactNativeBrownfieldModule.popToNative(false);
ReactNativeBrownfieldModule.popToNative(false, result);
} else {
console.warn('Not implemented: popToNative');
}
Expand Down
Loading