Mobile Development 17 min read

Integrating Flutter into an Existing Native App: Challenges, Solutions, and the Use of Flutter Boost and Fish‑Redux

This article details the process of embedding Flutter into a mature native Android/iOS application, covering architectural background, thread models, the drawbacks of the default multi‑engine approach, the adoption of Flutter Boost, code‑level integration steps, network and resource sharing techniques, and the subsequent migration to the Fish‑Redux framework for better modularity and maintainability.

58 Tech
58 Tech
58 Tech
Integrating Flutter into an Existing Native App: Challenges, Solutions, and the Use of Flutter Boost and Fish‑Redux

The article introduces the motivation for mixing Flutter with an existing native apartment‑PMS app, explaining that a full rewrite would be costly and that hybrid development allows reuse of native resources while gaining Flutter’s cross‑platform UI benefits.

It then describes the Flutter engine architecture—Framework, Engine, and Embedder—and the thread model involving Platform, UI, GPU, and IO task runners, emphasizing the need for stable thread configuration.

The official multi‑engine mixing scheme is presented, followed by a discussion of its disadvantages such as linear memory growth, redundant resources, complex page communication, and plugin registration issues, leading the team to reject this approach.

Flutter Boost’s shared‑engine solution is introduced, with diagrams (omitted) showing how all Flutter pages share a single FlutterView, reducing memory usage and simplifying resource management.

Implementation steps:

Dart side: Add Flutter Boost to pubspec.yaml and run flutter packages get .

flutter_boost:
    git:
      url: 'https://github.com/alibaba/flutter_boost.git'
      ref: '0.0.410'

Android native side: Include the Flutter project in settings.gradle and add dependencies in build.gradle .

setBinding(new Binding([gradle: this, mainModuleName: 'ApartmentClient']))
evaluate(new File(settingsDir.parentFile, 'flutter_apartment/.android/include_flutter.groovy'))
implementation project(':flutter')
implementation project(':flutter_boost')

Define a custom URL scheme for page navigation, e.g., wbapartment://jump/house/flutter?params={"container_name":"personalCenter","show_guide":true} , and handle it in native code:

private void initFlutterBoost() {
    FlutterBoostPlugin.init(new IPlatform() {
        @Override
        public boolean startActivity(Context context, String url, int requestCode) {
            return PageTransferManager.jump(context, url);
        }
    });
}

Network header sharing is achieved via a MethodChannel on the native side and a corresponding call on the Dart side to retrieve headers for Dio requests.

// Native side
new MethodChannel(getBoostFlutterView(), METHOD_CHANNEL).setMethodCallHandler(new MethodChannel.MethodCallHandler() {
    @Override
    public void onMethodCall(MethodCall call, MethodChannel.Result result) {
        if (call.method.equals("getHeader")) {
            Map
headerMap = CommonHeaderUtils.getInstance(...).generateParamMap(...);
            result.success(JsonUtils.hashMapToJson(headerMap));
        } else {
            result.notImplemented();
        }
    }
});
// Dart side
Map
headers;
final String headerString = await platform.invokeMethod('getHeader');
headers = jsonDecode(headerString);
Response response = await dio.get(dataUrl, options: Options(headers: headers));

Image sharing between native and Dart is performed with a BasicMessageChannel that transfers drawable bytes.

// Native side
BasicMessageChannel
messageChannel = new BasicMessageChannel<>(getFlutterView(), "getPic", StandardMessageCodec.INSTANCE);
messageChannel.setMessageHandler((o, reply) -> reply.reply(drawableToByte(getResources().getDrawable(getResId(o.toString())))));
// Dart side
const _messageChannel = BasicMessageChannel
('getPic', StandardMessageCodec());
Future
getNativeImage(String name) async {
  return await _messageChannel.send(name);
}

Because the project grew in complexity, the team adopted Fish‑Redux, a Redux‑based Flutter framework, to modularize pages into Page → Adapter → Component layers, separating state, effects, and UI. Sample code shows a page definition, adapter registration, and component implementation.

class PersonalCenterPage extends Page
> {
  PersonalCenterPage() : super(
    initState: initState,
    effect: buildEffect(),
    view: buildView,
    dependencies: Dependencies
(
      adapter: NoneConn
() + PersonalCenterListAdapter()
    )
  );
}
class PersonalCenterListAdapter extends DynamicFlowAdapter
{
  PersonalCenterListAdapter() : super(
    pool: {
      NORMAL_ITEM: NormalItemComponent(),
      USER_INFO_ITEM: UserItemComponent(),
      LOGOUT_ITEM: LogoutItemComponent(),
      TODO_ITEM: TodoItemComponent(),
      CONTACT_ITEM: ContactItemComponent(),
    },
    connector: _HouseListConnector(),
    reducer: buildReducer()
  );
}

The article concludes that using Flutter Boost solved the engine‑sharing problem, while Fish‑Redux provided a clean, component‑based architecture that improved code maintainability, facilitated reuse of native resources, and streamlined communication between native and Dart layers.

DartFluttermobilehybrid-developmentfish-reduxNative Integrationflutter boost
58 Tech
Written by

58 Tech

Official tech channel of 58, a platform for tech innovation, sharing, and communication.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.