Android集成Flutter

目录
  • Android 集成Flutter
    • 1, Hello Flutter
    • 2, 引入 Flutter 模块
    • 3,使用Flutter
      • 3.1 添加依赖
      • 3.2 运行Flutter页面
    • 4,Flutter APK 解析
    • 5,踩过的坑

Android 集成Flutter

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

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

1, Hello Flutter

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

  • 跨平台:可以做到一套代码完美适配 Android、iOS 平台,未来还会覆盖更多平台,大大节省了开发人力与维护成本,同时拥有出色的跨端 UI 表现一致性。
  • 高效开发:SDK 提供了丰富的 UI 组件,开箱即用;声明式的 UI 构建方式,大大减少出错率;Debug 模式提供热重载能力,可实时预览代码变更,不需要重新编译安装。
  • 高性能:采用自建渲染引擎,独立于系统并可单独优化;区别于 RN、WEEX,没有中间层转换的额外开销;Release 模式下代码编译为 AOT 指令,运行高效。

受益于以上的核心优势,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 模块导入成功之后,原工程文件、结构都会发生一些变化,主要有:

  • 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 模块之前,项目中仅有 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 时生成的,记录了插件的本地文件目录、依赖信息等。

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 结构大致相同,区别如下:

  • 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 模式下是统一打包成共享库。

5,踩过的坑

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

  • 路由管理复杂:这里面包括 Flutter 层内部的页面路由管理以及 Flutter 与原生的混合栈管理。前者在 Navigator 2.0 API 中已经得到了很好的完善与支持,但后者仍面临着诸多限制与不足,需要改进。目前项目中还未涉及到后者这种很复杂的业务场景,因此对这一块的研究比较少,感兴趣的同学可以了解一下诸如 flutter_boost 此类的开源解决方案。
  • 生命周期不对应:Android 的组件一般都会有自己的生命周期,Flutter 的 Widget State 也有一套自己的生命周期,但这两者其实并不是一一对应的。比如原生的 Activity 页面虽然已经被 Finish 并 Destroy 掉了,但 Flutter 层的页面并不一定会随之而被 Dispose,尤其是在使用 Cache Flutter Engine 的时候。Flutter 页面是可以脱离原生页面而存在的,它们可以被动态地 Attach 和 Detach,Attach 时会触发重新渲染,Detach 时 UI 相关的所有操作都会 Pending 直到重新被 Attach。所以在混合开发中,业务逻辑不应该过度依赖 Widget State 的一些生命周期方法,因为它们可能会被延后执行从而导致一些奇怪的 Bug。

