flutter打包的app有多大_Flutter原生混合开发-程序员宅基地

技术标签: flutter文字滚动时闪烁  flutter打包的app有多大  

1010149bcdc7117309296503a49b71ac.png

使用 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 工程作为原生工程共用的子模块,维持原有的原生工程管理方式不变。这种模式,就是三端分离模式。

fed46a70dbc08794d46bf384a419c2d8.png

由于 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 打开它,其目录如下图所示。

c2ae3bea296722a590224fff07958a3d.png

可以看到,和传统的 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,如下图所示。

e44244e00f33c467e229aef7a372a8b1.png

你很快就会想到,如果是构建 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原生工程,效果如下图。

80d151a0d924a27a1e38a15a581f0504.png

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 也展示出来了,如下图所示。

c2adb555f5aedb445b967b6596b50235.png

总结

在原生工程中集成Flutter是现阶段最常见的方式。通过分离 Android、iOS 和 Flutter 三端工程,抽离 Flutter 库和引擎及工程代码为组件库,以 Android 和 iOS 平台最常见的 aar 和 pod 形式接入原生工程,从而将不同平台的构建产物依照标准组件化的形式进行管理。

如果每次通过构建 Flutter 模块工程,都是手动搬运 Flutter 编译产物,那很容易就会因为工程管理混乱导致 Flutter 组件库被覆盖,从而引发难以排查的 Bug。而要解决此类问题的话,我们可以引入 CI 自动构建框架,把 Flutter 编译产物构建自动化,原生工程通过接入不同版本的构建产物,实现更优雅的三端分离模式。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_39654352/article/details/110105489

智能推荐

系统架构师考试经验分享_中级架构师好考吗-程序员宅基地

