马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
使用 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文件的设置如下:- use_frameworks!
- platform :ios, '8.0'
- target 'iOSDemo' do
- #todo
- 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 的模块即可,下令如下。- 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,如下所示。- import 'package:flutter/material.dart';
- import 'dart:ui';
- void main() => runApp(_widgetForRoute(window.defaultRouteName));//独立运行传入默认路由
- Widget _widgetForRoute(String route) {
- switch (route) {
- default:
- return MaterialApp(
- home: Scaffold(
- backgroundColor: const Color(0xFFD63031),//ARGB红色
- body: Center(
- child: Text(
- 'Hello from Flutter', //显示的文字
- textDirection: TextDirection.ltr,
- style: TextStyle(
- fontSize: 20.0,
- color: Colors.blue,
- ),
- ),
- ),
- ),
- );
- }
- }
复制代码 我们创建的 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 打包构建下令,如下所示。- 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 中添加对它的依赖。- ...
- repositories {
- flatDir {
- dirs 'libs' // aar目录
- }
- }
- android {
- ...
- compileOptions {
- sourceCompatibility 1.8 //Java 1.8
- targetCompatibility 1.8 //Java 1.8
- }
- ...
- }
- dependencies {
- ...
- implementation(name: 'flutter-debug', ext: 'aar')//Flutter模块aar
- ...
- }
复制代码 Sync 一下项目,Flutter 模块就被添加到了 Android 项目中。
然后,我们试着改一下 MainActivity.java 的代码,把它的 contentView 改成 Flutter 的 widget,如下所示。- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- View FlutterView = Flutter.createView(this, getLifecycle(), "defaultRoute"); //传入路由标识符
- setContentView(FlutterView);//用FlutterView替代Activity的ContentView
- }
复制代码 重新运行Android原生工程,结果如下图。
iOS 原生集成
iOS 工程接入的情况要稍微复杂一些。在 iOS 平台,原生工程对 Flutter 的依赖分别是:
- Flutter 库和引擎,即 Flutter.framework;
- Flutter 工程的产物,即 App.framework。
iOS 平台的 Flutter 模块抽取,现实上就是通过打包下令天生这两个产物,并将它们封装成一个 pod 供iOS原生工程引用。
雷同地,起首我们在 Flutter_library 的根目次下,实行 iOS 打包构建下令。- Flutter build ios --debug
复制代码 这条下令的作用是编译 Flutter 工程天生两个产物:Flutter.framework 和 App.framework。同样,把 debug 换成 release 就可以构建 release 产物(固然,你还须要处置惩罚一下署名题目)。
然后,在 iOSDemo 的根目次下创建一个名为 FlutterEngine 的目次,并把这两个 framework 文件拷贝进去。iOS 的模块化产物工作要比 Android 多一个步调,由于我们须要把这两个产物手动封装成 pod。因此,我们还须要在该目次下创建 FlutterEngine.podspec,即 Flutter 模块的组件界说。- Pod::Spec.new do |s|
- s.name = 'FlutterEngine'
- s.version = '0.1.0'
- s.summary = 'XXXXXXX'
- s.description = <<-DESC
- TODO: Add long description of the pod here.
- DESC
- s.homepage = 'https://github.com/xx/FlutterEngine'
- s.license = { :type => 'MIT', :file => 'LICENSE' }
- s.author = { 'chenhang' => '[email protected]' }
- s.source = { :git => "", :tag => "#{s.version}" }
- s.ios.deployment_target = '8.0'
- s.ios.vendored_frameworks = 'App.framework', 'Flutter.framework'
- end
复制代码 然后,实行pod lib lint 下令,Flutter 模块组件就已经做好了。接下来,我们再修改 Podfile 文件把它集成到 iOSDemo 工程中,添加如下脚本。- ...
- target 'iOSDemo' do
- pod 'FlutterEngine', :path => './'
- end
复制代码 然后,实行pod install 下令,Flutter 模块就集成进 iOS 原生工程中了。再次,我们试着修改一下 AppDelegate.m 的代码,把 window 的 rootViewController 改成 FlutterViewController,如下所示。- - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
- {
- self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
- FlutterViewController *vc = [[FlutterViewController alloc]init];
- [vc setInitialRoute:@"defaultRoute"]; //路由标识符
- self.window.rootViewController = vc;
- [self.window makeKeyAndVisible];
- return YES;
- }
复制代码 末了运行原生项目,一个写着“Hello from Flutter”的全屏赤色的 Flutter Widget 也展示出来了,如下图所示。
总结
在原生工程中集成Flutter是现阶段最常见的方式。通太过离 Android、iOS 和 Flutter 三端工程,抽离 Flutter 库和引擎及工程代码为组件库,以 Android 和 iOS 平台最常见的 aar 和 pod 情势接入原生工程,从而将差别平台的构建产物依照标准组件化的情势举行管理。
如果每次通过构建 Flutter 模块工程,都是手动搬运 Flutter 编译产物,那很轻易就会由于工程管理紊乱导致 Flutter 组件库被覆盖,从而引发难以排查的 Bug。而要办理此类题目标话,我们可以引入 CI 主动构建框架,把 Flutter 编译产物构建主动化,原生工程通过接入差别版本的构建产物,实现更优雅的三端分离模式。
|