Skip to content

Latest commit

 

History

History
219 lines (173 loc) · 8.66 KB

File metadata and controls

219 lines (173 loc) · 8.66 KB

好的,我们来全面、系统地梳理一下 Flutter 混合开发方案。

Flutter 混合开发是指将 Flutter 集成到现有的原生(Android/iOS)应用程序中,或者在一个原生应用中同时使用 Flutter 和原生代码进行开发。这对于已经拥有成熟原生应用、希望逐步迁移或引入 Flutter 的团队来说,是至关重要的技术方案。


1. 为什么需要混合开发?

  1. 渐进式迁移:对于大型现有应用,一次性重写所有代码风险高、成本大。混合开发允许你“小步快跑”,先选择一两个模块用 Flutter 重写,验证效果。
  2. 复用现有能力**:应用的核心业务逻辑、第三方SDK(如支付、地图、推送)可能已经非常成熟,直接复用比用 Flutter 重新实现更稳妥。
  3. 降低入门门槛:团队可以逐步学习 Flutter,而不需要立即全面转向。
  4. 动态性(在特定平台上):通过混合栈,可以实现 Flutter 模块的动态更新(主要针对 Android,iOS 受 App Store 审核限制)。

2. 官方混合开发方案

这是目前最主流、最稳定的方案,核心是将 Flutter 作为一个模块(Module) 集成到原生项目中。

2.1 项目结构

你会拥有三个独立的项目(或目录):

  • MyNativeApp/:你的主原生 Android/iOS 项目。
  • my_flutter_module/:你的 Flutter 模块项目。
  • 最终,Flutter 模块会被编译成原生项目可以依赖的 .aar(Android)和 .framework(iOS)文件。

2.2 核心步骤

1. 创建 Flutter Module 在原生项目根目录的同级,执行:

flutter create -t module --org com.example my_flutter_module

2. 在 Android 端集成

  • 添加依赖:在原生 Android 项目的 settings.gradle 中加入 Flutter Module 的路径。
    // settings.gradle
    include ':app'
    setBinding(new Binding([gradle: this]))
    evaluate(new File(
      settingsDir.parentFile,
      'my_flutter_module/.android/include_flutter.groovy'
    ))
  • 在 app/build.gradle 中添加依赖:
    dependencies {
      implementation project(':flutter')
    }

3. 在 iOS 端集成

推荐使用 CocoaPods(如果原生项目用了 CocoaPods)。

  • 在 Podfile 中添加:
    # Podfile
    
    # 指定Flutter模块的路径
    flutter_application_path = '../my_flutter_module'
    load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
    
    target 'MyNativeApp' do
      # 安装 Flutter 引擎和你的插件
      install_all_flutter_pods(flutter_application_path)
    end
    
    # 这是一个Post-install钩子,确保Flutter.framework是静态链接的
    post_install do |installer|
      flutter_post_install(installer) if defined?(flutter_post_install)
    end
  • 然后执行 pod install。

4. 在原生端启动 Flutter 页面

  • Android:

    // 使用 FlutterActivity
    startActivity(
      FlutterActivity
        .withNewEngine()
        .initialRoute("/your_route") // 可选,传递初始路由
        .build(context)
    );
    
    // 或者使用缓存的引擎(推荐,性能更好)
    // 先在Application中初始化
    public class MyApplication extends Application {
      @Override
      public void onCreate() {
        super.onCreate();
        FlutterEngine flutterEngine = new FlutterEngine(this);
        flutterEngine.getDartExecutor().executeDartEntrypoint(DartExecutor.DartEntrypoint.createDefault());
        FlutterEngineCache.getInstance().put("my_engine_id", flutterEngine);
      }
    }
    
    // 然后启动
    startActivity(
      FlutterActivity
        .withCachedEngine("my_engine_id")
        .build(context)
    );
  • iOS(Swift):

    import Flutter
    
    let flutterEngine = (UIApplication.shared.delegate as! AppDelegate).flutterEngine
    let flutterViewController = FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)
    navigationController?.pushViewController(flutterViewController, animated: true)

    需要在 AppDelegate 中预先初始化并持有 FlutterEngine。

2.3 通信机制

