前言


下面的内容是最近在使用Flutter和我们自己项目进行混编时候的一些总结以及自己踩的一些坑,处理完了就顺便把整个过程以及一些我们可能需要注意的点全都梳理出来,希望对有需要的小伙伴有点帮助,也方便自己后续的查看。

一:混编具体步骤以及需要注意的问题


1:创建Flutter项目  (切记:下面任何命令执行出错基本上都是Flutter环境有问题,多执行 Flutter doctor 检查)

这里需要我们留意的就一点, 创建的Flutter项目的文件层级和你想混编的原生项目要同级,就像下面这样:

终端命令行如下: flutter_module:你自己的项目名称,自己定义。-t 和 --template 一样,别纠结。

flutter create -t module flutter_module

还是前面开头说的,有问题多执行 flutter dotcor检查,要是没有问题,正确创建成功之后是下面的情况:(我临时在桌面创建的,请忽略位置)

2:通过pod将Flutter模块导入项目

我们在我们项目的podfile文件中加入下面两句:

flutter_application_path = '../flutter_mixed'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')

注意: flutter_application_path 后面的是你自己Flutter项目的名称。flutter_application_path为Flutter模块相对于podfile文件的位置。

在target种加入下面这句

install_all_flutter_pods(flutter_application_path)

我这里刚好有一份写demo时候的podfile文件,代码全都给出来,方便也想demo尝试的小伙伴直接复制,节省时间。

platform :ios, '14.0'
source 'https://cdn.cocoapods.org/' use_frameworks!
#use_modular_headers! # 忽略引入库的所有警告
inhibit_all_warnings! # [!] Could not automatically select an Xcode project. Specify one in your Podfile like so:
# project 'path/to/Project.xcodeproj' # [!] `xcodeproj` was renamed to `project`. Please update your Podfile accordingly. xcodeproj 'flutter_mixed_ios.xcodeproj' flutter_application_path = '../flutter_mixed'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb') target 'flutter_mixed_ios' do install_all_flutter_pods(flutter_application_path) ####
pod 'AFNetworking'
pod 'WoodPeckeriOS' end

3:接下来就是 pod install

4:关于原生项目的配置更改以及问题解释

<1> Flutter混编项目是不支持Bitcode的,具体Bitcode代表的是什么,这个大家可以翻以前我的文章:

<2> Build Phases 添加 Script 具体的操作如下所示:

添加下面内容:

"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" build
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" embed

注意:单纯这样添加之后编译大概率是不通过的,主要问题就是集中的 FLUTTER_ROOT 这个点上

/packages/flutter_tools/bin/xcode_backend.sh: No such file or directory

我们就把注意力放在 No such file or directory 上,别走别的岔路。解决上面这问题的方法就是在你的项目中指定一下FLUTTER_ROOT的具体路径,让不再No such file or directory就OK了

具体的做法是在 Build Settings中找到 User-Defined 添加 FLUTTER_ROOT 和 FLUTTER_APPLICATION_PATH

FLUTTER_ROOT是我Flutter环境所在的具体位置 FLUTTER_APPLICATION_PATH 是我这个Flutter项目所在的路径,当然我们还有更靠谱的查找这两路径位方法。

终端进入自己flutter项目,按照下面路径/.ios(隐藏文件)/Flutter/Generated.xcconfig  我们open Generated.xcconfig 文件就,在最上面就可以看到我们需要的FLUTTER_ROOT 和 FLUTTER_APPLICATION_PATH 。

经过上面的处理,我们的 No such file or directory的问题就解决了,最后我们说说 xcode_backend.sh ,其实关于它我想表达的就只有一点,就这个脚本的作用到底有哪些,他能帮我们完成什么工作呢?

前面的疑问,这篇文文章给出了具体的分析 #Flutter之ios脚本 xcode-backend.sh文件分析#,文章逐句分析了我们xcode_backend.sh脚本的代码,也就间接的阐述了它的作用。有兴趣的朋友可以好好了解一下。

经过脚本的处理,有这样一种场景,我们在开发的时候假如修改了一些涉及到混编消息传递的内容(任何Flutter内容都可以),我们在Flutter这边修改了代码,这时候你可以直接运行Xcode查看更改的内容是否正确,里面具体的工作我们在运行Xcode它在执行xcode_backend.sh脚本的时候已经帮我们处理了。当然正常Flutter修改的内容我们运行Flutter项目查看,在原生传递消息给Flutter的时候需要我们运行iOS项目,就打个上面的比方,理解知道就可以了。

至此,你的iOS和Flutter混编的代码是可以正常运行起来的了。

5:Local Network Privacy Permissions