文章浏览阅读2.8k次。目录前言考前复习考试过程考试结果证书领取前言新的一年系统架构师考试前,分享一下之前参加系统架构师考试的经验,以及考过后如何领证书。软考报名地址 中国计算机技术职业资格网 。考前复习考前由于工作原因,我个人只在考试前一周突击复习,时间允许的话,还是多匀一些时间复习,会比较有把握。架构师考试分3部分:上午的综合知识选择题考试,下午的案例分析考试及论文。复习的重点应该安排在综合知识及案例分析,论文则是在靠前根据以往的项目经验,确定好论文的内容,在考试时选择接近的论文题目即可(例如,我在以前参与过云平台的_中级架构师好考吗

多体素模式分析(MVPA)和表征相似性分析(RSA)-程序员宅基地

文章浏览阅读7.6k次,点赞17次,收藏82次。目录一、学习资源二、MVPA分析工具——pronto1.下载安装2.参考视频地址3.基本步骤(一)Data&Design(二)Prepare feature set 准备特征集(三)确定并且跑一个模型(四)看结果(五)检测哪些特征对模型的建立提供了更多的信息一、学习资源RSA学习链接1 https://www.zhihu.com/question/268530028二、MVPA分析工具——pronto1.下载安装github下载地址ht.._表征相似性分析

区域生长算法原理及MATLAB实现_区域生长原理-程序员宅基地

文章浏览阅读8.6k次,点赞3次,收藏24次。1. 基于区域生长算法的图像分割原理数字图像分割算法一般是基于灰度值的两个基本特性之一:不连续性和相似性。前一种性质的应用途径是基于图像灰度的不连续变化分割图像,比如图像的边缘。第二种性质的主要应用途径是依据实现指定的准则将图像分割为相似的区域。区域生长算法就是基于图像的第二种性质,即图像灰度值的相似性。1.1 基本公式令R表示整幅图像区域,那么分割可以看成将区域R划分为n个子区域R1..._区域生长原理

卸载出错:error reading information on service impala-catalog: No such file or directory error: %preun(i_error reading information on service bgpd:-程序员宅基地

文章浏览阅读2k次。卸载出错:error reading information on service impala-catalog: No such file or directory error: %preun(impala-catalog-2.11.0+cdh5.14.0+0-1.cdh5.14.0.p0.50.el6.x86_64) scriptlet failed, exit status 1卸载impala的依赖报错 相信大家再卸载的时候 都用用过 很多方法用了好多种方法才发现的方法好用,建议大家收藏,以后用_error reading information on service bgpd:

用python画小猪佩奇代码_用python画个小猪佩奇(turtle示例源码)-程序员宅基地

文章浏览阅读1k次。【实例简介】来副小猪佩奇,用python画个小猪佩奇【实例截图】【核心代码】# coding:utf-8import turtle as tdef nose(x,y):#鼻子t.pu()t.goto(x,y)t.pd()t.seth(-30)t.begin_fill()a=0.4for i in range(120):if 0..._python米奇代码

PhotonOS入门_photon os 教程-程序员宅基地

文章浏览阅读4.3k次。PhotonOS是VMware专为ESXi定制的容器操作系统,当前版本3.0,内核4.19,已内置Docker;ESXi直接导入ova文件即可使用;配置1. 软件包管理Photon OS使用TDNF代替yum,但与yum命令基本相同;2. 服务管理Photon OS使用systemd;3. 网络配置Photon OS网络服务为systemd-networkd;4..._photon os 教程

随便推点

深度神经网络模型压缩_深度网络模型压缩-程序员宅基地

文章浏览阅读1.7k次。“本文介绍的论文全面概述了深度神经网络的压缩方法,主要可分为参数修剪与共享、低秩分解、迁移/压缩卷积滤波器和知识精炼,本论文对每一类方法的性能、相关应用、优势和缺陷等进行独到的分析。” 大型神经网络具有大量的层级与结点,因此考虑如何减少它们所需要的内存与计算量就显得极为重要,特别是对于在线学习和增量学习等实时应用。此外,近来智能可穿戴设备的流行也为研究员提供了在资源(内存、CPU、能..._深度网络模型压缩

TortoiseGit的介绍和使用-程序员宅基地

文章浏览阅读4.4w次,点赞23次,收藏254次。  Git是什么,相信大家都很清楚。Git不就是分布式版本控制系统嘛?那你知道TortoiseGit是什么吗?下面我们就介绍一下TortoiseGit它是什么?如何使用?  TortoiseGit其实是一款开源的git的版本控制系统,也叫海龟git。TortoiseGit提供了人性化的图形化界面,不用像Git一样输入许多语句,像git init、git add、git commit这些语句就通通不用记了。轻松使用鼠标,就可以完成代码的提交和上传。对于使用本地Git的新手来说,TortoiseGit的更加简_tortoisegit

离线安装RabbitMQ,非root普通用户启动RabbitMQ_rabbitmq离线安装教程-程序员宅基地

文章浏览阅读3.6k次。离线安装RabbitMQ,非root普通用户启动RabbitMQ。_rabbitmq离线安装教程

java script实训心得_javascript实训报告总结.docx-程序员宅基地

文章浏览阅读1.1w次,点赞5次,收藏27次。javascript实训报告总结Javascript实训报告  专业名称:计算机应用技术  班级名称:  学员姓名:  指导教师:_______________  完成日期:  一、简介:  Web标准并不是一个单一的标准,而是一个系列的标准的集合。Web标准中具有代表性的几种语言有:XML可扩展标记语言、XHTML可扩展超文本标记语言、CSS层叠样式表、DOM文档对象模型、JavaScript脚..._javascript实训报告

Android O Android P 自定义开机广播_flag_receiver_include_background-程序员宅基地

文章浏览阅读4.1k次,点赞4次,收藏14次。背景一般来说,我们都是用的监听android.intent.action.BOOT_COMPLETED。但凡稍有些经验的开发者都知道,这个广播很慢,非常慢。因为它是一个有序广播,根据优先级来的,而且监听这个广播的apk又非常多。打个log感受一下,这个广播开始到结束在我司的机器上持续了30s!关键是你把优先级调高了,即便你是前几个收到android.intent.action.BO..._flag_receiver_include_background

记录文章_updatedata(true);//把界面上的数据传递给底层代码 cstring strsno, -程序员宅基地

文章浏览阅读542次。数据库操作接口比较 (ADO OLED ODBC DAO) http://blog.csdn.net/ithomer/article/details/6624684 VC操作数据库sql sever http://blog.csdn.n_updatedata(true);//把界面上的数据传递给底层代码 cstring strsno, strsname, st

推荐文章

热门文章

相关标签