前言
flutter
开发也不或许纯flutter
开发,除非只开发一个图片文本阅读的东西,否则一旦用到原生的,那么就需求了解原生
与 flutter
的交互了
交互场景许多,例如:原项目以原生为主,要添加flutter
作为部分功用,如订单模块;项目以flutter
为主,但是运用到了原生的硬件相关,还没有合适的三方,需求通过原生处理
因此 flutter
与原生
之间一同进行开发的情况不在少数,这篇文件首要介绍 flutter
与ios
的交互,android
的也类似,只需大致交互逻辑理解即可
检验案例demo
ps
:这儿一共介绍两种情况,一种原生为主、flutter为辅
的(初始页面运用原生编写),一种flutter为主、原生为辅
,假设功用差不多看自己选择了,实质差不多
其他实践运用进程中,完全以自己项目为基准,下面两种方案只是初期配备办法不相同,要是自己肯改动,其实原理都相同的(要是两个都看完信任很快了解)
module(原生为主、flutter为辅)
本方案首要选用module
办法配备flutter
,这种情况一般是原生为主、flutter为辅
,即:flutter
编写项目首要运用于某个功用模块,例如:订单、会员、个人信息、活动等,默许从原生初步主页等功用
注
:该办法解耦后,flutter项目和原生就分开了
其他此办法假设想工作完好项目,有必要要从 xcode
或许 android studio
初步工作,flutter
中直接工作的只是是flutter单个模块
的功用(走的是其他一个默许原生工程
,后边会介绍,是不是很像检验那套)
创建flutter module
首要创建一个 flutter
的 module
模块,选择了之后,会发现跟原生编程言语不要紧,如下所示(记住项目姓名不要大写)
创建结束之后,会发现,创建的默许的app
不相同,android
和ios
的都是.开始的躲藏文件
其他,.ios
躲藏文件夹的 Generated.xcconfig
后边要是报错或许会需求了解他,如下所示
然后就初步配备原生了!
配备原生
创建一个 ios
原生项目,和 flutter
一个目录,如下所示(也可以不一个目录,但更新path
即可),
1、配备Podfile
然后编写 Podfile
文件,假设没有 pod init
初始化,参加内容如下所示
platform :ios, '9.0'
target 'FlutterObjcDemo' do
use_frameworks!
# 导入flutter相关环境
# 途径,../表明前一个目录,./表明当时目录
flutter_application_path = '../flutter_module/'
# 加载环境
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
install_all_flutter_pods(flutter_application_path)
# 下面这个也可以加载环境
# eval(File.read(File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')), binding)
end
修改结束后,然后 pod install
即可
2、设置 bitcode
然后 Build Setting
中 bitcode
设置为 no
注意:到这儿就现已设置差不多了,项目也不会报错,但会有一个问题
,那就是项目只能加载flutter
编译好的内容,当flutter
更新文件,却没有从头编译时,那么 xcode
工作的会是flutter
上次编译的缓存,这就很苦恼
3、脚本文件设置
1、拖拽 Generated.xcconfig
文件到项目
实行脚本文件之前,我们往项目中拖拽前面提到的.ios
的Flutter
文件夹,如下所示,不要copy
然后右键移除多余的文件引用(选择Remove References
,不要移动到废纸篓)选择只留下一个,如下所示
注
:这个进程是自己检验出来的,看他人的没有提到相对途径无法辨认的问题
2、添加 run Script
脚本
幸亏的是,flutter
早在tools
中给我们供给了一个xcode_backend.sh
的脚本文件,我们只需求设置好脚本文件,即可在项目工作时自动编译flutter
项目
然后在 Build Phases
中添加一个脚本实行模块
然后,在下面方位添加脚本,且Run Script
的方位,要排在第二位,要在xcode编译之前
,先实行脚本编译flutter
项目,否则工作会出现问题(注意:假设没有此脚本,flutter项目不会编译更新,只会用缓存)
具体脚本内容就如下所示($FLUTTER_ROOT
为flutter
的环境相对目录),仿制进去就行,然后修改工作成功就配备结束了(前面往项目中拖拽Generated.xcconfig
就是为了这儿,有些机器环境就是不辨认),工作失败看下面一步
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" build
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" embed
备用
:由于环境配备或许其他不知道问题,有些电脑或许仍是无法辨认 $FLUTTER_ROOT
指令,因此会犯错,之前提到过Generated.xcconfig
,这个文件里边有这个绝对途径信息,我们将他们仿制替换过来就行,如下所示(横竖我是相同的配备办法,一台电脑可以,而另一台不可以)
"/Users/lishuai/flutter/packages/flutter_tools/bin/xcode_backend.sh" build
"/Users/lishuai/flutter/packages/flutter_tools/bin/xcode_backend.sh" embed
两头交互
这儿先阐明一下,打开 flutter
模块,实践上就是创建了一个 FlutterViewController
控制器,然后工作,假设想发动工作 Flutter
模块(和默许创建的Flutter
项目相同),那么直接设置 rootViewController
即可,否则就像一个正常的控制器相同,进行push
或许present
注
:虽然下面的案例也是设置rootViewController
,但实践工作进程中不举荐这样运用,这样运用会影响flutter
对ios
端运用声明周期的监听,假设想监听后续会了解到
ios端交互设置
以 Object-c
为例,在 ios
我们需求引进头文件 Flutter.h
,如下所示
#import <Flutter/Flutter.h>
然后创建 FlutterViewController
,通过 FlutterMethodChannel
进行交互
//创建flutter模块寄予的 ViewController
FlutterViewController *vc = [[FlutterViewController alloc] init];
//可以直接设置成根控制器,也可以进行push或许dismiss,这儿设置成根控制器
self.window.rootViewController = vc;
//设置 methodChannel 用于和 flutter 通讯
//假设原生端组件化开发,那就每个组件创建各自的methodChannel即可,分别对应特定功用
//可以创建多个methodChannel变量,即:起不同的姓名,可以分别和flutter不同的功用进行通讯
//例如:一个订单页面通讯,一个和个人页面通讯
self.methodChannel =
[FlutterMethodChannel methodChannelWithName:@"mine/mine_page" binaryMessenger:vc];
//向flutter端以method发送一个消息
//第一个参数为办法名,第二个为参数,参数多的话主张json字符串,两边分别解析
[self.methodChannel invokeMethod:@"one" arguments:nil];
//最终一个参数是发送回调,假设fluter端出现了问题,可以通过回调得到回馈,否则就是成功,一般不会犯错
[self.methodChannel invokeMethod:@"one" arguments:nil result:^(id _Nullable result) {}];
//监听flutter发送过来的消息
[self.methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call,
FlutterResult _Nonnull result) {
//接纳到flutter传递过来的消息
//可以看到 call 有 method 和 arguments两个参数,分别为办法名,参数
NSLog(@"ios回调 %@ -- %@", call.method, call.arguments);
//假设交互进程出现了问题,可以调用 result 回调,将内容回调给 flutter端
}];
假设想在工作flutter
时当即传递一个参数,则通过下面办法传递创建 FlutterViewController
即可
FlutterViewController *vc = [[FlutterViewController alloc]
initWithProject:nil initialRoute:@"one" nibName:nil bundle:nil];
flutter端交互设置
如下所示,flutter 中直接声明MethodChannel
目标和ios
端进行通讯(android也是一套逻辑),这儿没有先引用头文件,信任开发过的会马上理解,报错提示直接自动纠正就引进了 flutter/services
文件
//头文件
import 'package:flutter/services.dart';
//声明 MethodChannel
里边名称需求仅有化:可以功用模块姓名/功用姓名,也可以像官方提示相同com... 保证不重复即可
final MethodChannel _channel = const MethodChannel("mine/mine_page");
向ios
和android
端发送消息
//和ios端设置相同,第一个参数办法名,第二个为参数
//作用回来一个 Future,假设交互进程出现了问题,可以及时接纳反响作用,和原生端相同
_channel.invokeMethod("testInfo");
_channel.invokeMethod("testInfo", "我是参数");
监听ios
和android
端发来的消息
//设置回调
_channel.setMethodCallHandler((MethodCall call) {
print(call.method);
print(call.arguments);
print("flutter--回调作用");
//这个参数用于反响给原生端,假设工作出现了问题,那边能通过 callback 监听到回馈
return Future(() => null); //给一个空Future
});
这样两个端的交互问题解决了
module 单独调试
flutter
项目的热更在开发中很节省时刻,上面一向用原生工作开发是不现实的,实践上需求整个项目联调的时分才需求从原生端工作
当像单独调试 flutter
的 module
是,很简单,就像我们工作单独的 flutter
项目相同,直接点击工作即可,他会自动以默许的备用空原生项目工作,一同加载 module
内容(还记住前面的 .ios
躲藏文件么,那可不是一个铺排)
就这样,将 module
当成单个 app
工作了,自己可以根据调试内容,设置初步的参数,这式联调的时分去掉检验数据即可
application(flutter为主、原生为辅)
我们新创建一个demo
一般就是这种,一般flutter为主、原生为辅
默许创建的是一个 flutter
项目,如下所示,不多说
然后 flutter
不需求我们配备,原生端呢,其实默许也是配备好的,其他也不需求我们配备
还记住前面讲的 Flutter
模块其实就是打开了一个 FlutterViewController
,其实就是一个控制器,初步的时分,体系会默许将跟控制器设置成 FlutterViewController
,其实和我们的 Module
类似,且 bitcode
和脚本
都设置结束了,和 module
根柢类似,
注
:项目在xcode
工作和flutter
中工作作用一模相同
不信你看这个,刚出创建的项目默许加载 main.storyboard
,其中跟控制器就是 FlutterViewController
是不是感觉,天哪,前面我们做了那么多,干嘛这么费力,没事,仍是有区其他,我们先看看作用,后边比照介绍
如下所示,会发现,他默许继承了 FlutterAppDelegate
,这个往常我们也用不到,modules
可以不用继承,默许的项目继承我们也不用管,改回来也没事
//FlutterAppDelegate的介绍阐明,一般用于检验阶段,例如:modules根柢不需求,可以根据自己需求重写回调
/**
* `UIApplicationDelegate` subclass for simple apps that want default behavior.
*
* This class implements the following behaviors:
* * Status bar touches are forwarded to the key window's root view
* `FlutterViewController`, in order to trigger scroll to top.
* * Keeps the Flutter connection open in debug mode when the phone screen
* locks.
*
* App delegates for Flutter applications are *not* required to inherit from
* this class. Developers of custom app delegate classes should copy and paste
* code as necessary from FlutterAppDelegate.mm.
*/
@interface AppDelegate : FlutterAppDelegate
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
[self setupFlutter];
// Override point for customization after application launch.
return [super application:application
didFinishLaunchingWithOptions:launchOptions];
}
flutter和ios交互
交互不多说了,和ios
相同,可以抽离出来,就是由于以 flutter
为主,导致现在只能写到 AppDelegate
中了,可以一致放到一同整理起来
- (void)setupFlutter {
UIViewController *vc = [UIApplication sharedApplication].delegate.window.rootViewController;
_methodChannel = [FlutterMethodChannel methodChannelWithName:@"one_page" binaryMessenger:(FlutterViewController *)vc];
[_methodChannel invokeMethod:@"one" arguments:nil];
//监听退出
[_methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
NSLog(@"ios回调 %@ -- %@", call.method, call.arguments);
}];
}
两种办法差异,以及举荐场景
差异
通过 module
创建的项目:
flutter
的模块可以单独工作,不受原生端代码的影响,相比照较独立,当然要通过 flutter
端工作(一般在 android studio),需求整体工作的时分,通过原生端发动即可;
特征
:flutter
端调试便当,减少了原生项目的编译时刻,仍然能热更,减少了原生项目的影响,但检验简单遗失与原生端的沟通问题
通过 application
创建的项目:
flutter
模块不可以单独工作,项目工作的时分会自动先编译flutter
在编译原生
工作,因此每次都要编译两个端,每次都是工作整个项目;
特征
:调试进程中总是针对整体代码,但flutter
仍然可以热更,检验进程中不会遗失功用,就是每次从头发动都要从头编译整个项目,简单受到原生项目的过错影响
举荐场景
module
比较适用于老到项目,原生端和 flutter
分别明显,希望他们之间最小影响,更适用于现已用原生开发的项目,后续直接接入module
,开发进程对原生影响也不大
application
比较合适小公司项目或许首要运用 flutter编写的项目,他们之间耦合略严峻,但也不是不能分别
可以根据当时场景抉择,当然这只是一部分考量,实践中心偏移也没问题,根据自己项目来选择更快的办法
最终
本篇文章可以作为一个参考,初步你的flutter之旅吧