1.iOS集成Flutter
1.1创建项目
创建原生项目"iOS_demo",创建Flutter项目"flutter_lab",两个项目在同一级目录, 在flutter_lab项目里找到lib文件夹,添加dart代码,如图:
1.2使用CocoPods集成
"iOS_demo"添加PodFile文件,命令:cd iOS_demo path -> touch Podfile
打开新创建的Podfile文件,添加代码
flutter_application_path = '../flutter_lab' //这里是flutter项目名
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
target 'iOS_demo' do
install_all_flutter_pods(flutter_application_path)
end
命令: pod install, iOS集成Flutter完成
2.iOS调起Flutter
2.1 AppDelegate配置,注册FlutterEngine,代码如下:
import UIKit
import Flutter
import FlutterPluginRegistrant
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
lazy var flutterEngine = FlutterEngine(name: "my flutter engine")
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
GeneratedPluginRegistrant.register(with: self.flutterEngine);
flutterEngine.run()
return true
}
}
2.2 使用 FlutterEngine 展示 FlutterViewController,代码如下:
import UIKit
import Flutter
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Make a button to call the showFlutter function when pressed.
let button = UIButton(type:UIButton.ButtonType.custom)
button.addTarget(self, action: #selector(showFlutter), for: .touchUpInside)
button.setTitle("Show Flutter!", for: UIControl.State.normal)
button.frame = CGRect(x: 80.0, y: 210.0, width: 160.0, height: 40.0)
button.backgroundColor = UIColor.blue
self.view.addSubview(button)
}
@objc func showFlutter() {
let flutterEngine = (UIApplication.shared.delegate as! AppDelegate).flutterEngine
let flutterViewController =
FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)
present(flutterViewController, animated: true, completion: nil)
}
}
以上默认执行flutter的main函数, 只能实现调起单一路由(控制器),实际操作中,一个iOS原生控制器会根据不同的事件调起不同的路由, 操作如下,首先需要更改2.2代码:
@objc func showFlutter() {
let flutterViewController = FlutterViewController(project: nil, initialRoute: "home", nibName: nil, bundle: nil) // 这里initialRoute要与Flutter项目中的main.dart设置的名称一致, 跳转到homeVC路由
self.modalPresentationStyle = .fullScreen
self.navigationController?.setNavigationBarHidden(true, animated: true)
self.navigationController?.pushViewController(flutterViewController, animated: true)
}
main.dart代码如下:
void main() {
// 获取原生跳转的路由,根据路由显示对应的界面,ui.window.defaultRouteName就是上面设置的 “home”路由标识
runApp(run(ui.window.defaultRouteName));
}
//根据路由标识返回对应的Widget,这里需要注意的是如果是单独的界面,必须使用MaterialApp包裹住,不然跳转过来后显示不了当前ui
Widget run(String name){
switch (name) {
case "test":
return TestVC();
break;
case "home":
return HomeVC();
break;
case "myApp":
return MyApp();
break;
}
return Center(
child: Text('Unknown route: $name'),
);
}
3.iOS与Flutter相互传值
3.1.iOS传值到Flutter
iOS代码:
在按钮点击方法showFlutter()的跳转加FlutterEventChannel
@objc func showFlutter() {
// push代码...
let evenChannel1 = FlutterEventChannel.init(name: "com.nativeToFlutter", binaryMessenger: flutterViewController as! FlutterBinaryMessenger)
evenChannel1.setStreamHandler(self)
}
实现代理方法,该代理方法,只有Flutter项目做了监听才可以触发:
func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
print("push传值代理方法")
events(["key": "push传值", "state": "0"])
return nil
}
func onCancel(withArguments arguments: Any?) -> FlutterError? {
return nil
}
Flutter中的HomeVC代码:
class _HomeVCState extends State {
//注意这里的com.nativeToFlutter一定要与原生的名称相同,不然没办法通信
static const eventChannel = EventChannel('com.nativeToFlutter');
@override
void initState() {
// TODO: implement initState
super.initState();
eventChannel.receiveBroadcastStream().listen(_getData,onError: _getError);
}
//获得到传值(["key": "push传值", "state": "0"])
void _getData(dynamic data) {
print("传值${data}");
}
//获取到错误
void _getError(Object err) {
}
3.1.Flutter传值到iOS
iOS代码:
在按钮点击方法showFlutter()的跳转加FlutterEventChannel
@objc func showFlutter() {
// push代码...
let presentChannel:FlutterMethodChannel = FlutterMethodChannel.init(name: "sf.flutter.io/sf_present", binaryMessenger: flutterViewController as! FlutterBinaryMessenger)
weak var weakSelf = self
// 添加监听回调
presentChannel.setMethodCallHandler { (call, result) in
print(call.method)
// 当flutter调用了原生方法后,此回调会调用
// call.method 为方法名,call对象里面还有参数属性
if call.method == "getNativeResult" {
let dict:[String : Any] = call.arguments as! [String : Any]
print(dict["key"] ?? "")
weakSelf?.navigationController?.popViewController(animated: true)
}
}
}
Flutter中的HomeVC代码:
// 任意事件返回到原生,同时传值到原生
Future invokeNativeGetResult() async {
try {
// 调用原生方法并传参,以及等待原生返回结果数据,getNativeResult是方法名,{"key": "value"}是参数
var result = await platform.invokeListMethod('getNativeResult', {"key": "参数1"});
} catch (e) {}
}