这个问题我们在查看Flutter官方文档进行学习的时候肯定是可以看到的。  官方解释传送门

在你运行混编iOS项目的时候,你不处理这个问题就可以看到下面内容的日志:

Failed to register observatory port with mDNS with error -65555. On iOS 14+, local network broadcast in apps need to be declared in the app's Info.plist. Debug and profile Flutter apps and modules host VM services on the local network to support debugging features such as hot reload and DevTools. To make your Flutter app or module attachable and debuggable, add a '_dartobservatory._tcp' value to the 'NSBonjourServices' key in your Info.plist for the Debug/Profile configurations.

官方也给我们做出了提醒以及解释说明:

【 在iOS 14和更高版本,在你的应用程序的调试版本中启用Dart组播DNS服务,以添加调试功能,如热加载和DevTools via flutter attach。注意:该服务不能在你的应用的Release版本中启用,否则你可能会遇到应用商店拒绝。一种方法是维护应用程序信息的一个单独副本。每个构建配置的Plist。下面的说明假设默认的Debug和Release。根据应用程序的构建配置,根据需要调整名称 】

我自己还是按照官方给的的处理方法处理的

首先还是处理我们的plist文件,把它处理成debug和release两个模式的,我们一旦改了它们。在 build settings 中一定要改动,不然编译肯定过不了的!具体的操作如下图:

    

Build Settings Info.plist 这里我们添加的是 Info-$(CONFIGURATION).plist Debug和Release环境的让它们根据自己的配置内容读取。

接下来就是再Debug环境中的配置问题,这里主要有两点:

1、Privacy - Local Network Usage Description 填写的 Allow Flutter tools on your computer to connect and debug your application.This prompt will not appear on release builds. ,当然我是写demo随便写的,具体的在自己项目中需要自己填写,这个权限在iOS14之后审核比较严格,大家需要注意,要使用到得描述清楚,避免审核被拒绝,但具体的苹果什么加强这块的审核,我们大致了解下这个权限的用处就理解了。

【 因为在过去的 iOS 版本中,应用可以随意扫描本地网络中的设备,因此应用就可以很轻松地得到本地网络里所有设备的名称和MAC地址。MAC地址是一种确认网络设备位置的地址,每个网卡都有一个唯一的MAC地址,加上MAC地址也具有唯一性,设备厂商会按照一定的规律分配MAC,所以不同的局域网都是独一无二可以识别的。这样就通过MAC地址和设备的名字以生成一个特定的「指纹」,持续地、跨应用地、跨设备地跟踪用户的行为,并对用户画像持续进行调整。就大部分应用而言,它们都不需要给本地网络权限。因为它们没有功能会使用到本地网络,请求这个权限的主要目的就是为了跟踪用户并推送广告。】

2、Bonjour services  填写的  _dartobservatory._tcp

最后还剩一点就是把Copy Bundle当中的Info-Release.plist进行一个删除。下面图片中的内容我是已经删除了的:

       经过上面的处理之后,Local Network Privacy Permissions 这个问题我们就应该是解决了!

二:原生与Flutter通信


首先Flutter为我们提供了以下几种原生和Flutter之间通信的方式:

  • FlutterBasicMessageChannel 双向通道,iOS和Flutter都可以主动向对方传递消息,最简单的传递数据方式。
  • FlutterMethodChannel 也是双向通信,它的使用和FlutterBasicMessageChannel基本上一致,不同的点在于FlutterMethodChannel可以自定义Channel的name。
  • FlutterEventChannel 用于事件流的发送(event streams), 属于持续性的单向通信, 只能是iOS端主动调用, 常用于传递原生设备的信息, 状态等, 比如电池电量, 远程通知, 网络状态变化, 手机方向, 重力感应, 定位位置变化等等。

具体的它们三者的使用我们就不在很具体的说了,我们就从FlutterMethodChannel这个方法入手,简单的看一下Flutter给iOS发送消息以及iOS给Flutter发送消息时候具体的代码执行是什么样子的,具体的过程当中我们又遇到了那些问题,我们也简要的进行一个分析。

1、Flutter给iOS发送消息

iOS端的代码,下面代码大致逻辑是iOS端接收到Flutter发送的channel name为MixChannelName.backToNative,消息名称为 MixChannelMethod.iOSBack,执行返回上个控制器。

