引入 Flutter 实战开发入门

本文目标

  1. 将 Flutter 引入到日常的开发;
  2. 熟悉引入 Flutter 开发后由开发到交付产品的流程;

一个简单的流程图,来表示一下引入 Flutter 后的开发流程:


三个 channel

通常情况下,在现有工程中接入 Flutter 是大部分开发者的选择,即混编。这既兼顾到了大部分开发者以 Native 开发的现状,又能尝一下螃蟹的味道。基于此,我们来看一下一个比较重要的概念 channel。

在混编过程中避免不了原生与 Flutter 侧的数据传递和方法相互调用,Flutter 提供了三个 channel 专门去解决这个比较重要的问题。

这三个 channel 分别是 MessageChannel,MethodChannel,EventChannel,下面分别看一下。

以 Flutter 与 iOS 混编为例,以源码形式集成 Flutter Module ,执行 pod install 之后会自动生成以下三个 channel 类。

FlutterBasicMessageChannel

作用:用于 Native 与 Flutter 传递数据。下面是该类提供的三个比较重要的方法。

// Native 向 Flutter 侧传递数据
- (void)sendMessage:(id _Nullable)message;
 
// Native 向 Flutter 侧传递数据,并接收 Flutter 侧的回调
- (void)sendMessage:(id _Nullable)message reply:(FlutterReply _Nullable)callback;
 
// 注册一个回调,用于接收 Flutter 侧返回的回调 
- (void)setMessageHandler:(FlutterMessageHandler _Nullable)handler;

FlutterMethodChannel

作用:用于 Native 与 Flutter 之间方法的相互调用。下页是该类提供的三个比较重要的方法。

// Native 调用 Flutter 侧的方法,并传参
- (void)invokeMethod:(NSString*)method arguments:(id _Nullable)arguments;
 
// Native 调用 Flutter 侧的方法,并传参,接收 Flutter 侧返回的回调
- (void)invokeMethod:(NSString*)method
           arguments:(id _Nullable)arguments
              result:(FlutterResult _Nullable)callback;
 
// 监听 Flutter 侧的方法回调并做相应处理
- (void)setMethodCallHandler:(FlutterMethodCallHandler _Nullable)handler;

FlutterEventChannel

作用:Native 向 Flutter 侧发送通知。下面是该类发送通知的核心方法。

// Native 向 Flutter 侧发送通知,Flutter 侧接收到通知后可以执行相应的操作
- (void)setStreamHandler:(NSObject<FlutterStreamHandler>* _Nullable)handler;

Flutter 与 Android 混编,以源码形式集成 Flutter Module 时,在 build 之后也会生成对应的三个 channel,含义和用法与上面是一样的,就不再列出介绍了。

看完上面三个 channel,是不是感觉这个交互方式有点熟悉。是不是跟 Native 接入 Hybrid 后两者之间的交互方式是类似的的,区别在于 Native 无法向 Hybrid 直接发送通知。你细品!

三种开发模式

三种开发模式是本篇的重点,但这里也不做具体详细的介绍,只介绍其中的关键衔接之处。

Android 与 Flutter 混编

将 Flutter 集成到现有 Android 工程可能参考官方文档,这里主要介绍一下 Android 与 Flutter 衔接的点。

在以 Flutter Module 源码集成后,会生成一个 FlutterView 的类,用于 Android 调起 Flutter 侧的视图。实例化 FlutterView 的一个对象并添加到 Android 端的壳 activity 中,即可以实现 Android 加载 Flutter 侧视图的功能。关键代码如下

FlutterView flutterView = new FlutterView(this);
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
FrameLayout flContainer = findViewById(R.id.layout001);
flContainer.addView(flutterView, lp);

Native 与 Flutter 之间的数据传递,方法调用,通知则以方法相互调用为例说明。

MethodChannel nativeChannel = new MethodChannel(flutterEngine.getDartExecutor(), 'channel_native');
nativeChannel.setMethodCallHandler(new MethodChannel.MethodCallHandler() {
    @Override
    public void onMethodCall(MethodCall call, MethodChannel.Result result) {
      switch (call.method){
            case "openSecondNative":
                // 这里执行具体的操作...
                result.success("成功打开第二个原生页面");
                break;
            case "backFirstNative":
                // 这里执行具体的操作...
                result.success("成功返回第一个原生页面");
                break;
            case "backAction":
                // 这里执行具体的操作...
                result.success("成功通过虚拟按键返回第一个原生页面");
                break;
            default :
                result.notImplemented();
                break;
 
        }
  }
});

iOS 与 Flutter 混编

将 Flutter 集成到现有 iOS 工程可能参考官方文档,这里也主要介绍一下 Android 与 Flutter 衔接的点。

