flutter 专题 八十八 Flutter原生肴杂开辟

[复制链接]
发表于 2025-10-15 02:42:29 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
使用 Flutter 重新开始写一个 App是一件轻松舒服的变乱。但是对于成熟产物来说,完全摒弃原有 App 的汗青沉淀,全面转向 Flutter 并不现实。用 Flutter 去同一 iOS/Android 技能栈,把它作为已有原生 App 的扩展,然后通过渐渐试验有序推进从而提升终端开辟服从,大概才是现阶段 Flutter 最有用的集成方式。
那么,Flutter 工程与原生工程该怎样构造管理?差别平台的 Flutter 工程打包构建产物该怎样抽取封装?封装后的产物该怎样引入原生工程?原生工程又该怎样使用封装后的 Flutter 本领?
这些题目使得在已有原生 App 中接入 Flutter 看似并不是一件轻易的变乱。那接下来,我就和你先容下如安在原生 App 中以最自然的方式接入 Flutter。
预备工作

既然要在原生应用中混编 Flutter,信赖你肯定已经预备好了原生应用工程。如果你还没有预备好也没关系,我会以一个最小化的示例和你演示这个改造过程。
起首,我们分别用 Xcode 与 Android Studio 快速创建一个只有首页的根本工程,工程名分别为 iOSDemo 与 AndroidDemo。
到此,Android 工程就已经预备好了;而对于 iOS 工程来说,由于根本工程并不支持以组件化的方式管理项目,因此我们还须要多做一步,将其改造成使用 CocoaPods 管理的工程,也就是要在 iOSDemo 根目次下创建一个只有根本信息的 Podfile 文件。Podfile文件的设置如下:
  1. use_frameworks!
  2. platform :ios, '8.0'
  3. target 'iOSDemo' do
  4. #todo
  5. end
复制代码
然后,在下令行输入 pod install 下令后,会主动天生一个 iOSDemo.xcworkspace 文件,该文件存放的就是我们项目须要的依赖库,这时我们就完成了 iOS 工程改造。
混编方案

如果你想要在已有的原生 App 里嵌入一些 Flutter 页面,有两个办法可以实现,即同一管理模式和三端分离模式。

  • 将原生工程作为 Flutter 工程的子工程,由 Flutter 同一管理。这种模式,就是同一管理模式。
  • 将 Flutter 工程作为原生工程共用的子模块,维持原有的原生工程管理方式稳固。这种模式,就是三端分离模式。

由于 Flutter 早期提供的混编方式本领及相干资料有限,国内较早使用 Flutter 肴杂开辟的团队大多使用的是同一管理模式。但是,随着功能迭代的深入,这种方案的弊端也随之体现,不但三端(Android、iOS、Flutter)代码耦合严肃,相干工具链耗时也随之大幅增长,导致开辟服从低落。
以是,后续使用 Flutter 肴杂开辟的团队连续按照三端代码分离的模式来举行依赖管理,实现了 Flutter 工程的轻量级接入。
除此之外,三端代码分离模式还可以把 Flutter 模块作为原生工程的子模块,从而快速实现 Flutter 功能的“热插拔”,低落原生工程改造的本钱。而 Flutter 工程通过 Android Studio 举行管理,无需打开原生工程,可直接举行 Dart 代码和原生代码的开辟调试。
三端工程分离模式的关键是抽离 Flutter 工程,将差别平台的构建产物依照标准组件化的情势举行管理,即 Android 使用 aar、iOS 使用 pod。换句话说,接下来先容的混编方案会将 Flutter 模块打包成 aar 和 pod,如许原生工程就可以像引用其他第三方原生组件库那样快速接入 Flutter 了。
集成Flutter预备

当我们创建一个新的Flutter 工程时,除了一些通用设置外,Flutter还包罗 Flutter 工程和原生工程的目次(即 iOS 和 Android 两个目次)。在这种情况下,原生工程就会依赖于 Flutter 相干的库和资源,从而无法脱离父目次举行独立构建和运行。
原生工程对 Flutter 的依赖紧张分为两部门:

  • Flutter 库和引擎,也就是 Flutter 的 Framework 库和引擎库;
  • Flutter 工程,也就是我们自己实现的 Flutter 模块功能,紧张包罗 Flutter 工程 lib 目次下的 Dart 代码实现的这部门功能。
