插件与Native通信
1. Flutter向native发送通信(分析实例: SharedPreferences)
Flutter通过Dart与Native发送数据通信请求是通过MethodChannel 调用invokeMethod 来实现
const MethodChannel _kChannel =
const MethodChannel('plugins.flutter.io/shared_preferences');
使用Dart语言调用,获取数据
获取preferences数据:
final Map<Object, Object> fromSystem =
await _kChannel.invokeMethod('getAll');
通过Dart向Native发送数据,并获得返回结果
Future<bool> _setValue(String valueType, String key, Object value) {
final Map<String, dynamic> params = <String, dynamic>{
'key': '$_prefix$key',
};
if (value == null) {
_preferenceCache.remove(key);
return _kChannel
.invokeMethod('remove', params)
.then<bool>((dynamic result) => result);
} else {
_preferenceCache[key] = value;
params['value'] = value;
return _kChannel
.invokeMethod('set$valueType', params)
.then<bool>((dynamic result) => result);
}
}
数据通信在Flutter中定义是Plugin,因此iOS需要遵循Plugin协议FlutterPlugin
Android实现MethodCallHandler
,通信过程中是根据Dart中设置的ChannelName来区分对应的Plugin
对于跨平台来说流程是统一的,我们通过iOS来说通信流程,然后在此基础上稍微梳理一下Android的流程
通信基本流程
- 注册Plugin
- Channel与messager进行匹配
- 通信
iOS:
声明出一个Plugin
#import <Flutter/Flutter.h>
@interface FLTSharedPreferencesPlugin : NSObject<FlutterPlugin>
@end
- 注册
对于每一个遵循FlutterPlugin
的类都会在系统创建plugin时实现注册方法+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar
- 匹配
在系统的注册方法中需要将通信的Channel与regster所携带来的messager进行匹配绑定
FlutterMethodChannel *channel =
[FlutterMethodChannel methodChannelWithName:CHANNEL_NAME binaryMessenger:registrar.messenger];
- 通信
通信是相互的,flutter向native发送数据通信之后,native需要通过回调向flutter做出反馈
Channel通过handler来处理平台之间的数据沟通
[channel setMethodCallHandler:^(FlutterMethodCall *call, FlutterResult result) {}
拿 getAll 作说明:
NSString *method = [call method];
NSDictionary *arguments = [call arguments];
if ([method isEqualToString:@"getAll"]) {
result(getAllPrefs());
}
1. 对于通信方法的区分是采用字符串匹配的方式来达到平台的兼容
2. arguments中携带的是flutter传递给native的数据
3. 采用回调的当时进行数据结果的反馈
下面是iOS具体的通信过程
[channel setMethodCallHandler:^(FlutterMethodCall *call, FlutterResult result) {
NSString *method = [call method];
NSDictionary *arguments = [call arguments];
if ([method isEqualToString:@"getAll"]) {
result(getAllPrefs());
} else if ([method isEqualToString:@"setBool"]) {
NSString *key = arguments[@"key"];
NSNumber *value = arguments[@"value"];
[[NSUserDefaults standardUserDefaults] setBool:value.boolValue forKey:key];
result(@YES);
} else if ([method isEqualToString:@"setInt"]) {
NSString *key = arguments[@"key"];
NSNumber *value = arguments[@"value"];
// int type in Dart can come to native side in a variety of forms
// It is best to store it as is and send it back when needed.
// Platform channel will handle the conversion.
[[NSUserDefaults standardUserDefaults] setValue:value forKey:key];
result(@YES);
} else if ([method isEqualToString:@"setDouble"]) {
NSString *key = arguments[@"key"];
NSNumber *value = arguments[@"value"];
[[NSUserDefaults standardUserDefaults] setDouble:value.doubleValue forKey:key];
result(@YES);
} else if ([method isEqualToString:@"setString"]) {
NSString *key = arguments[@"key"];
NSString *value = arguments[@"value"];
[[NSUserDefaults standardUserDefaults] setValue:value forKey:key];
result(@YES);
} else if ([method isEqualToString:@"setStringList"]) {
NSString *key = arguments[@"key"];
NSArray *value = arguments[@"value"];
[[NSUserDefaults standardUserDefaults] setValue:value forKey:key];
result(@YES);
} else if ([method isEqualToString:@"commit"]) {
// synchronize is deprecated.
// "this method is unnecessary and shouldn't be used."
result(@YES);
} else if ([method isEqualToString:@"remove"]) {
[[NSUserDefaults standardUserDefaults] removeObjectForKey:arguments[@"key"]];
result(@YES);
} else if ([method isEqualToString:@"clear"]) {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
for (NSString *key in getAllPrefs()) {
[defaults removeObjectForKey:key];
}
result(@YES);
} else {
result(FlutterMethodNotImplemented);
}
}];
Android待后续梳理