在以 Flutter Module 源码集成后,会生成一个 FlutterViewController 的类,用于 iOS 调起 Flutter 侧的视图。实例化 FlutterViewController 的一个对象并 push 或 present 该对象,即可以实现 iOS 加载 Flutter 侧视图的功能。关键代码如下

let flutterVC = FlutterViewController()
flutterVC.fd_prefersNavigationBarHidden = true
flutterVC.setInitialRoute(paramsJsonStr)
let messageChannel = FlutterMethodChannel(name: "channel_native", binaryMessenger: flutterVC.binaryMessenger)
messageChannel.setMethodCallHandler { [weak self] call, result in
    if call.method == "backToMineViewController" {
        self?.navigationController?.popViewController(animated: true)
        if let tmpArguments = call.arguments as? [AnyHashable: Any] {
            let message = tmpArguments["message"] as? String
            LoadingManager.showText(message)
        }
     } else if call.method == "didSelectCell" {
        if let tmpArguments = call.arguments as? [AnyHashable: Any] {
            self?.handleJump(with: tmpArguments)
        }
    }
}
flutterVC.hidesBottomBarWhenPushed = true
navigationController?.pushViewController(flutterMessageCenterVC, animated: true)

Native 与 Flutter 之间的数据传递,方法调用,通知也以他们之间的方法相互调用为例说明。看上方代码。

纯 Flutter 开发

对于一个全新的 App 来说,选择纯 Flutter 方式开发或许是一个不错的选择。
一是不用去踩混编的坑,二是越纯粹越简单,包袱也少;
开发完成之后,分别构建各端上的包即可。
一处开发,到处运行,简直不能太爱了!

构建 ipa 或 apk 包

构建包首先要注意的是需要支持哪些架构类型,这关系到你的包发行的广度的问题。下面分别看一下 android 和 iOS 支持的架构类型。

Android 支持的架构

架构类型 简介
arm64-v8a 第8代,64位,包含AArch32、AArch64两个执行状态对应32、64bit
armeabi 第5代 ARM v5TE,使用软件浮点运算,兼容所有ARM设备,通用性强,速度慢
armeabi-v7a 第7代 ARM v7,使用硬件浮点运算,具有高级扩展功能(从2010年起)
x86 intel 32位,一般用于平板(从2011年起)
x86_64 intel 64位,一般用于平板(从2014年起)
mips 比较少见(目前市面几乎没有采用这种架构的手机)
mips64 比较少见(目前市面几乎没有采用这种架构的手机)

设置支持特定架构的包,可以在主工程 app 文件夹下的 build.gradle 添加下面的代码

defaultConfig {
    ndk {
        abiFilters "armeabi-v7a", "x86", "armeabi"
    }
}

iOS 支持的架构

架构类型 简介
armv7s iPhone5、iPhone5C、iPad4(iPad with Retina Display)
armv7 iPhone4、iPhone4S、iPad、iPad2、iPad3(The New iPad)、iPad mini、iPod Touch
armv6 iPhone, iPhone2, iPhone3G, 第一代、第二代 iPod Touch(一般不需要去支持)
arm64e iphone XS、iphone XS Max、iphoneXR、iphone11、iphone11 Pro
arm64 iPhone 5S、iPhone 6、iPhone 6 Plus、iPhone 6S、6S Plus、iPhone 7、7 Plus、iPad (2018)、iPhone 8、iPhone 8 Plus、and iPhone X
x86_64 Mac指令集:x86_64是针对x86架构的64位处理器
i386 Mac指令集:i386是针对intel通用微处理器32位处理器

可以在 Xcode 中如下图所示的位置设置支持的架构类型


安装

Android apk 包安装

adb install xxx.apk

iOS ipa 包安装

Enterprise 企业包,tf 包

最后

也许一开始引入 Flutter 会面临各种各样的问题。
比如学习成本,新技术的不完备性等风险,但后期带来的收益也是很可观的。
业务是在不断变化的,对高效率的追求却是不变的!Flutter 也许会是一个相对不错的选择!

推荐学习实践:

Flutter、Android混合开发实践:
https://juejin.cn/post/6844904065881604109

Flutter、iOS混合开发实践:
https://juejin.cn/post/6844904087918477320

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • 16宿命:用概率思维提高你的胜算 以前的我是风险厌恶者,不喜欢去冒险,但是人生放弃了冒险,也就放弃了无数的可能。 ...
    yichen大刀阅读 6,030评论 0 4
  • 公元:2019年11月28日19时42分农历:二零一九年 十一月 初三日 戌时干支:己亥乙亥己巳甲戌当月节气:立冬...
    石放阅读 6,870评论 0 2