到此这篇关于Android 集成Flutter的文章就介绍到这了,更多相关Android内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Flutter中嵌入Android 原生TextView实例教程

    前言 本篇文章 中写到的是 flutter 调用了Android 原生的 TextView 案例 添加原生组件的流程基本上可以描述为: 1 android 端实现原生组件PlatformView提供原生view 2 android 端创建PlatformViewFactory用于生成PlatformView 3 android 端创建FlutterPlugin用于注册原生组件 4 flutter 平台嵌入 原生view 1 创建原生组件 创建在fLutter工程时会生成几个文件夹,lib是放fl

  • Android原生项目集成Flutter解决方案

    了解一下如何在 Android 原生项目中集成 Flutter 生成配置 在原生项目根目录执行命令 flutter create -t module --org {package_name} {module_name} // 此处 module_name 的命令遵循 Android 子 module 的命名即可.不能有中划线. // 比如, flutter create -t module --org com.engineer.mini.flutter flutter_sub // 此处 mod

  • Flutter 和 Android 互相传递数据的实现

    (一)Android代码设置 1,打开Android Studio 创建一个应用程序,包名dev.android.book 2, 创建一个MyApplication ,应用在AndroidManifest.xml文件中的application的android:name属性上 3,创建FlutterEngine的实例,然后把这个实例添加到缓存的FlutterEngine当中 4,创建MethodChannel的实例,指定一个此实例的唯一字符串,例如dev.android.book/add 5, 设

  • 详解Flutter 调用 Android Native 的方法

    Flutter 调用 Android Native 的方法,是通过MethodChannel的方式来实现的: 在Android端: 创建一个Class,实现FlutterPlugin和MethodCallHandler接口 重写onAttachedToEngine(),onDetachedFromEngine(),onMethodCall() onAttachedToEngine()中,根据自定义的CHANNEL_NAME创建MethodChannel, onDetachedFromEngine

  • Android Flutter自适应瀑布流案例详解

    目录 Flutter自适应瀑布流 根据效果图可以分为四步: 1.图片自适应: 2.自适应标签: 3.上拉刷新和下拉加载 4.底部的点赞按钮 Flutter自适应瀑布流 前言:在电商app经常会看到首页商品推荐的瀑布流,或者类似短视频app首页也是瀑布流,这些都是需要自适应的,才能给用户带来好的体验 (具体代码请联系我,当天会回复) 话不多说先上效果图: 根据效果图可以分为四步: 图片自适应 自适应标签 上拉刷新和下拉加载 底部的点赞按钮可以去掉或者自己修改样式,我这里使用的like_button

  • Android如何在原生App中嵌入Flutter

    本文参考文档Add Flutter to existing apps. 首先有一个可以运行的原生项目 第一步:新建Flutter module Terminal进入到项目根目录,执行flutter create -t module 'module名字'例如:flutter create -t module flutter-native 执行完毕,就会发现项目目录下生成了一个module 第二步:同步Flutter module依赖 进入到新生成的Flutter module目录下的.androi

  • Android 集成Flutter

    目录 Android 集成Flutter 1, Hello Flutter 2, 引入 Flutter 模块 3,使用Flutter 3.1 添加依赖 3.2 运行Flutter页面 3.2.1 添加Flutter页面 4,Flutter APK 解析 5,踩过的坑 Android 集成Flutter Flutter 作为 Google 开源的新一代跨平台.高性能 UI 框架,旨在帮助开发者高效地构建出跨平台的.UI 与交互体验一致的精美应用,推出后一直倍受开发者的青睐. 当需要开发一个全新的应

  • Android集成Flutter

    目录 Android 集成Flutter 1, Hello Flutter 2, 引入 Flutter 模块 3,使用Flutter 3.1 添加依赖 3.2 运行Flutter页面 4,Flutter APK 解析 5,踩过的坑 Android 集成Flutter Flutter 作为 Google 开源的新一代跨平台.高性能 UI 框架,旨在帮助开发者高效地构建出跨平台的.UI 与交互体验一致的精美应用,推出后一直倍受开发者的青睐. 当需要开发一个全新的应用时,我们可以很方便地从零开始,完全

  • Android利用Flutter path绘制粽子的示例代码

    目录 前言 绘制 基本轮廓 粽叶 嘴巴 眼睛 腮红 手&脚 头巾 咸甜是一家 发声 动画控制嘴巴开合 用到的技术点 总结 前言 大家好,端午将至,首先提前祝小伙伴端午安康,端午作为中华民族的非常重要的传统节日,粽子那是必不可少的,但是你真的知道粽子的历史吗? 今天跟随本篇文章用Flutter path画一个会科普节日的的粽子吧- 绘制 基本轮廓 首先我们需要将粽子的基本轮廓绘制出来,通过图片可以看到粽子的轮廓是一个圆圆的三角形状, 本篇文章所有的图形都是用纯Path路径制作,这里我们可以将粽子的

  • 图文详解Android Studio搭建Android集成开发环境的过程

    有很长一段时间没有更新博客了,最近实在是太忙了,没有时间去总结,现在终于可以有时间去总结一些Android上面的东西了,很久以前写过这篇关于使用Android Studio搭建Android集成开发环境,不过一直没有发表出来,写这篇文章的目的是记录一下Android开发环境的搭建过程,这篇文章写得一般般,主要是记录了整个搭建过程,没什么技术含量,觉得有帮助的朋友就看一下! 一.Android Studio简单介绍 2013年GoogleI/O大会首次发布了Android Studio IDE(A

  • Android集成新浪微博第三方登录的方法

    本文实例讲述了Android集成新浪微博第三方登录的方法.分享给大家供大家参考.具体实现方法如下: 1.下载微博的sdk ,导入微博的jar包两个 android-support-v4.jar和weibosdkcore.jar两个包 2.把新浪微博中的demo_src中SDK中的com,导入到项目中 3.用demo中的constants,主要是参数设置,将里面的参数改成自己的参数. 4.编写代码,主要步骤如下: 复制代码 代码如下: // 初始化微博对象 mWeiboAuth = new Wei

  • Android集成腾讯X5实现文档浏览功能

    Android内部没有控件来直接显示文档,跳转WPS或其他第三方文档App体验性不好,使用腾讯X5内核能很好的解决的这一问题. 一.下载腾讯X5内核 1.前往https://x5.tencent.com/下载Android的内核,新版本的腾讯X5可以直接在bulid.gradle集成 api 'com.tencent.tbs.tbssdk:sdk:43697',如果是在App里集成可以把api换成implementation 2.AndroidStudio导入腾讯X5 a.把下载好的jar包导入

  • 超简单Android集成华为HMS Scankit 扫码SDK实现扫一扫二维码

    前言 最近要做一个停车场扫码收费的app,在网上搜了一圈,首先接触到了ZXing,上手试了下,集成过程不复杂,但是感觉效果欠佳,比如距离稍微远点儿就扫不出来了,另外角度对的不好,反光或者光线比较暗的时候,成功率也比较低,集成好给我们老大看了下,感觉不是很满意.最近偶尔看到了华为一个发布会里面有介绍扫码功能,稍微研究了下,居然是一款免费扫码神器,官方称之为Scan Kit,号称还同时支持Android和iOS,半信半疑上手搞了一把发现效果还真不错!测了下发现对于一些有反光,污损,形变,超远距离的场

  • Android集成zxing扫码框架功能

    我们知道zxing是一个强大的处理二维码和条形码等的开源库,本篇文章记录一下自己在项目中集成zxing开源库的过程. 导入依赖 implementation 'com.google.zxing:core:3.3.3' 申请权限 在AndroidManifest中申请相应权限: <!--相机--> <uses-permission android:name="android.permission.CAMERA" /> <!--震动--> <use

  • Android 集成 google 登录并获取性别等隐私信息的实现代码

    前言 公司做海外产品的,集成的是 google 账号登录,账号信息.邮箱等这些不涉及隐私的按 google 的正常登录流程可以轻松实现 .但是一旦需要获取涉及隐私的信息就比较麻烦,文档也不是十分清晰,非常难找,很多坑. google 账号登录 官方链接:https://developers.google.com/identity/sign-in/android/start https://developers.google.com/identity/sign-in/android/sign-in

随机推荐