Skip to content

Commit db99985

Browse files
committed
docs: add brownfield guidelines
1 parent 15123c2 commit db99985

File tree

2 files changed

+135
-2
lines changed

2 files changed

+135
-2
lines changed

docs/GUIDELINES.md

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
Here you can find the guidelines for standard brownfield approach and advanced use cases.
2+
3+
### Standard Brownfield
4+
5+
As a golden rule of standard brownfield with react-native, your native App should never have to interact directly
6+
with react-native APIs. There are various reasons that doing the opposite is discouraged.
7+
8+
- If you have different teams working on RN brownfield and the native App and you distribute your AAR/XCFramework to the native
9+
team. They can use the APIs from those artifacts and interact with them. However, if the native team have to import a react native
10+
API, say `PackageList` then the rule of brownfield is being violated. The native team have native developers and they should not need
11+
to worry about and interact with react-native directly. All of the abstraction should be handled within your artifacts.
12+
13+
- If your native App interacts with react-native directly then you could imagine how complicated the codebase would be. The native App
14+
should follow and worry about their native APIs rather than interacting with react-native. If in future, some react-native APIs needs to
15+
be changed or refactored, then the effort would be cumbersome. On the contrast, if your native App was interacting with your artifact only
16+
then the native App need not to worry about what happens internally. This makes things simpler for the native App team.
17+
18+
- If the native App team is using your artifact and any build, compile time or run time issue arises the stack trace would lead to your artifact
19+
and making it simpler for the teams to focus on their area only. On the contrary, if the native App team would interact with react-native directly,
20+
then any related issues would be time consuming for that team to figure out the root cause and then delegate to the team managing RN flows.
21+
22+
Building upon the above points, below is how your brownfield implementation should look like if you're using `react-native-brownfield`:
23+
24+
- In your brownfield android library or iOS xcframework, create a class following the facade pattern. The role of this class would be to encapsulate the
25+
initialization of `react-native-brownfield` by not asking the native App to interact with `react-native` directly. Below is how it would look like:
26+
27+
```kt
28+
// Your artifact
29+
import com.facebook.react.PackageList
30+
import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative
31+
32+
class ReactNativeHostManager {
33+
companion object {
34+
fun initialize(application: Application) {
35+
loadReactNative(application) // imported from autogenerated ReactNativeApplicationEntryPoint
36+
val packages = PackageList(application).packages // imported from autogenerated PackageList
37+
38+
ReactNativeBrownfield.initialize(application, packages)
39+
}
40+
}
41+
}
42+
```
43+
44+
Then the native App only needs to call `initialize` like so:
45+
46+
```kt
47+
// native App
48+
ReactNativeHostManager.initialize(application)
49+
```
50+
51+
If you do not follow this approach, then the usage in the native App would look like this:
52+
53+
```kt
54+
// native App
55+
import com.facebook.react.PackageList
56+
import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative
57+
58+
59+
loadReactNative(application)
60+
val packages = PackageList(this).getPackages()
61+
ReactNativeHostManager.initialize(application)
62+
```
63+
64+
As you can see the issue here is that now we are mixing the native App with react-native APIs, which is discouraged. If we stick to
65+
the above approach then the native App is free of interacting with react-native directly.
66+
67+
68+
### Advanced Use Cases:
69+
70+
If you built on top of the above approach, then you can rather easily scale it to incorporate advanced use cases. We will discuss here only one
71+
case but you can extend it to your need as the gist remains the same.
72+
73+
Consider you need to present a few native App's existing screens from react-native. Which means you need a communication way so that you can tell
74+
the native App to present this screen. Let's see how we can achieve this:
75+
76+
In your `ReactNativeHostManager` add the following method:
77+
78+
```kt
79+
// Your artifact
80+
class ReactNativeHostManager {
81+
companion object {
82+
fun createView(
83+
context: Context,
84+
activity: FragmentActivity?,
85+
moduleName: String,
86+
launchOptions: Bundle? = null,
87+
eventHandler: (String) -> Unit = {}
88+
): FrameLayout {
89+
EventHandlerRegistry.register(moduleName, eventHandler) // Later invoke this event or callback to perform the navigation
90+
return ReactNativeBrownfield.shared.createView(context, activity, moduleName, launchOptions)
91+
}
92+
}
93+
}
94+
```
95+
96+
What happens here is that the `createView` method now accepts an optional callback or eventHandler argument. The native App will rely on this eventHandler
97+
to perform the navigation or to receive any events from the react-native side. The usage in the native App would look like below:
98+
99+
```kt
100+
// native App
101+
ReactNativeHostManager.createView(context, activity, "Enterprise") {
102+
if (it == "navigate_to_faq") {
103+
// present faq fragment
104+
}
105+
}
106+
```
107+
108+
HINT: To achieve this you will need to write some native code in your artifact to trigger an event from JS and then forward that event by invoking the eventHandler. You can wire up a native module and expose it to JS. Now, when you need to present FAQ screen from the native App, you invoke that native module method which forwards the event to eventHandler. The gist is below:
109+
110+
```JS
111+
// Your artifact
112+
113+
// handlerId is the name of RN module loaded, eg: Enterprise
114+
RNEventHandler.sendEvent("navigate_to_faq", handlerId);
115+
```
116+
117+
```kt
118+
// Your artifact
119+
120+
// RNEventHandler
121+
fun sendEvent(event: String, handlerId: String) {
122+
EventHandlerRegistry.sendEvent(handlerId, event)
123+
}
124+
```
125+
126+
```kt
127+
// Your artifact
128+
129+
// EventHandlerRegistry
130+
fun sendEvent(event: String, handlerId: String) {
131+
eventHandlers[handlerId].invoke(event)
132+
}
133+
```

docs/KOTLIN.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ Below is the code you need to add before you call `RNBrownfield.initialize`:
1313
```kt
1414
import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative
1515

16-
loadReactNative(application);
17-
RNBrownfield.initialize(application, packages);
16+
loadReactNative(application)
17+
RNBrownfield.initialize(application, packages)
1818
```
1919

2020
### API Reference

0 commit comments

Comments
 (0)