189 8069 5689

如何进行混合开发Flutter

如何进行混合开发Flutter,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。

公司主营业务:网站设计制作、网站设计、移动网站开发等业务。帮助企业客户真正实现互联网宣传,提高企业的竞争能力。成都创新互联是一支青春激扬、勤奋敬业、活力青春激扬、勤奋敬业、活力澎湃、和谐高效的团队。公司秉承以“开放、自由、严谨、自律”为核心的企业文化,感谢他们对我们的高要求,感谢他们从不同领域给我们带来的挑战,让我们激情的团队有机会用头脑与智慧不断的给客户带来惊喜。成都创新互联推出清徐免费做网站回馈大家。

引言

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

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

Hello Flutter

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

  • 跨平台:可以做到一套代码完美适配 Android、iOS 平台,未来还会覆盖更多平台,大大节省了开发人力与维护成本,同时拥有出色的跨端 UI 表现一致性。

  • 高效开发:SDK 提供了丰富的 UI 组件,开箱即用;声明式的 UI 构建方式,大大减少出错率;Debug 模式提供热重载能力,可实时预览代码变更,不需要重新编译安装。

  • 高性能:采用自建渲染引擎,独立于系统并可单独优化;区别于 RN、WEEX,没有中间层转换的额外开销;Release 模式下代码编译为 AOT 指令,运行高效。

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

引入 Flutter 模块

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

如何进行混合开发Flutter

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

  • settings.gradle 文件新增了以下内容。其实就是执行对应 Flutter 模块下 .android/include_flutter.groovy 脚本文件,该步骤会引入一个名为 Flutter 的 Android Library Module,同时还会引入 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

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

  • flutter_module:指代要引入的目标 Flutter Module,不会 apply Android 相关的任何插件,主要是包含 Flutter 相关源码、资源、依赖等。

  • flutter:为 Flutter Gradle 插件引入的 Android Library Module;主要负责编译 flutter_module 及其依赖的第三方 Package、Plugin 的 Dart 代码,以及打包 Flutter 资源等。

  • device_info:为 Flutter Gradle 插件自动引入的 Flutter Android Plugin Library Module,这是因为一开始我在 flutter_module 的 pubspec.yaml 文件中添加了对 device_info 这个插件的依赖。Flutter Gradle 工具会将 flutter_module 依赖到的所有插件其 Android 平台侧的代码、资源作为一个 Library Module 引入到项目中一起参与构建。如果要查看 flutter_module 引入了哪些 Plugin,可以查看其对应目录下的 .flutter-plugins 与 .flutter-plugins-dependencies 文件,这两个文件是执行 flutter pub get 时生成的,记录了插件的本地文件目录、依赖信息等。

注意:一个工程不能包含多个 Flutter Module,最多只能引入一个,这是由 Flutter 的 Gradle 插件决定的。

使用 Flutter

完成 Flutter 模块的引入后,我们再来看看如何使用 Flutter。

添加依赖

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

dependencies {
  implementation project(':flutter')
}

运行 Flutter 页面

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

  • 运行 Flutter Activity。使用io.flutter.embedding.android.FlutterActivity类可以很方便的启动一个 Flutter Activity,当然我们也可以继承它并扩展自己的逻辑。示例代码如下:

FlutterActivity 
  .withNewEngine() 
  .build(context) 
  .also { startActivity(it) }
  • 运行 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() 
fragmentManager 
      .beginTransaction() 
      .add( 
           FRAGMENT_CONTAINER_ID, 
           flutterFragment, 
           TAG_FLUTTER_FRAGMENT 
          ) 
       .commit()
  • 平台层和 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 _handleMessage(MethodCall call) async { 
    if (call.method == 'reportCounter') { 
      _count = call.arguments as int; 
      notifyListeners(); 
    } 
  }

这里我们是通过手动创建 MethodChannel 进行通信的,这在进行简单通信的场景是没问题的,但在通信接口 API 比较复杂的情况就不是很适用了。

一是繁琐,因为我们需要手写大量的打包、拆包代码;二是容易出错。这个时候就轮到 Pigeon 大显身手了。Pigeon 是一个官方推出的代码生成工具,可以生成类型安全的双向通信 API 接口,具体可以参考官方的 Example,这里不再赘述。

Pigeon :https://flutter.dev/docs/development/platform-integration/platform-channels#pigeon

Flutter APK 解析

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

如何进行混合开发Flutter

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

  • lib/{arch}/libflutter.so:为对应架构的 Flutter Engine 共享库,负责 Flutter 渲染、JNI 通信、DartVM。如果不需要对应架构的版本,通过 abiFilters 可以 Exclude 掉。

  • lib/{arch}/libapp.so:只存在于 Release 模式下,共享库中包含 Dart AOT 生成的二进制指令和数据。在运行时,Flutter Engine 通过 Dynamic Load 的方式,从共享库中读取对应的可执行机器指令以及数据。

  • assets/flutter_assets:Flutter 引用到的相关资源

    • fonts:包含字体库。

  • FontManifest.json:引用到的字体库清单文件,json 格式,所有使用到的字体、以及字体文件在 flutter_assets 下的路径。

  • AssetManifest.json:其他资源清单文件,json 格式,为所有资源名称到资源路径的映射,Flutter 在加载某一项资源时,会通过这个配置清单找到对应路径的资源进行读取后加载。

  • kernel_blob.bin、isolate_snapshot_data、vm_snapshot_data:只存在于 Debug 模式下,分别为 DartVM 字节码与数据,其作用类似于 libapp.so,只是存在形式、打包方式不同。在 Debug 模式下,Flutter Tools 将指令和数据分别打包,主要是为了热重载(HotReload)服务的,而在 Release 模式下是统一打包成共享库。

看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注创新互联行业资讯频道,感谢您对创新互联的支持。


网页标题:如何进行混合开发Flutter
标题网址:http://cdxtjz.cn/article/jiesis.html

其他资讯