在已经有原生工程的情况下,我们须要在同级目次创建 Flutter 模块,构建 iOS 和 Android 各自的 Flutter 依赖库。这也很好实现,Flutter 就为我们提供了如许的下令。我们只须要在原生项目标同级目次下,实行 Flutter 下令创建名为 flutter_library 的模块即可,下令如下。
  1. Flutter create -t module flutter_library
复制代码
这里的 Flutter 模块,也是 Flutter 工程,我们用 Android Studio 打开它,其目次如下图所示。

可以看到,和传统的 Flutter 工程相比,Flutter 模块工程也有内嵌的 Android 工程与 iOS 工程,因此我们可以像平凡工程一样使用 Android Studio 举行开辟调试。
细致查察可以发现,Flutter 模块有一个渺小的厘革:Android 工程下多了一个 Flutter 目次,这个目次下的 build.gradle 设置就是我们构建 aar 的打包设置。这就是模块工程既能像 Flutter 传统工程一样使用 Android Studio 开辟调试,又能打包构建 aar 与 pod 的秘密。
现实上,iOS 工程的目次结构也有渺小厘革,但这个差别并不影响打包构建,因此此处就不再睁开了。
然后,我们打开 main.dart 文件,将其逻辑更新为以下代码逻辑,即一个写着“Hello from Flutter”的全屏赤色的 Flutter Widget,如下所示。
  1. import 'package:flutter/material.dart';
  2. import 'dart:ui';
  3. void main() => runApp(_widgetForRoute(window.defaultRouteName));//独立运行传入默认路由
  4. Widget _widgetForRoute(String route) {
  5.   switch (route) {
  6.     default:
  7.       return MaterialApp(
  8.         home: Scaffold(
  9.           backgroundColor: const Color(0xFFD63031),//ARGB红色
  10.           body: Center(
  11.             child: Text(
  12.               'Hello from Flutter', //显示的文字
  13.               textDirection: TextDirection.ltr,
  14.               style: TextStyle(
  15.                 fontSize: 20.0,
  16.                 color: Colors.blue,
  17.               ),
  18.             ),
  19.           ),
  20.         ),
  21.       );
  22.   }
  23. }
复制代码
我们创建的 Widget 现实上是包在一个 switch-case 语句中的。这是由于封装的 Flutter 模块一样寻常会有多个页面级 Widget,原生 App 代码则会通过传入路由标识字符串,告诉 Flutter 毕竟应该返回何种 Widget。为了简化案例,在这里我们忽略标识字符串,同一返回一个 MaterialApp。
接下来,我们要做的变乱就是把这段代码编译打包,构建出对应的 Android 和 iOS 依赖库,实现原生工程的接入。
现在,我们起首来看看 Android 工程怎样接入。
Android原生集成

之前我们提到原生工程对 Flutter 的依赖紧张分为两部门,对应到 Android 平台,这两部门分别是:

  • Flutter 库和引擎,也就是 icudtl.dat、libFlutter.so,另有一些 class 文件。这些文件都封装在 Flutter.jar 中。
  • Flutter 工程产物,紧张包罗应用步伐数据段 isolate_snapshot_data、应用步伐指令段 isolate_snapshot_instr、捏造机数据段 vm_snapshot_data、捏造机指令段 vm_snapshot_instr和资源文件 Flutter_assets等内容。
搞清楚 Flutter 工程的 Android 编译产物之后,我们须要对 Android 的 Flutter 依赖举行抽取,步调如下。
起首,在 Flutter_library 的根目次下,实行 aar 打包构建下令,如下所示。
  1. Flutter build apk --debug
复制代码
这条下令的作用是编译工程产物,并将 Flutter.jar 和工程产物编译结果封装成一个 aar,如下图所示。

你很快就会想到,如果是构建 release 产物,只须要把 debug 换成 release 就可以了。
打包构建的 flutter-debug.aar 位于.android/Flutter/build/outputs/aar/ 目次下,我们把它拷贝到原生 Android 工程 AndroidDemo 的 app/libs 目次下,并在 App 的打包设置 build.gradle 中添加对它的依赖。
  1. ...
  2. repositories {
  3.     flatDir {
  4.         dirs 'libs'   // aar目录
  5.     }
  6. }
  7. android {
  8.     ...
  9.     compileOptions {
  10.         sourceCompatibility 1.8 //Java 1.8
  11.         targetCompatibility 1.8 //Java 1.8
  12.     }
  13.     ...
  14. }
  15. dependencies {
  16.     ...
  17.     implementation(name: 'flutter-debug', ext: 'aar')//Flutter模块aar
  18.     ...
  19. }
