当前位置:主页 > 移动开发 > Android代码 >

Android集成Flutter

时间:2022-05-26 08:23:32 | 栏目:Android代码 | 点击:

Android 集成Flutter

Flutter 作为 Google 开源的新一代跨平台、高性能 UI 框架,旨在帮助开发者高效地构建出跨平台的、UI 与交互体验一致的精美应用,推出后一直倍受开发者的青睐。

当需要开发一个全新的应用时,我们可以很方便地从零开始,完全使用 Flutter 进行开发。但如果是针对一个现有的应用,需要引入 Flutter 技术,显然使用 Flutter 全部重写一遍是不现实的。幸运的是,Flutter 很好地支持了以独立页面、甚至是 UI 片段的方式集成到现有的应用中,即所谓的混合开发模式。本文主要从一个 Android 开发的视角,谈谈 Android 平台下, Flutter 的混合开发与构建。

1, Hello Flutter

对于这门技术,使用过的应该绝大多数都会说好;没用过的推荐尝试一下,跑个 Demo 体验体验,有可能它就是你需要学习和掌握的最后一门新技术了。回过头来,Flutter 究竟有什么独特的魅力让它能从一众技术中脱颖而出呢?总结一下,主要有以下几点:

受益于以上的核心优势,Flutter 推出后圈了很多移动开发者的粉,各互联网大厂也纷纷将其作为一项基础技术进行研究。在 Flutter 初期,其应用场景主要是从 0 构建一个全新 App,对混合开发的支持很不友好。但作为一门跨平台的技术框架,到底还是需要依赖原生平台提供的诸多系统能力,此外还有众多现存原生 App 跃跃欲试,因此在这个需求背景下,混合开发的支持与完善至今已发展得越来越好,下面我们就用一个简单的示例开始 Android 端的 Flutter 混合开发与构建之旅。

2, 引入 Flutter 模块

要在一个已有的 Android Project 中使用 Flutter,需要引入一个 Flutter Module。在 Android Studio(需要确保 Flutter 插件已经成功安装并启用)中打开现有 Android 工程,通过使用 File > New > New Module… 菜单,我们可以新创建一个 Flutter 模块或是导入一个外部的 Flutter 模块。

这里以最简单的 Android App 项目为例,导入 Flutter 模块。在 Flutter 模块导入成功之后,原工程文件、结构都会发生一些变化,主要有:

setBinding(new Binding([gradle: this])) 
evaluate(new File( 
    settingsDir.parentFile, 
    'flutter_module/.android/include_flutter.groovy' 
)) 
include ':flutter_module' 
project(':flutter_module').projectDir = new File('../flutter_module')

在引入 Flutter 模块之前,项目中仅有 app 一个 Module;而在引入之后,可以看到除了原有的 app Module 外,Flutter Gradle 插件自动引入了额外几个子 Module。

说明如下:

3,使用Flutter

3.1 添加依赖

首先,需要在 App 模块的build.gradle脚本文件中添加对Flutter工程的依赖,只有这样 Flutter 模块才会参与到整个应用的构建中来,我们也才能够在 App 模块中调用到 Flutter 提供的 Java 层 API。

dependencies { 
  implementation project(':flutter') 
}

3.2 运行Flutter页面

3.2.1 添加Flutter页面

我们可以选择使用Activity、Fragment 或者 View 来承载 Flutter 的 UI,这里主要介绍前面两种方式,并假设flutter_module中已经通过runApp方法渲染了一个widget。

Flutter Activity

首先,我们介绍下使用 Flutter Activity的方式。使用io.flutter.embedding.android.FlutterActivity类可以很方便的启动一个 Flutter Activity,当然我们也可以继承它并扩展自己的逻辑。

FlutterActivity 
  .withNewEngine() 
  .build(context) 
  .also { 
    startActivity(it) 
  }
Flutter Fragment

