FairCommonPlugin插件
所有需要到的动态化逻辑,都用FairCommonPlugin这个插件来进行扩展, 完成从js到dart的到调用和回调。
如何开发插件
1、编写FairCommonPluginMixin
fair_toast_plugin.dart
将此文件放到 lib/src/plugin/目录下面:
mixin FairHttpPlugin implements FairCommonPluginMixin {
Future<dynamic> http(dynamic map) => request(map, _run);
Future<Map?> _run(Map requestMap) async {
// implements http here.
final method = requestMap['method'];
final url = requestMap['url'];
Response<String>? result;
switch (method) {
case 'GET':
result = await _get(url);
break;
case 'POST':
result = await _post(url);
break;
default:
}
if (result != null) {
return {
'data': result.data == null ? '' : jsonDecode(result.data!),
'statusCode': result.statusCode,
};
}
return null;
}
static Future<Response<String>> _post(String path,
{Map<String, String>? queryParameters}) async {
var resp =
await _getDio().post<String>(path, queryParameters: queryParameters);
return Future.value(resp);
}
static Future<Response<String>> _get(String path,
{Map<String, String>? queryParameters}) async {
var resp =
await _getDio().get<String>(path, queryParameters: queryParameters);
return Future.value(resp);
}
static Dio? _dio;
static Dio _getDio() {
_dio ??= Dio();
return _dio!;
}
}
注意这的位置,一定要是lib/src目录下,且实现implements FairCommonPluginMixin
2、执行脚本 生成js和将方法注册
输入命令:
dart run bin/fair_common_plugin.dart
得到产物:
产物1:/assets/plugin/fair_common_plugin.js
产物2:/lib/src/plugin/fair_common_plugin.dart
这样就完成了:
生成FairCommonPlugin().xxx() js方法
生成class FairCommonPlugin extends IFairPlugin在这个插件getRegisterMethods方法表中完成了注册
3、demo中调用
导入插件:
import 'package:example/src/plugin/fair_common_plugin.dart';
import 'package:fair/fair.dart';
在页面中调用逻辑动态化插件:
///build方法中调用:
build(){
///省略代码
Container(
alignment: Alignment.center,
child: ElevatedButton(
onPressed: commonHttp,
child: Text('网络请求-基于FairCommonPlugin')),
),
///省略代码
}
///调用
commonHttp() {
FairCommonPlugin().http({
'method': 'GET',
'url':
'https://wos2.58cdn.com.cn/DeFazYxWvDti/frsupload/3b8ae7a4e0884b4d75b8094f6c83cd8c_list_page_data.json',
'callback': (dynamic result) {
if (result != null) {
var statusCode = result['statusCode'];
if (statusCode == 200) {
var list = result['data']['data'];
list.forEach((item) {
var icon = item['icon'];
print('icon = $icon');
});
}
}
}
});
}
注意:一定需要使用package://包名导入,不要使用 相对路径方式导入'../src/plugin/fair_common_plugin.dart';
,
这种是正常的:
使用相对路径会使第二个参数是[1]就,导致js报错
fair js调用dart流程解析:
调用顺序:
0、业务调用FairCommonPlugin().xxx方法
FairCommonPlugin().http(convertObjectLiteralToSetOrMap({
['method']: 'GET',
['url']: 'https://wos2.58cdn.com.cn/DeFazYxWvDti/frsupload/3b8ae7a4e0884b4d75b8094f6c83cd8c_list_page_data.json',
['callback']: function dummy(result) {
if (result != null) {
let statusCode = result.__op_idx__('statusCode');
if (statusCode == 200) {
let list = result.__op_idx__('data').__op_idx__('data');
list.forEach(function dummy(item) {
let icon = item.__op_idx__('icon');
print(`icon = ${icon}`);
});
}
}
},
}));
1、FairCommonPlugin().xxx实现
/example/assets/plugin/fair_common_plugin.js
// 由 bin/fair_common_plugin.dart 生成
let FairCommonPlugin = function () {
return {
futureComplete: function (resp) {
fairCommonPluginRequest(resp, 'futureComplete');
},
http: function (resp) {
fairCommonPluginRequest(resp, 'http');
},
pushNamed: function (resp) {
fairCommonPluginRequest(resp, 'pushNamed');
},
pushFairPath: function (resp) {
fairCommonPluginRequest(resp, 'pushFairPath');
},
pop: function (resp) {
fairCommonPluginRequest(resp, 'pop');
},
toast: function (resp) {
fairCommonPluginRequest(resp, 'toast');
}
}
}
2、 fairCommonPluginRequest
Fair/fair/assets/fair_core/fair_common_plugin.js
//用户自定义拓展,需要在fair_basic_config.json中注册
//会在基础js加载之后加载
let _callBack = {};
let _callBackId = 0;
let fairCommonPluginRequest = function (resp, methodName) {
let respMap = {};
respMap = mapOrSetToObject(resp);
let id = 'FairCommonPlugin$' + (++_callBackId);
let requestParameter = {};
requestParameter['pageName'] = '#FairKey#';
// 类名 + 方法名
requestParameter['className'] = "FairCommonPlugin#" + methodName;
_callBack[id] = respMap['callback'];
respMap['callId'] = id;
// 代码里面有判断 funcName 必填
requestParameter['funcName'] = 'invokePlugin';
requestParameter['request'] = respMap;
let map = JSON.stringify(requestParameter);
console.log('FairCommonPlugin请求参数:' + map);
invokeFlutterCommonChannel(map, (resultStr) => {
console.log('FairCommonPlugin请求结果:' + resultStr);
let responseMap = JSON.parse(resultStr);
console.log('FairCommonPlugin请求结果1:' + responseMap);
let id = responseMap['callId']
let data = responseMap['response'];
console.log('FairCommonPlugin请求结果2:' + id);
// 这两个函数用户拓展的
if (_callBack[id] === null) {
return;
}
let complete = _callBack[id];
console.log('FairCommonPlugin请求结果3:' + data);
// 返回的是 map
if (data === null) {
complete(null);
}
else {
complete(convertObjectLiteralToSetOrMap(data));
}
_callBack[id] = null
})
}
3、invokeFlutterCommonChannel
const invokeFlutterCommonChannel = (invokeData, callback) => {
console.log("invokeData" + invokeData)
jsInvokeFlutterChannel(invokeData, (resultStr) => {
console.log('resultStr' + resultStr);
if (callback) {
callback(resultStr);
}
});
};
4、jsInvokeFlutterChannel
/Fair/fair/ios/Classes/FairDynamicJSPlugin/FairJSBridge.m
// JS 异步调用 Dart
_context[FairExecuteDartFunctionAsync] = ^(id receiver, JSValue *callback) {
FairStrongObject(strongSelf, weakSelf)
NSString *data = [strongSelf convertStringWithData:receiver];
if ([strongSelf.delegate respondsToSelector:@selector(FairExecuteDartFunctionAsync:callback:)]) {
[strongSelf.delegate FairExecuteDartFunctionAsync:data callback:callback];
}
};
5、BasicMessageChannel 通讯调用dart
com.wuba.fair/common_message_channel
/Fair/fair/lib/src/runtime/fair_message_channel.dart
_commonChannel!.setMessageHandler((String? message) async {
print('来自native端的消息:$message');
//js 异步调用dart中的相关方法
var data = json.decode(message??'');
var funcName = data['funcName']?.toString();
if (funcName == 'invokePlugin') {
var p = await FairPluginDispatcher.dispatch(message);
return p;
}
_callback?.call(message);
return 'reply from dart';
});
6、FairPluginDispatcher 从已注册插件表pluginMap中查找实现
/Fair/fair/lib/src/runtime/plugin/plugin_dispatcher.dart
static Future<dynamic> dispatch(dynamic msg) async {
dynamic obj;
if (msg is Map) {
obj = msg;
} else {
obj = jsonDecode(msg);
}
// var args = obj['args'];
var className = obj['className']?.toString();
if (className == null || className.isEmpty) {
return null;
}
if (className.contains('#')) {
className = className.split('#')[0];
}
if (pluginMap[className] != null) {
// var d = await ;
return pluginMap[className]?.invoke(msg);
}
}
7、Function.apply 调用对应的方法
/Fair/fair/lib/src/runtime/plugin/fair_plugin.dart
abstract class IFairPlugin with FairCommonPluginMixin {
Future<dynamic> invoke(dynamic par) async {
var resp =
await Function.apply(getRegisterMethods()[getMethodName(par)]!, [par]);
return Future.value(resp);
}
String getMethodName(dynamic par) {
dynamic a;
if (par is Map) {
a = par;
} else {
a = jsonDecode(par);
}
var name = a['className']?.toString() ?? '';
if (name.contains('#')) {
var list = name.split('#');
if (list.length >= 2) {
return list[1];
}
}
return '';
}
8、 从目标插件中的方法列表中 getRegisterMethods查找对应的实现function
class FairCommonPlugin extends IFairPlugin
with CompleterPlugin, FairHttpPlugin, FairNavigatorPlugin, FairToastPlugin {
factory FairCommonPlugin() => _fairCommonPlugin;
FairCommonPlugin._();
static final FairCommonPlugin _fairCommonPlugin = FairCommonPlugin._();
@override
Map<String, Function> getRegisterMethods() {
return <String, Function>{
'futureComplete': futureComplete,
'http': http,
'pushNamed': pushNamed,
'pushFairPath': pushFairPath,
'pop': pop,
'toast': toast,
};
}
}
9、FairCommonPluginMixin 真正的dart逻辑
/Fair/example/lib/src/plugin/fair_http_plugin.dart
mixin FairHttpPlugin implements FairCommonPluginMixin {
Future<dynamic> http(dynamic map) => request(map, _run);
Future<Map?> _run(Map requestMap) async {
// implements http here.
final method = requestMap['method'];
final url = requestMap['url'];
Response<String>? result;
switch (method) {
case 'GET':
result = await _get(url);
break;
case 'POST':
result = await _post(url);
break;
default:
}
if (result != null) {
return {
'data': result.data == null ? '' : jsonDecode(result.data!),
'statusCode': result.statusCode,
};
}
return null;
}
static Future<Response<String>> _post(String path,
{Map<String, String>? queryParameters}) async {
var resp =
await _getDio().post<String>(path, queryParameters: queryParameters);
return Future.value(resp);
}
static Future<Response<String>> _get(String path,
{Map<String, String>? queryParameters}) async {
var resp =
await _getDio().get<String>(path, queryParameters: queryParameters);
return Future.value(resp);
}
static Dio? _dio;
static Dio _getDio() {
_dio ??= Dio();
return _dio!;
}
}
10、通用方法request
/Fair/fair/lib/src/runtime/plugin/fair_common_plugin.dart
源码:
mixin FairCommonPluginMixin {
/// common request method
Future<dynamic> request(
dynamic map,
// do your business logic in this call back
Future<Map?> Function(Map reqData) run,
) async {
if (map == null) {
return;
}
var req;
bool isDart;
if (map is Map) {
isDart = true;
req = map;
} else {
isDart = false;
req = jsonDecode(map);
}
final pageName = req['pageName'];
var request = req['request'];
if (isDart) {
request = req;
}
final callId = request['callId'];
final completeCallback = request['callback'];
final response = await run(request);
// 需要判断发起方的请求是dart端还是js端
if (isDart) {
completeCallback?.call(response);
return Future.value();
} else {
final resp = {
'callId': callId,
'pageName': pageName,
'response': response,
};
return Future.value(jsonEncode(resp));
}
}
}
处理通用的逻辑:
js参数解析:
js业务参数 :request。
通用参数:pageName、request、
request参数:js调用 callId,dart调用callback、业务参数FairCommonPlugin().xx({}///这里传递的参数)
dart回调参数:
'callId': callId,
'pageName': pageName,
'response': response,
处理特有的逻辑:
implements FairCommonPluginMixin中实现:
Future<Map?> _run(Map requestMap) async {
//只管返回业务的数据。 js dart通讯参数不需要管。
}