混合开发的核心是 Flutter 与原生之间的通信。

  • MethodChannel:用于方法调用。Flutter 可以调用原生方法,原生也可以调用 Flutter 方法。最常用。
  • EventChannel:用于原生向 Flutter 发送事件流(Stream),如传感器数据、电池状态。
  • BasicMessageChannel:用于简单的数据传递(字符串、半结构化数据)。

示例(MethodChannel):

// Flutter 端
const channel = MethodChannel('com.example/app');
final String result = await channel.invokeMethod('getBatteryLevel');
print('Battery level is $result%.');
// Android 端
MethodChannel channel = new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), "com.example/app");
channel.setMethodCallHandler((call, result) -> {
  if (call.method.equals("getBatteryLevel")) {
    int batteryLevel = getBatteryLevel();
    result.success(batteryLevel);
  } else {
    result.notImplemented();
  }
});
// iOS 端
let channel = FlutterMethodChannel(name: "com.example/app", binaryMessenger: controller.binaryMessenger)
channel.setMethodCallHandler { (call, result) in
  if call.method == "getBatteryLevel" {
    let batteryLevel = self.getBatteryLevel()
    result(batteryLevel)
  } else {
    result(FlutterMethodNotImplemented)
  }
}

3. 第三方混合开发方案

3.1 Flutter Boost

由闲鱼团队开源,是目前最流行的混合栈解决方案。

核心思想:

  • 将整个 Flutter 环境视为一个共享的 引擎。
  • 通过一个统一的 路由管理 来管理多个 Flutter 和 Native 页面。
  • 解决了原生和 Flutter 页面混合堆叠时,页面生命周期和内存管理的复杂问题。

优势:

  • 统一路由:提供了一套统一的路由API,无论是打开 Native 还是 Flutter 页面,体验一致。
  • 页面生命周期管理:能正确管理 Flutter 页面的可见性,优化内存和性能。
  • 共享引擎:多个 Flutter 页面共享同一个引擎,大大降低了内存开销。
  • 成熟的社区和实践:被许多大厂使用,坑相对较少。

适用场景:

  • 应用中 Flutter 和 Native 页面深度混合,频繁互相跳转。
  • 对性能和内存有较高要求。

4. 方案对比与选型建议

特性/方案 官方方案 Flutter Boost
复杂度 中等,需要自己管理引擎和页面关系 较高,需要理解其路由和容器概念
性能 好,但多页面多引擎时内存开销大 优,共享引擎,内存控制更好
路由管理 需要自己实现 提供强大的统一路由管理
生命周期 需要手动处理,较为繁琐 自动管理,更接近原生体验
社区支持 官方维护,文档齐全 阿里/闲鱼维护,社区活跃,有大量实践
适用场景 1. 简单的“一个Tab是Flutter”
2. 作为功能插件嵌入
3. 混合程度不高的应用
1. 复杂的混合堆栈
2. 需要频繁在Native/Flutter间跳转
3. 大型项目,对性能要求高

5. 最佳实践与注意事项

  1. 从简单开始:如果你的场景不复杂(比如只有一个完整的 Flutter 业务模块),可以先从官方方案入手。
  2. 考虑 Flutter Boost:如果你的应用是深度混合,页面跳转复杂,强烈建议直接使用 Flutter Boost,可以避免后期重构。
  3. 引擎管理:
    • 预热引擎:在应用启动时预热 Flutter 引擎,可以显著提升第一个 Flutter 页面的打开速度。
    • 谨慎使用多引擎:除非有特殊隔离需求(如两个独立的 Flutter 游戏),否则尽量使用单引擎或共享引擎方案。
  4. 通信设计:
    • 定义好 Channel 的命名规范,避免冲突。
    • 通信的数据尽量简单,使用基础类型或可序列化的对象。
    • 处理好异步回调。
  5. 包体积:集成 Flutter 会增加约 10-20 MB 的安装包体积,需要评估是否可接受。
  6. 持续关注官方动态:Flutter 团队一直在优化混合开发的体验,例如 FlutterEngineGroup 提供了更好的多引擎性能。

总结

Flutter 混合开发是一项成熟且强大的技术,它允许团队以渐进、低风险的方式享受 Flutter 的高效开发体验。

  • 入门或简单集成:从官方 Module 方案开始。
  • 复杂混合应用:直接采用 Flutter Boost 来应对复杂的页面栈和性能挑战。

无论选择哪种方案,充分理解其原理、做好通信设计和引擎管理,是成功实施混合开发的关键。