/// MixFlutterViewController 继承与 FlutterViewController
extension MixFlutterViewController{ /// 返回事件
func channelBack() {
/// MixChannelName.backToNative 字符串channel name
self.flutterMethodChannel = MixFlutterMethodChannel.init(name: MixChannelName.backToNative, binaryMessenger: self.engine!.binaryMessenger)
self.flutterMethodChannel!.setMethodCallHandler { [weak self] (call:FlutterMethodCall,result:@escaping FlutterResult) in
/// 返回上一个页面
/// MixChannelMethod.iOSBack 字符串返回方法名称
if call.method == MixChannelMethod.iOSBack{ self?.navigationController?.popViewController(animated: true)
self?.flutterMethodChannel = nil
} else { result(FlutterMethodNotImplemented)
}
}
}
} class MixFlutterMethodChannel: FlutterMethodChannel { deinit {
debugPrint("MixFlutterMethodChannel - deinit")
}
}

我们再看看Flutter端的发送代码是怎么处理的:

///  前面定义一个MethodChannel 名称为flutter_backToNative 和iOS端的需要保持一致
static const _messageChannel = MethodChannel("flutter_backToNative"); /// 然后在你需要发送消息的地方调用
_messageChannel.invokeMethod("backToNative");

经过上面的处理之后,我们的iOS端是能够正接受到Flutter发送的消息的。

2、iOS给Flutter发送消息

Flutter端的代码,还是之前的_messageChannel这个渠道,直接调用setMethodCallHandler设置接收到消息的处理函数。

/// 建立和原生通讯的渠道
_messageChannel.setMethodCallHandler((call) => handleMessage(call.arguments)); /// 处理消息的方法
Future handleMessage(String message) async { print(message);
}

iOS端的代码如下,flutterMethodChannel还是我们刚开始创建的渠道

/// 发送普通消息
/// - Parameter stringParams: stringParams description
func sendMessageWithString(_ stringParams:String){
/// MixChannelMethod.goodsId 调用的方法名称
self.flutterMethodChannel!.invokeMethod(MixChannelMethod.goodsId, arguments: stringParams)
}

注意点: 在使用FlutterMethodChannel进行双向通信的时候,尤其需要注意的是iOS端和Flutter端的渠道Channel的name一定要保持一致!

疑惑点:我在MixFlutterViewController的deinit方法中加入了日志,然后综合上面的MixFlutterMethodChannel中deinit的日志,得出一个有点不理解的点,主要疑问如下面所示是在flutterMethodChannel的创建方式上。

         /*
"MixFlutterMethodChannel - deinit"
2022-05-08 22:28:26.159278+0800 flutter_mixed_ios[70375:6110936] flutter: 10086
"MixFlutterViewController - deinit"
"MixFlutterMethodChannel - deinit"
2022-05-08 22:28:35.960283+0800 flutter_mixed_ios[70375:6110936] flutter: 10086
"MixFlutterMethodChannel - deinit"
"MixFlutterViewController - deinit"
"MixFlutterMethodChannel - deinit"
*/
/// 使用该方法创建后 在Flutter发送消息返回 打印日志如上面注释
self.flutterMethodChannel = MixFlutterMethodChannel.init(name: MixChannelName.backToNative, binaryMessenger: self.engine!.binaryMessenger,codec: FlutterStandardMethodCodec.sharedInstance()) /*
2022-05-08 22:31:21.842965+0800 flutter_mixed_ios[70389:6112382] flutter: 10086
"MixFlutterViewController - deinit"
*/
/// 使用该方法创建后 在Flutter发送消息返回 打印日志如上面注释
self.flutterMethodChannel = MixFlutterMethodChannel.init(name: MixChannelName.backToNative, binaryMessenger: self.engine!.binaryMessenger)

总结:经过上面的内容,关于iOS和Flutter的混编的一些东西就都介绍完毕了,疑问点还是存在,等后面找到具体的答案之后我会补充在文章后面。要是对上面内容有什么疑问,可以留言或者私信我,可以换个方式具体的沟通。

