How NetEase News Integrated Flutter: A Step-by-Step Hybrid Mobile Development Guide
This article details NetEase News' practical experience of gradually integrating Flutter as a module into an existing Android/iOS codebase, covering architecture, integration methods, build modes, project management, native‑Dart communication, routing strategies, debugging, encountered issues, and stability measures.
Flutter Overview
Flutter is Google’s UI toolkit that enables developers to build high‑quality iOS and Android applications from a single Dart codebase. The framework consists of a Dart‑only Framework layer on top of a C++/Java/Objective‑C Engine that handles rendering, giving Flutter strong cross‑platform consistency.
Integration Approach
Two integration patterns exist:
Create a standalone Flutter application.
Add a Flutter module to an existing native Android/iOS project.
NetEase News adopted the module pattern, embedding the Flutter module into the existing Android codebase. The official guide is available at https://github.com/flutter/flutter/wiki/Add-Flutter-to-existing-apps.
Build Configurations
Debug mode uses Just‑In‑Time (JIT) compilation. The host app adds the Flutter project with compile project(':flutter') in build.gradle, enabling rapid iteration and hot‑reload.
Release mode uses Ahead‑Of‑Time (AOT) compilation. The Dart code is compiled by gen_snapshot into binary snapshot files ( vm_snapshot_data, isolate_snapshot_data, instr). The Engine is built with Ninja, producing flutter.jar that contains libflutter.so and Java bridge classes ( FlutterMain, FlutterView, etc.). The final artifact is packaged as an .aar, minimizing impact on the existing build pipeline.
Additional requirements:
minSdkVersion must be at least 16.
Android Gradle plugin version should be 3.x or higher.
Project Management
The Flutter module is added to both Android and iOS repositories as a Git submodule, with a .gitmodules file in the host repository. This allows Dart developers to work directly on the module while native teams see it as a transparent .aar dependency.
Native ↔ Dart Communication
Flutter provides three channel types for bidirectional communication:
BasicMessageChannel – exchange strings or semi‑structured data.
MethodChannel – invoke methods on the opposite side.
EventChannel – stream continuous data.
All channels rely on BinaryMessage and the FlutterNativeView implementation. NetEase News defined a unified message protocol to standardize payloads across Android, iOS, and Dart.
Third‑party plugins can be added via pubspec.yaml, and custom plugins can be created when native functionality is not covered.
Hybrid Stack and Routing
When a FlutterView is created inside an Android Activity or Fragment, multiple Flutter pages can coexist with native pages, forming a hybrid navigation stack. Two common routing strategies are:
Multiple Flutter pages share a single Activity; navigation is handled by Flutter’s internal Navigator. Native code must replicate page‑transition animations and gestures to keep the experience consistent.
Each Flutter page is hosted in its own Activity; native code controls routing. This isolates engines but increases memory usage because each Activity creates a separate engine instance.
Debugging
Flutter’s hot‑reload accelerates development. Inside the module, run flutter attach and press R (or r) after any code change to see updates instantly.
If flutter attach hangs, terminating the app process and re‑entering the Flutter page usually resolves the issue.
Issues and Solutions
SO Library Compatibility
Flutter provides native libraries for armeabi‑v7a, arm64‑v8a, x86, and x86_64. The x86 variant works only in debug mode, and there is no armeabi binary. NetEase News retained the armeabi‑v7a binaries, filtered out devices that do not support this ABI, and copied libflutter.so from the armeabi‑v7a folder to the armeabi folder during the Gradle build.
Package Size
The Flutter engine, ICU data, and snapshot files add roughly 6 MB to the APK. An initial dynamic‑download approach was prototyped but abandoned due to reliability concerns; the team now relies on the official size‑optimisation mechanisms.
Resource Sharing
Flutter assets must be declared in pubspec.yaml. Maintaining duplicate image resources for both native and Flutter sides increased bundle size and maintenance effort. A channel‑based approach to fetch native images by name was explored, but differing naming conventions across Android and iOS made it impractical, so the solution was dropped.
Stability Assurance
Gray‑scale testing on selected distribution channels.
Feature‑flag‑driven gradual rollout.
Global error handling via FlutterError.onError and runZoned, reporting to Crashlytics through a native channel.
Flutter adoption grew from 4 % to 10 % of NetEase News users, with a crash rate below 0.01 %, meeting production standards.
Future Work
iOS integration is in progress, with ongoing adjustments and optimisations. Continued improvements in the Flutter ecosystem are expected to further enhance stability and performance.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