复制代码
Sync 一下项目,Flutter 模块就被添加到了 Android 项目中。
然后,我们试着改一下 MainActivity.java 的代码,把它的 contentView 改成 Flutter 的 widget,如下所示。
  1. protected void onCreate(Bundle savedInstanceState) {
  2.     super.onCreate(savedInstanceState);
  3.     View FlutterView = Flutter.createView(this, getLifecycle(), "defaultRoute"); //传入路由标识符
  4.     setContentView(FlutterView);//用FlutterView替代Activity的ContentView
  5. }
复制代码
重新运行Android原生工程,结果如下图。

iOS 原生集成

iOS 工程接入的情况要稍微复杂一些。在 iOS 平台,原生工程对 Flutter 的依赖分别是:

  • Flutter 库和引擎,即 Flutter.framework;
  • Flutter 工程的产物,即 App.framework。
iOS 平台的 Flutter 模块抽取,现实上就是通过打包下令天生这两个产物,并将它们封装成一个 pod 供iOS原生工程引用。
雷同地,起首我们在 Flutter_library 的根目次下,实行 iOS 打包构建下令。
  1. Flutter build ios --debug
复制代码
这条下令的作用是编译 Flutter 工程天生两个产物:Flutter.framework 和 App.framework。同样,把 debug 换成 release 就可以构建 release 产物(固然,你还须要处置惩罚一下署名题目)。
然后,在 iOSDemo 的根目次下创建一个名为 FlutterEngine 的目次,并把这两个 framework 文件拷贝进去。iOS 的模块化产物工作要比 Android 多一个步调,由于我们须要把这两个产物手动封装成 pod。因此,我们还须要在该目次下创建 FlutterEngine.podspec,即 Flutter 模块的组件界说。
  1. Pod::Spec.new do |s|
  2.   s.name             = 'FlutterEngine'
  3.   s.version          = '0.1.0'
  4.   s.summary          = 'XXXXXXX'
  5.   s.description      = <<-DESC
  6. TODO: Add long description of the pod here.
  7.                        DESC
  8.   s.homepage         = 'https://github.com/xx/FlutterEngine'
  9.   s.license          = { :type => 'MIT', :file => 'LICENSE' }
  10.   s.author           = { 'chenhang' => '[email protected]' }
  11.   s.source       = { :git => "", :tag => "#{s.version}" }
  12.   s.ios.deployment_target = '8.0'
  13.   s.ios.vendored_frameworks = 'App.framework', 'Flutter.framework'
  14. end
复制代码
然后,实行pod lib lint 下令,Flutter 模块组件就已经做好了。接下来,我们再修改 Podfile 文件把它集成到 iOSDemo 工程中,添加如下脚本。
  1. ...
  2. target 'iOSDemo' do
  3.     pod 'FlutterEngine', :path => './'
  4. end
复制代码
然后,实行pod install 下令,Flutter 模块就集成进 iOS 原生工程中了。再次,我们试着修改一下 AppDelegate.m 的代码,把 window 的 rootViewController 改成 FlutterViewController,如下所示。
  1. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
  2. {
  3.     self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  4.     FlutterViewController *vc = [[FlutterViewController alloc]init];
  5.     [vc setInitialRoute:@"defaultRoute"]; //路由标识符
  6.     self.window.rootViewController = vc;
  7.     [self.window makeKeyAndVisible];
  8.     return YES;
  9. }
复制代码
末了运行原生项目,一个写着“Hello from Flutter”的全屏赤色的 Flutter Widget 也展示出来了,如下图所示。

总结

在原生工程中集成Flutter是现阶段最常见的方式。通太过离 Android、iOS 和 Flutter 三端工程,抽离 Flutter 库和引擎及工程代码为组件库,以 Android 和 iOS 平台最常见的 aar 和 pod 情势接入原生工程,从而将差别平台的构建产物依照标准组件化的情势举行管理。
如果每次通过构建 Flutter 模块工程,都是手动搬运 Flutter 编译产物,那很轻易就会由于工程管理紊乱导致 Flutter 组件库被覆盖,从而引发难以排查的 Bug。而要办理此类题目标话,我们可以引入 CI 主动构建框架,把 Flutter 编译产物构建主动化,原生工程通过接入差别版本的构建产物,实现更优雅的三端分离模式。
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表