Flutter和iOS混编详解

更新日期: 2022-05-08阅读: 927标签: Flutter

前言

下面的内容是最近在使用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 调用的方法名称<br> self.flutterMethodChannel!.invokeMethod(MixChannelMethod.goodsId, arguments: stringParams)<br>}

注意点: 在使用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)
来自:https://www.cnblogs.com/zhangxiaoxu/p/16243225.html


链接: https://fly63.com/article/detial/11473

移动跨平台框架Flutter介绍和学习线路

Flutter是一款移动应用程序SDK,一份代码可以同时生成iOS和Android两个高性能、高保真的应用程序。Flutter目标是使开发人员能够交付在不同平台上都感觉自然流畅的高性能应用程序。我们兼容滚动行为、排版、图标等方面的差异。

初识flutter

关注flutter已经好久,因为没有发正式版,所以一直也不想过早的躺浑水,但是最近无意中看到几篇文章,再加上美团和咸鱼等app也一直在做灰度测试,所以上周开始看了一下官方文档,地址:https://flutter.io/docs/get-started/install,然后在此做一下总结。

深入理解Flutter多线程

Flutter默认是单线程任务处理的,如果不开启新的线程,任务默认在主线程中处理。和iOS应用很像,在Dart的线程中也存在事件循环和消息队列的概念,但在Dart中线程叫做isolate。

Flutter1.5 开始,将成为全平台 UI 框架!

Flutter 1.5 的发布,同期也宣布发布 Flutter for Web 的 Preview 版本,正式开启了 Flutter 的全平台 UI 框架之路。早在年初发布的 Flutter 2019 Roadmap 中,就有提到,会在今年支持移动设备之外的平台,对 Web 的支持,算是完成了一个新的里程碑吧。

Flutter支持Web开发了!

Flutter作为一个可移植的UI框架,已经支持现代Web应用开发了!我们很开心已经发布了SDK预览版,这样你可以在Web浏览器里直接运行你的Flutter UI代码。

Flutter 混合开发 (交互通信)

Flutter 与原生之间的通信依赖灵活的消息传递方式:1,Flutter 部分通过平台通道将消息发送到其应用程序的所在的宿主环境(原生应用)。2,宿主环境通过监听平台通道,接收消息。

Flutter 局部路由实现

Flutter是借鉴React的开发思想实现的,在子组件的插槽上,React有this.props.children,Vue有<slot></slot>。当然Flutter也有类似的Widget,那就是Navigator,不过是以router的形式实现(像<router-view></router-view>)。

Flutter Kotlin 到底该如何选择?

这两个技术在当下如何选择,我之前在公众号上的回复是:如果你已经处于一个比较满意的公司,并考虑长期发展,公司并未使用这两个技术,你可以专心钻研公司当下使用的,或者未来将要使用的,这些才能助你在公司步步高升。

Flutter 与 iOS 原生 WebView 对比

本文对比的是 UIWebView、WKWebView、flutter_webview_plugin(在 iOS 中使用的是 WKWebView)的加载速度,内存使用情况。测试网页打开的速度,只需要获取 WebView 在开始加载网页和网页加载完成时的时间戳

Flutter For Web

用来构建漂亮、定制化应用的跨平台的 UI 框架 Flutter 现在已经支持 Web 开发了。我们很高兴推出了一个预览版的 SDK 可以让开发者直接使用 Flutter UI 和业务逻辑代码构建 web 应用

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!