Flutter和iOS混编详解的更多相关文章

  1. 转载]IOS LBS功能详解[0](获取经纬度)[1](获取当前地理位置文本 )

    原文地址:IOS LBS功能详解[0](获取经纬度)[1](获取当前地理位置文本作者:佐佐木小次郎 因为最近项目上要用有关LBS的功能.于是我便做一下预研. 一般说来LBS功能一般分为两块:一块是地理 ...

  2. iOS中-Qutarz2D详解及使用

    在iOS中Qutarz2D 详解及使用 (一)初识 介绍 Quartz 2D是二维绘图引擎. 能完成的工作有: 绘制图形 : 线条\三角形\矩形\圆\弧等 绘制文字 绘制\生成图片(图像) 读取\生成 ...

  3. iOS 2D绘图详解(Quartz 2D)之路径(点,直线,虚线,曲线,圆弧,椭圆,矩形)

    前言:一个路径可以包含由一个或者多个shape以及子路径subpath,quartz提供了很多方便的shape可以直接调用.例如:point,line,Arc(圆弧),Curves(曲线),Ellip ...

  4. iOS开发——Block详解

    iOS开发--Block详解 1. Block是什么 代码块 匿名函数 闭包--能够读取其他函数内部变量的函数 函数变量 实现基于指针和函数指针 实现回调的机制 Block是一个非常有特色的语法,它可 ...

  5. iOS开发:详解Objective-C runTime

    Objective-C总Runtime的那点事儿(一)消息机制 最近在找工作,Objective-C中的Runtime是经常被问到的一个问题,几乎是面试大公司必问的一个问题.当然还有一些其他问题也几乎 ...

  6. iOS应用开发详解

    <iOS应用开发详解> 基本信息 作者: 郭宏志    出版社:电子工业出版社 ISBN:9787121207075 上架时间:2013-6-28 出版日期:2013 年7月 开本:16开 ...

  7. 了解iOS消息推送一文就够:史上最全iOS Push技术详解

    本文作者:陈裕发, 腾讯系统测试工程师,由腾讯WeTest整理发表. 1.引言 开发iOS系统中的Push推送,通常有以下3种情况: 1)在线Push:比如QQ.微信等IM界面处于前台时,聊天消息和指 ...

  8. iOS开发者证书-详解

    iOS开发者证书-详解/生成/使用 本文假设你已经有一些基本的Xcode开发经验, 并注册了iOS开发者账号. 相关基础 加密算法 现代密码学中, 主要有两种加密算法: 对称密钥加密 和 公开密钥加密 ...

  9. iOS开发-Runtime详解

    iOS开发-Runtime详解 简介 Runtime 又叫运行时,是一套底层的 C 语言 API,其为 iOS 内部的核心之一,我们平时编写的 OC 代码,底层都是基于它来实现的.比如: [recei ...

随机推荐

  1. Spring 由哪些模块组成?

    以下是 Spring 框架的基本模块:第 393 页 共 485 页 Core module Bean module Context module Expression Language module ...

  2. Clickhouse 用户自定义外部函数

    写在前面 Clickhouse 从 21.11 版本开始,除了提供类似SqlServer.MySQL CREATE FUNCTION 的自定义函数之外,还有一个用户自定义函数(UDF),与其说是&qu ...

  3. C++“拷贝构造函数”和“等号重载”有什么区别?

    CTypeA(const CTypeB& b)CTypeA& operator=(const CTypeB& b)一直没弄懂这两个有什么区别.只知道,重载了=号,下面复制的时候 ...

  4. 单页应用SPA开发最佳实践

    最近用vue+vue-router做了个单页应用的项目,页面大概有15个左右.积累了一些开发经验在此做一些记录.本文主要从可维护性方面来考虑SPA的开发实践 全站的颜色定义放在一个less或者scss ...

  5. task0002(四)- 练习:数据处理、轮播及交互

    转载自我的个人博客 欢迎大家批评指正 包括5部分: 小练习1-处理用户输入 小练习2-日期对象的使用 小练习3:轮播图 小练习4:输入提示框 小练习5:界面拖拽交互 源码地址task0002 在线De ...

  6. 如何使用Flannel搭建跨主机互联的容器网络

    当您将多台服务器节点组成一个Docker集群时,需要对集群网络进行设置,否则默认情况下,无法跨主机容器互联,接下来我们首先分析一下原因. 跨主机容器互联 下图描述了一个简单的集群网络,在该集群内,有两 ...

  7. [computer vision] Bag of Visual Word (BOW)

    Bag of Visual Word (BoW, BoF, 词袋) 简介 BoW 是传统的计算机视觉方法,用一些特征(一些向量)来表示一个图像.BoW的核心思想是利用一组较为通用的特征,将图像用这些特 ...

  8. Unknown host mirrors.opencas.cn You may need to adjust the proxy settings in Gradle 报错及解决办法

    亲测Unknown host mirrors.opencas.cn You may need to adjust the proxy settings in Gradle 解决办法 - 程序员大本营 ...

  9. number(10,6)正则表达式

    /**     * 判断number(10,6)     * @param dateStr     * @return     */    public boolean isNumJW(String ...

  10. Python使用递归绘制谢尔宾斯基三角形

    谢尔宾斯基三角形使用了三路递归算法,从一个大三角形开始,通过连接每一个边的中点,将大三角型分为四个三角形,然后忽略中间的三角形,依次对其余三个三角形执行上述操作. 运行效果: 源代码: 1 impor ...