- Swift版本:5.0
- Xcode版本:13.2.1
- Flutter版本:3.3.9
- 设备:Mac mini(M1 2020)
- MacOS版本:12.2.1
环境安装时提示 zsh: command not found: flutter
我是直接把 .zshrc 和 .bash_profile 文件都创建在了/User目录下。.zshrc文件的内容复制的是.bash_profile内容
[[ -s "$HOME/.profile" ]] && source "$HOME/.profile" # Load the default .profile [[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm" # Load RVM into > a shell session *as a function* export LC_ALL=en_US.UTF-8 export LANG=en_US.UTF-8 export PATH=/Users/xxx/Desktop/flutter/bin:$PATH export PUB_HOSTED_URL=https://pub.flutter-io.cn export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn唯一区别是在 .zshrc 文件的底部还加了 'source ~/.bash_profile',保存直接重启终端就可以直接使用flutter相关命令了,而不用每次都要 cd 和 source ~/.bash_profile
集成Flutter我采用的是CocoaPods的方式,毕竟原生项目本身就有所以快速方便。
- 首先创建一个Flutter module用来实现Flutter的内容
cd路径自定义
然后终端执行: flutter create --template module xxx(项目名称自定义)
随后会在相关目录下生成一个flutter项目文件
- 在Podfile中添加相关集成信息
source 'https://github.com/CocoaPods/Specs.git' platform :ios, '11.0' inhibit_all_warnings! use_frameworks! #此处根据自己Flutter项目实际路径填写 flutter_application_path = 'xxx' #此句不可缺少 load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb') target 'FrogHunter' do install_all_flutter_pods(flutter_application_path) pod 'SnapKit' end post_install do |installer| flutter_post_install(installer) if defined?(flutter_post_install) end关于 platform 一开始设置的是10.0,单pod isntall后一直给我报版本过低的错误,所以就试了试11.0结果就成功了
flutter_application_path : 生成的flutter module 路径
随后执行pod install 提示成功就OK了
- 添加相关代码
在 AppDelegate 中添加相关头文件
import Flutter import FlutterPluginRegistrant创建 FlutterEngine
lazy var flutterEngine = FlutterEngine(name: "my flutter engine")在didFinishLaunchingWithOptions方法中添加相关代码
flutterEngine.run() GeneratedPluginRegistrant.register(with: self.flutterEngine)
- 传值
添加 import Flutter 后就能得到一个FlutterViewController 相当于相当于 Flutter 端的一个 ViewController
但 FlutterViewController 的初始化需要传入一个 FlutterEngine,可以使用在 AppDelegate 创建的 FlutterEngine
let flutterEngine = (UIApplication.shared.delegate as! AppDelegate).flutterEngine flutterViewController = FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)这时就已经可以直接使用 pushViewController 或者 present 来显示 FlutterViewController
传值有两种,一种是直接传值:即直接传值给Flutter端,还有种则是间接性传值:需要触发某种条件后传值
- 直接传值:
Swfit端:
var channel : FlutterEventChannel? var eventSink : FlutterEventSink? self.channel = FlutterEventChannel(name: "swift.value", binaryMessenger: flutterViewController as! FlutterBinaryMessenger) self.channel?.setStreamHandler(self)"swift.value" 可以被定义为和Flutter建立通信的唯一标识
实现 FlutterStreamHandler 协议
func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? { self.eventSink = events return nil } func onCancel(withArguments arguments: Any?) -> FlutterError? { return nil }随后如果我们想要在 pushViewController 或者 present 时把值传递时,可以在相应的触发方法中添加如下代码:
self.eventSink?("hahahahh") self.navigationController?.pushViewController(flutterViewController!, animated: true)eventSink()中所带的内容则是需要传递的值
Flutter端:
设置对应标识并接收值
static const EventChannel eventChannel = EventChannel('swift.value'); @override void initState() { super.initState(); eventChannel.receiveBroadcastStream("init").listen((event) { _context = event.toString(); setState(() {}); }); }
完整代码如下
import UIKit
import Flutter
class FHEntranceViewController: UIViewController {
var channel : FlutterEventChannel?
var eventSink : FlutterEventSink?
var flutterViewController : FlutterViewController? = nil
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .white
let flutterEngine = (UIApplication.shared.delegate as! AppDelegate).flutterEngine
flutterViewController = FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)
self.channel = FlutterEventChannel(name: "swift.value", binaryMessenger: flutterViewController as! FlutterBinaryMessenger)
self.channel?.setStreamHandler(self)
}
func mobileEntranceLadders(_ mobilestr : String) {
self.eventSink?("hahahahh")
self.navigationController?.pushViewController(flutterViewController!, animated: true)
}
}
extension FHEntranceViewController : FlutterStreamHandler {
func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
self.eventSink = events
return nil
}
func onCancel(withArguments arguments: Any?) -> FlutterError? {
return nil
}
}
关于间接传值是指当触发了Flutter中的某个方法,从而把Swift端的值传递到Flutter端。 例: 在Flutter中设置一个按钮和一个Text用来触发传值请求和现实传递过来的值
Flutter端:
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Center(
child: TextButton(
onPressed: () {
_communicateFunction('传值给Swift');
setState(() {});
},
child: const Text("点击传值"),
),
),
Center(
child: Text(value),
),
],
);
}
_communicateFunction()内的内容是传递给Swift的值
添加相应的传值和接收方法
static const communicateChannel = MethodChannel('ReceiveValue');
//异步执行调用原生方法,保持页面不卡住,因为调用原生的方法可能没实现会抛出异常,所以trycatch包住
Future<void> _communicateFunction(flutterPara) async {
try {
//原生方法名为callNativeMethond,flutterPara为flutter调用原生方法传入的参数,await等待方法执行
final result = await communicateChannel.invokeMethod(
'callNativeMethond', flutterPara);
//如果原生方法执行回调传值给flutter,那下面的代码才会被执行
value = result;
setState(() {});
} on PlatformException catch (e) {
//抛出异常
//flutter: PlatformException(001, 进入异常处理, 进入flutter的trycatch方法的catch方法)
print(e);
}
}
Swift端:
let methodChannel = FlutterMethodChannel(name: "ReceiveValue", binaryMessenger: >flutterViewController as! FlutterBinaryMessenger) methodChannel.setMethodCallHandler { call, result in print("call =====\(call),result ===== \(String(describing: result))") if call.method == "callNativeMethond" { print(call.arguments!) result("我是原生返回数据") } }result()中的内容是传递给Flutter的值
而 call.arguments 则是Flutter传递给Swfit的内容
如此就实现了Swift和Flutter的交互,当然传递值的类型还有报错等都是需要在实际项目中进行处理的