2024-07-10 fair release4.0生成插件

2024-07-09  本文已影响0人  我是小胡胡123

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';

这种是正常的:


image.png

使用相对路径会使第二个参数是[1]就,导致js报错


image.png

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通讯参数不需要管。
}
上一篇 下一篇

猜你喜欢

热点阅读