另外一种就是 Flutter Fragment方式。可以使用FlutterFragmentActivity或者FlutterFragment来添加 Flutter UI 片段:a. 使用FlutterFragmentActivity可以自动创建并添加一个FlutterFragment;b. 手动创建FlutterFragment后添加到目标 Activity 中。

val flutterFragment = FlutterFragment.withNewEngine() 
      .dartEntrypoint(getDartEntrypointFunctionName()) 
      .initialRoute(getInitialRoute()) 
      .appBundlePath(getAppBundlePath()) 
      .flutterShellArgs(FlutterShellArgs.fromIntent(intent)) 
      .handleDeeplinking(shouldHandleDeeplinking()) 
      .renderMode(renderMode) 
      .transparencyMode(transparencyMode) 
      .shouldAttachEngineToActivity(shouldAttachEngineToActivity()) 
      .build<FlutterFragment>() 
fragmentManager 
      .beginTransaction() 
      .add( 
           FRAGMENT_CONTAINER_ID, 
           flutterFragment, 
           TAG_FLUTTER_FRAGMENT 
          ) 
       .commit()
 3.2.2 平台层和 Flutter 层通信

不论是开发 Plugin 还是业务逻辑,平台层与 Flutter 层通信是必不可少的,为此就需要使用到MethodChannel。平台层通过MethodChannel请求调用 Flutter 层 API 时,数据在经过打包编码后,通过 JNI、DartVM 传到 Flutter 层解码后使用;待结果计算完成后,又会重新打包编码,经过 DartVM、JNI 传回到 Native 层;同理,在 Flutter 层请求调用平台层的 API 时,数据处理是一致的,只是流转方向相反。通过这种方式,平台层与 Flutter 层就建立了一个双向的、异步的通信通道。

在下面的示例代码中,Native 层使用dev.flutter.example/counter创建一个MethodChannel,并设置 Handler 接收 Dart 的远程方法调用 incrementCounter,并调用 reportCounter 将结果回传,如下所示。

channel = MethodChannel(flutterEngine.dartExecutor, "dev.flutter.example/counter") 
channel.setMethodCallHandler { call, _ -> 
     when (call.method) { 
         "incrementCounter" -> { 
              count++ 
              channel.invokeMethod("reportCounter", count) 
         } 
     } 
}

Dart 层使用相同的名称创建 MethodChannel,并设置 Handler 处理回调结果,随后调用 incrementCounter 方法请求 counter。

final _channel = MethodChannel('dev.flutter.example/counter'); 
_channel.setMethodCallHandler(_handleMessage); 
_channel.invokeMethod('incrementCounter'); 
 
Future<dynamic> _handleMessage(MethodCall call) async { 
    if (call.method == 'reportCounter') { 
      _count = call.arguments as int; 
      notifyListeners(); 
    } 
  }

在上面的示例中,我们是通过手动创建 MethodChannel 进行通信的,这在进行简单通信的场景是没问题的,但在通信接口 API 比较复杂的情况就不是很适用了。一是繁琐,因为我们需要手写大量的打包、拆包代码;二是容易出错。

这个时候就轮到 Pigeon 大显身手了。Pigeon 是一个官方推出的代码生成工具,可以生成类型安全的双向通信 API 接口,具体可以参考官方的 例子,Pigeon官方链接。

4,Flutter APK 解析

我们已经了解了如何在现有 Android 项目中引入并使用 Flutter,接下来我们再来探究一下 Flutter APK 的结构,看看 Flutter Tools 在这个 APK 包内到底打包了哪些东西。下面两图分别为 Debub 模式和 Release 模式下构建出来的 Flutter APK 包结构,忽略了非 Flutter 相关的项。

可以看到两个模式下的 APK 结构大致相同,区别如下:

5,踩过的坑

Flutter 混合开发使得开发者可以渐进式地进行 Flutter 开发与迁移,是 Flutter 寄生于原生平台至关重要的一环,不过在接入Flutter的过程中,也出现了一些问题:

您可能感兴趣的文章:

相关文章