Embedding Flutter Views in React Native and Native Applications: Architecture, Implementation, and Lessons Learned
This article explores the practical integration of Flutter views within React Native and native mobile pages, detailing architectural choices, lifecycle management, event handling, and code implementations to enable seamless cross‑stack UI composition in a large‑scale travel app.
The rapid evolution of multi‑platform technologies has blurred the boundaries between mobile and front‑end development, prompting Ctrip's hotel team to investigate embedding Flutter views inside both React Native (RN) and native containers.
Background : Hotel list and detail pages have migrated to Flutter, but new business scenarios require reusing the same Flutter UI across RN and native screens, demanding a flexible embedding solution.
RN Integration : Directly overlaying a Flutter view on the RN layer proved problematic due to offset calculations, lifecycle synchronization, and event propagation. Instead, the team wrapped the Flutter view as an RN component using a custom RNTListManager that extends RCTViewManager , exposing lifecycle methods and commands to RN.
Key RN native component registration code: /// iOS RCT_EXPORT_MODULE(FlutterListView) - (UIView *)view { if (self.viewPlugin == nil) { self.viewPlugin = [[GlobalSearchEmbedderPlugin alloc] init]; [self.viewPlugin createView]; } return self.viewPlugin.exportView; }
On Android, a SimpleViewManager creates a RNLinearLayout that hosts the Flutter fragment, with command handling for initializing the fragment and passing parameters.
/// Android class RNTListManager : SimpleViewManager () { override fun getName() = "FlutterListView" override fun createViewInstance(reactContext: ThemedReactContext) = LayoutInflater.from(reactContext).inflate(R.layout.flutter_container, null) as RNLinearLayout override fun getCommandsMap() = mapOf("setDestinationParam" to 1) override fun receiveCommand(root: RNLinearLayout, commandId: String?, args: ReadableArray?) { if (commandId?.toInt() == 1) initFlutterFragment(root.context, args) } }
Native Integration : The same embedding principle applies; a native view hierarchy directly adds the Flutter view as a child. Lifecycle is managed by attaching the Flutter view controller to the current visible view controller.
Example native view attachment: // iOS UIViewController *rootVC = (UIViewController *)[self currentVisibleViewController]; [rootVC addChildViewController:flutterViewControler];
Event handling ensures click and scroll events propagate correctly between Flutter and its parent containers, with special handling for nested scrolling scenarios.
Lifecycle coordination relies on FlutterBoost, treating Flutter pages like WebViews managed by native containers, allowing consistent start‑up, rendering, and disposal across RN and native hosts.
Conclusion : The prototype demonstrates a viable path for mixing Flutter, RN, and native UI components, offering reusable UI blocks while highlighting challenges such as smooth nested scrolling and increased integration complexity that must be addressed in future iterations.
Ctrip Technology
Official Ctrip Technology account, sharing and discussing growth.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.