likes
comments
collection
share

58fair json文件怎么转化成widget与js方法调用

作者站长头像
站长
· 阅读数 36

动态页面生成

编写页面的dart代码如下:

import 'package:fair/fair.dart';
import 'package:fairdemo/plugins/screen_util.dart';
import 'package:flutter/material.dart';

@FairPatch()
class Test2 extends StatefulWidget {
  @override
  State<Test2> createState() => _Test2State();
}

class _Test2State extends State<Test2> {
  String getHeight(double height) {
    return '${height + 100}';
  }

  @override
  Widget build(BuildContext context) {
    return Text(getHeight(100));
  }
}

通过fair compiler编译生成逻辑js文件和json文件: 页面json文件:

{
  "className": "Text",
  "pa": [
    "%(getHeight(100))"
  ],
  "methodMap": {},
  "digest": "fc6dd47c7b54434b70b954c981085540"
}

逻辑js文件:

GLOBAL['#FairKey#'] = (function(__initProps__) {
    const __global__ = this;
    return runCallback(function(__mod__) {
        with(__mod__.imports) {
            function _Test2State() {
                const inner = _Test2State.__inner__;
                if (this == __global__) {
                    return new _Test2State({
                        __args__: arguments
                    });
                } else {
                    const args = arguments.length > 0 ? arguments[0].__args__ || arguments : [];
                    inner.apply(this, args);
                    _Test2State.prototype.ctor.apply(this, args);
                    return this;
                }
            }
            _Test2State.__inner__ = function inner() {};
            _Test2State.prototype = {
                getHeight: function getHeight(height) {
                    const __thiz__ = this;
                    const __arg_ctx__ = {
                        height,
                    };
                    with(__thiz__) {
                        with(__arg_ctx__) {
                            return `${height + 100}`;
                        }
                    }
                },
            };
            _Test2State.prototype.ctor = function() {};;
            return _Test2State();
        }
    }, []);
})(convertObjectLiteralToSetOrMap(JSON.parse('#FairProps#')));

动态页面还原成dart页面渲染过程

通过FairWidget加载:

FairWidget(
  name: "test1",
  path: 'assets/fair/lib_fair_test_test2.fair.json',
)

解析第一步: 通过toWidget方法将json文件还原成widget

var widget = _convert(context, layout!, methodMap, data: data);

这一步layout数据就是json格式页面数据

通过遍历map

{
  "className": "Text",
  "pa": [
    "%(getHeight(100))"
  ],
  "methodMap": {},
  "digest": "fc6dd47c7b54434b70b954c981085540"
}

tag值是className

var name = map[tag];

1、先在module中匹配

var module = bound?.modules?.moduleOf(name)?.call();

这个module的定义可以在FairApp初始化中配置

FairApp(
      generated: AppGeneratedModule(),
      modules: {},
      delegate: { 
      },
      child: MyApp(),
    );

2、在方法和变量中匹配

mapper = bound?.functionOf(name) ?? bound?.valueOf(name);

这个bound通过FairApp获取,先获取FairApp,

var app = FairApp.of(context);
var bound = app?.bindData[page];

FairApp.of(context)这个方法是从 context 中 findAncestorWidgetOfExactType通过widget 树结构查找。

static FairApp? of(BuildContext? context, {bool rebuild = false}) {
 return rebuild ? context?.dependOnInheritedWidgetOfExactType<FairApp>() : context?.findAncestorWidgetOfExactType<FairApp>();
}

我们在main中通过FairApp在最外层包裹页面。 所以这里对应app对象就是从main中初始化的FairApp

FairApp(
     generated: AppGeneratedModule(),
     modules: {},
     delegate: {
      
     },
     child: MyApp(),
   );

FairApp继承自 AppState

class FairApp extends InheritedWidget with AppState 

bindData是AppState定义的属性,通过其register方法绑定

Future<dynamic> register(FairState state) 

注册页面 的

    bindData.putIfAbsent(
      state.state2key,
      () => BindingData(
        modules,
        functions: delegate.bindFunction(),
        values: delegate.bindValue(),
      ),
    );

这里key名就是 页面名字,即对应

FairWidget(
  name: "test1",
  path: 'assets/fair/lib_fair_test_test2.fair.json',
)

这个name 进行计算得到:

state2key = GlobalState.id(widget.name);

通过_counter全局的变量标识,避免同一个可能会使用多次而导致数据混用问题:

static String id(String? prefix) {
  return '$prefix#${GlobalState._counter++}';
}

因此回到上面跟踪的过程:

mapper = bound?.functionOf(name) ?? bound?.valueOf(name);

这个方法就是在 delegate.bindFunction(), 和delegate.bindValue(),方法在FairApp创建时候通过传入的delegate实现的:

 FairApp(
      generated: AppGeneratedModule(),
      modules: {},
      delegate: {
        ///定义方法和变量映射表
      },
      child: MyApp(),
    );

3,在mapper = proxyMirror?.componentOf(name);中查找

mapper = proxyMirror?.componentOf(name); ProxyMirror 这个就是一个大map 叫做_provider对象管理,存放 字符串到dart方法的映射关系。

class ProxyMirror with P {
  final _provider = BindingProvider();
}

分为3大部分:

首先是fair_version下面的,这是flutter framework 系统widget和方法的对应关系

BindingProvider 混入$BindingImpl类

class BindingProvider with $BindingImpl

$BindingImpl定义如下

  import '\$\$c.dart' as $0;
import '\$\$w.dart' as $1;
import '\$\$p.dart' as $2;
import '\$\$m.dart' as $3;
import '\$\$r.dart' as $4;
import '\$\$a.dart' as $5;
 
  mixin $BindingImpl {
    final provider = [
  
$0.p,
$1.p,
$2.p,
$3.p,
$4.p,
$5.p,
];}

一些特殊映射表:

specialBinding =
    SplayTreeMap.from({
  ...common.provider(),
  ...geometry.provider(),
  ...flow.provider(),
});

对应的是geometry.dart common.dart flow.dart 这3个文件中定义的映射关系,比如FairWidget Color等这些对象的映射对照表:

{
    'FairWidget': (props) => FairWidget(
          name: props['name'],
          path: props['path'],
          data: props['data'],
        ),
    'Color': (props) {
      var color = pa0(props);
      return color is String ? FairUtils.fromHex(color) : Color(color);
    },

最后一部分就是GeneratedModule通过@FairBindging注解生成的第三方包中的方法和widget

  void addGeneratedBinding(GeneratedModule? generated) {
    if (generated == null) {
      return;
    }
    _generatedMapping.addAll(generated.mapping());
    _provider.binding.addAll(generated.components());
  }

通过_proxy.addGeneratedBinding(generated);方法添加。

GeneratedModule

FairApp(
  generated: AppGeneratedModule(),
  modules: {},
  delegate: {
 
  },
  child: MyApp(),
)

AppGeneratedModule是一个通过@FairBinding通过fair compiler工具自动化生成的代码

class AppGeneratedModule extends GeneratedModule 

GeneratedModule 类对应的就是需要提供方法:

abstract class GeneratedModule {
  Map<String, dynamic> components();

  Map<String, bool> mapping();
}
 

也是一个map

综合上面3个大map

就完成了 proxyMirror?.componentOf(name);这个组件的查找的逻辑。

在大map中找到匹配关系

调用return block(map, methodMap, context, domain, mapper, name, isWidget);方法。

这个mapper对象则为fun ,就是 json 页面中name为key从大map找到的对应的实现,是一个方法或者是一个widget构造对象,这就完成了从json string name到widget的映射查找关系。

dynamic block(
  Map map,
  Map? methodMap,
  BuildContext ctx,
  Domain? domain,
  dynamic fun,
  String name,
  bool widget, {
  bool forceApply = false,
}) 

通过named方法递归遍历json结构 并且返回当前层的context即dart三棵树的Element数BuildContext对象,通过positioned方法提取参数

var na = named(name, map['na'], methodMap, ctx, domain);
var pa = positioned(map['pa'], methodMap, ctx, domain);

看下之前转化的json 这个是一层,

{
  "className": "Text",
  "pa": [
    "%(getHeight(100))"
  ],
  "methodMap": {},
  "digest": "fc6dd47c7b54434b70b954c981085540"
}

这个是多层widget嵌套样子:

{
  "className": "Scaffold",
  "na": {
    "appBar": {
      "className": "AppBar",
      "na": {
        "title": {
          "className": "Text",
          "pa": [
            "测试2131"
          ],
          "na": {
            "style": {
              "className": "TextStyle",
              "na": {
                "color": "#(Colors.black)",
                "fontSize": 20
              }
            }
          }
        }
      }
    }}

named方法递归遍历实现如下:通过 json中na往下遍历

W<Map<String, dynamic>> named(
    String tag,
    dynamic naMap,
    Map? methodMap,
    BuildContext context,
    Domain? domain,
  ) {
    var na = <String, dynamic>{};
    var needBinding = false;
    if (naMap is Map) {
      naMap.entries.forEach((e) {
        if (e.value is Map) {
          na[e.key] = namedMap(tag, naMap, methodMap, context, domain, e);
        } else if (e.value is List) {
          na[e.key] =
              namedList(tag, naMap, methodMap, context, domain, e.value);
        } else if (domain != null && domain.match(e)) {
          na[e.key] = domain.bindValue(e as String);
        } else if (domain != null && e is MapEntry && domain.match(e.value)) {
          na[e.key] = domain.bindValue(e.value);
        } else if (e.value is String) {
          var w = namedString(tag, naMap, methodMap, context, domain, e.value);
          needBinding = w.binding ?? false;
          na[e.key] = w.data;
        } else {
          na[e.key] = e.value;
        }
      });
    }
    na['\$'] = context;
    return W<Map<String, dynamic>>(na, needBinding);
  }

通过positioned方法进行参数解析

var r = proxyMirror?.evaluate(context, bound, e, domain: domain);

有8种Expression正则表达式匹配,用来解析字符串对应提取属性值。是方法还是变量的调用。

abstract class Expression {
  R onEvaluate(
      ProxyMirror? proxy, BindingData? binding, Domain? domain, String? exp, String? pre);

  /// fail-fast
  bool hitTest(String? exp, String? pre);
}

这里从源码中全部找出来如下:

final List<Expression> _expressions = [
  ComponentExpression(),
  InlineExpression(),
  InlineObjectExpression(),
  WidgetParamExpression(),
  FunctionExpression(),
  GestureExpression(),
  PropValueExpression(),
  ValueExpression(),
];

ValueExpression匹配放到最后,所有无法匹配的当作变量。

ComponentExpression:
return RegExp('#\\(.+\\)', multiLine: true).hasMatch(exp ?? '');

InlineExpression:
return RegExp(r'\$\w+', multiLine: true).hasMatch(pre ?? '');

InlineObjectExpression:
return RegExp(r'\$\{\w.+\}', multiLine: true).hasMatch(pre ?? '');

WidgetParamExpression:
return RegExp('#\\(widget\..+\\)', multiLine: true).hasMatch(exp ?? '');

FunctionExpression:
return RegExp(r'\%\(.+\)', multiLine: false).hasMatch(exp ?? '');

GestureExpression:
return RegExp(r'\@\(.+\)', multiLine: false).hasMatch(exp ?? '');

PropValueExpression:
return RegExp(r'\^\(\w+\)', multiLine: false).hasMatch(exp ?? '');

所以回到本次例子中json格式:

{
  "className": "Text",
  "pa": [
    "%(getHeight(100))"
  ],
  "methodMap": {},
  "digest": "fc6dd47c7b54434b70b954c981085540"
}

%(getHeight(100)) 这个匹配的是FunctionExpression对应为一个函数方法的调用

分别会提取 getHeight 和 参数 100

完整的postion方法实现如下:

  W<List> positioned(
      dynamic paMap, Map? methodMap, BuildContext context, Domain? domain) {
    var pa = [];
    var needBinding = false;
    if (paMap is List) {
      paMap.forEach((e) {
        if (e is Map) {
          pa.add(convert(context, e, methodMap, domain: domain));
        } else if (domain != null && domain.match(e)) {
          pa.add(domain.bindValue(e));
        } else if (domain != null && e is MapEntry && domain.match(e.value)) {
          pa.add(domain.bindValue(e.value));
        } else if (e is String) {
          var r = proxyMirror?.evaluate(context, bound, e, domain: domain);
          if (r?.binding == true) {
            needBinding = true;
          }
          pa.add(r?.data);
        } else {
          pa.add(e);
        }
      });
    }
    return W<List>(pa, needBinding);
  }

注意到这里有一个匹配methodMap方法。

重新创建一个稍微复杂的使用情况:

import 'package:fair/fair.dart';
import 'package:fairdemo/plugins/custom_method.dart';
import 'package:fairdemo/plugins/custom_method2.dart';
import 'package:flutter/material.dart';

@FairPatch()
class Test2 extends StatefulWidget {
  @override
  State<Test2> createState() => _Test2State();
}

class _Test2State extends State<Test2> {
  String getHeight(double height) {
    return '${height + 100}';
  }

  String getHeight2(double height) {
    return CustomMethod.getString('$height');
  }

  String getHeight3() {
    return CustomMethod.getString('123123');
  }

  String getHeight4() {
    getHeight2(23);
    getHeight3();
    CustomMethod2.getString2('123123');
    return CustomMethod.getString('123123');
  }

  String getHeight5() {
    getHeight2(23);
    getHeight3();
    CustomMethod.getString('123123');
    return CustomMethod2.getString2('123123');
  }

  String getHeight6() {
    getHeight2(23);
    getHeight3();

    return CustomMethod2.getString2('123123') +
        CustomMethod.getString('123123');
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text(getHeight(100)),
        Text(getHeight2(100)),
        Text(getHeight3()),
        Text(getHeight4()),
        Text(getHeight5()),
        Text(getHeight6()),
      ],
    );
  }
}

js文件如下:

GLOBAL['#FairKey#'] = (function(__initProps__) {
    const __global__ = this;
    return runCallback(function(__mod__) {
        with(__mod__.imports) {
            function _Test2State() {
                const inner = _Test2State.__inner__;
                if (this == __global__) {
                    return new _Test2State({
                        __args__: arguments
                    });
                } else {
                    const args = arguments.length > 0 ? arguments[0].__args__ || arguments : [];
                    inner.apply(this, args);
                    _Test2State.prototype.ctor.apply(this, args);
                    return this;
                }
            }
            _Test2State.__inner__ = function inner() {};
            _Test2State.prototype = {
                getHeight: function getHeight(height) {
                    const __thiz__ = this;
                    const __arg_ctx__ = {
                        height,
                    };
                    with(__thiz__) {
                        with(__arg_ctx__) {
                            return `${height + 100}`;
                        }
                    }
                },
                getHeight2: function getHeight2(height) {
                    const __thiz__ = this;
                    const __arg_ctx__ = {
                        height,
                    };
                    with(__thiz__) {
                        with(__arg_ctx__) {
                            return CustomMethod.getString(`${height}`);
                        }
                    }
                },
                getHeight3: function getHeight3() {
                    const __thiz__ = this;
                    with(__thiz__) {
                        return CustomMethod.getString('123123');
                    }
                },
                getHeight4: function getHeight4() {
                    const __thiz__ = this;
                    with(__thiz__) {
                        getHeight2(23);
                        getHeight3();
                        CustomMethod2.getString2('123123');
                        return CustomMethod.getString('123123');
                    }
                },
                getHeight5: function getHeight5() {
                    const __thiz__ = this;
                    with(__thiz__) {
                        getHeight2(23);
                        getHeight3();
                        CustomMethod.getString('123123');
                        return CustomMethod2.getString2('123123');
                    }
                },
                getHeight6: function getHeight6() {
                    const __thiz__ = this;
                    with(__thiz__) {
                        getHeight2(23);
                        getHeight3();
                        return CustomMethod2.getString2('123123') + CustomMethod.getString('123123');
                    }
                },
            };
            _Test2State.prototype.ctor = function() {};;
            return _Test2State();
        }
    }, []);
})(convertObjectLiteralToSetOrMap(JSON.parse('#FairProps#')));

json如下:

{
  "className": "Column",
  "na": {
    "children": [
      {
        "className": "Text",
        "pa": [
          "%(getHeight(100))"
        ]
      },
      {
        "className": "Text",
        "pa": [
          "%(getHeight2(100))"
        ]
      },
      {
        "className": "Text",
        "pa": [
          "%(getHeight3)"
        ]
      },
      {
        "className": "Text",
        "pa": [
          "%(getHeight4)"
        ]
      },
      {
        "className": "Text",
        "pa": [
          "%(getHeight5)"
        ]
      },
      {
        "className": "Text",
        "pa": [
          "%(getHeight6)"
        ]
      }
    ]
  },
  "methodMap": {
    "getHeight2": {
      "className": "CustomMethod.getString",
      "pa": [
        "#($height)"
      ]
    },
    "getHeight3": {
      "className": "CustomMethod.getString",
      "pa": [
        "123123"
      ]
    },
    "getHeight4": {
      "className": "CustomMethod.getString",
      "pa": [
        "123123"
      ]
    },
    "getHeight5": {
      "className": "CustomMethod2.getString2",
      "pa": [
        "123123"
      ]
    }
  },
  "digest": "40c9bc448860777c9ff7bd08912d877c"
}

getHeight2方法和getHeight3方法因为方法内部调用了其他方法,所以在methodMap则有一个定义。 这个methodMap生成规则这里不研究。

主要methodMap有和没有在解析过程中有什么区别

参数方法执行

dynamic get value {
  var extract;
  matches
      ?.map((e) => {
            '0': binding?.runFunctionOf(
                e.group(0)!.substring(2, e.group(0)!.length - 1), proxyMirror, binding, domain),
            '1': e.group(0)
          })
      .forEach((e) {
    var first = e['0'] is ValueNotifier ? e['0'].value : e['0'];
    if (first != null) {
      extract = first; // extract.replaceFirst(e['1'], '$first');
    } else {
      extract = data;
    }
  });
  return extract;
}

通过 binding?.runFunctionOf( e.group(0)!.substring(2, e.group(0)!.length - 1), proxyMirror, binding, domain)方法进行方法调用的解析

提取方法名字和方法参数:

dynamic runFunctionOf(String funcName, ProxyMirror? proxyMirror,
    BindingData? bound, Domain? domain,
    {String? exp}) {
  if (_functions?[funcName] == null) {
    var result;
    if (RegExp(r'.+(.+)', multiLine: false).hasMatch(funcName)) { //提取方法名字
      var rFuncName = funcName.substring(0, funcName.indexOf('('));
      var params = funcName.substring(//提取参数
          funcName.indexOf('(') + 1, funcName.lastIndexOf(')'));
      var args = params.split(',').map((e) {
        if (RegExp(r'^(index)', multiLine: false).hasMatch(e) &&
            domain is IndexDomain?) {
          return domain?.index;
        } else if (domain != null && domain.match(e)) {
          return domain.bindValue(e);
        } else {
          var r = proxyMirror?.evaluate(null, bound, e, domain: domain);
          if (r?.data == null) {
            return e;
          } else {
            return r?.data is ValueNotifier ? r?.data.value : r?.data;
          }
        }
      }).toList();
      //通过运行时 调用native通道执行js
      result = _functions?['runtimeInvokeMethodSync']?.call(rFuncName, args);
    } else {
        //通过运行时  调用native通道执行js
      result = _functions?['runtimeInvokeMethodSync']?.call(funcName);
    }
    try {
      var value = jsonDecode(result);//返回结果用json解析
      return value['result']['result'];//获取native js方法结果,返回的result字段则运算结果数据
    } catch (e) {
      throw RuntimeError(errorMsg: result);
    }
  } else {
    return _functions?[funcName]?.call();
  }
}

调用js方法:

{
    "pageName": "test1#3",
    "type": "method",
    "args":
    {
        "funcName": "getHeight",
        "args":
        [
            "100"
        ]
    }
}

js方法调用:

function _invokeMethod(par) {
    let pageName = par['pageName'];
    let funcName = par['args']['funcName'];
    let args = par['args']['args'];

    if ('getAllJSBindData' === funcName) {
        return getAllJSBindData(par);
    }
    if ('releaseJS' === funcName) {
        return _release(par);
    }
    let mClass = GLOBAL[pageName];
    let func = mClass[funcName];
    let methodResult;
    if (isNull(func)) {
        methodResult = '';
    } else {
        methodResult = func.apply(mClass, args);
    }
    let result = {
        pageName: pageName,
        result: {
            result: methodResult
        }
    };
    return JSON.stringify(result);
}

结果回调数据格式:

{
    "pageName": "test1#3",
    "result":
    {
        "result": "100100"
    }
}

这里有一个问题,为什么result总是返回字符串类型的? 这样会导致在使用如果是需要double类型的地方,则会到界面转化失败。

double getHeight(double height) {
  return height;
}
//转化为js方法: %(getHeight(100))
{
  "className": "Column",
  "na": {
    "children": [
      {
        "className": "Container",
        "na": {
          "height": "%(getHeight(100))"
        }
      }
    ]
  },
  "methodMap": {},
  "digest": "4f6da55171a3ae0e9c8550464b7bf25e"
}
//js方法定义
GLOBAL['#FairKey#'] = (function(__initProps__) {
    const __global__ = this;
    return runCallback(function(__mod__) {
        with(__mod__.imports) {
            function _Test3State() {
                const inner = _Test3State.__inner__;
                if (this == __global__) {
                    return new _Test3State({
                        __args__: arguments
                    });
                } else {
                    const args = arguments.length > 0 ? arguments[0].__args__ || arguments : [];
                    inner.apply(this, args);
                    _Test3State.prototype.ctor.apply(this, args);
                    return this;
                }
            }
            _Test3State.__inner__ = function inner() {};
            _Test3State.prototype = {
                getHeight: function getHeight(height) {
                    const __thiz__ = this;
                    const __arg_ctx__ = {
                        height,
                    };
                    with(__thiz__) {
                        with(__arg_ctx__) {
                            return height; //这个height是什么类型
                        }
                    }
                },
            };
            _Test3State.prototype.ctor = function() {};;
            return _Test3State();
        }
    }, []);
})(convertObjectLiteralToSetOrMap(JSON.parse('#FairProps#')));

//"{\"pageName\":\"test1#0\",\"type\":\"method\",\"args\":{\"funcName\":\"getHeight\",\"args\":[\"100\"]}}"
//通过native调用fair_core.js中的方法:
function invokeJSFunc(parameter) {
    if (parameter === null) {
        return null;
    }
    let map = JSON.parse(parameter);
    if ('method' === map['type']) {
        return _invokeMethod(map);// 类型是method则调用名字为getHeight 的js方法
    } else if ('variable' === map['type']) {
        return _invokeVariable(map);
    }
    return null;
}

function _invokeMethod(par) {
    let pageName = par['pageName'];
    let funcName = par['args']['funcName'];
    let args = par['args']['args'];

    if ('getAllJSBindData' === funcName) {
        return getAllJSBindData(par);
    }
    if ('releaseJS' === funcName) {
        return _release(par);
    }
    let mClass = GLOBAL[pageName];
    let func = mClass[funcName];
    let methodResult;
    if (isNull(func)) {
        methodResult = '';
    } else {
        methodResult = func.apply(mClass, args);//调用js方法
    }
    let result = {
        pageName: pageName,
        result: {
            result: methodResult//methodResult为什么总是string类型
        }
    };
    return JSON.stringify(result);
}

通过native转化将结果结果通过 dartFFI函数返回dart端
//dartffi调用
const char *invokeJSCommonFuncSync(char *args) {
    if ([FairDynamicFlutter sharedInstance].delegate &&
        [[FairDynamicFlutter sharedInstance].delegate respondsToSelector:@selector(executeScriptSyncImpl:)]) {
        return [[FairDynamicFlutter sharedInstance].delegate executeScriptSyncImpl:args];
    }
    return "";
}
//[[FairDynamicFlutter sharedInstance].delegate executeScriptSyncImpl:args];native真正的实现
- (const char *)executeScriptSyncImpl:(char *)args
{
    JSValue *obj;
    if (self.delegate && [self.delegate respondsToSelector:@selector(executeJSFunctionSync:params:)]) {
        
        NSString *str = [NSString stringWithUTF8String:args];
        obj = [self.delegate executeJSFunctionSync:FairExecuteJSFunction params:@[str]];
    }
    NSString *result = [NSString stringWithFormat:@"%@", obj.toString];
    FairLog(@"result:%@", result);
    if([result isEqualToString:@"undefined"]){
        //取args中的funcName字段
        //arg ===> "{\"pageName\":\"null#0\",\"type\":\"method\",\"args\":{\"funcName\":\"_getAuth\",\"args\":null}}"
        NSString *str = [NSString stringWithUTF8String:args];
        NSData *jsonData = [str dataUsingEncoding:NSUTF8StringEncoding];

        NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil];
        
        NSDictionary *args = dic[@"args"];
        NSString *funcName = args[@"funcName"];
        
        FairLog(@"invoke funcName:%@",funcName);
        
        NSString *errorResult = [NSString stringWithFormat:@"Runtime error while invoke JavaScript method:%@()", funcName];
        
        return errorResult.UTF8String;
    }
    return result.UTF8String;
}

总结

到这里基本,就简单分析了界面转化过程的源码实现部分。下一步继续分析:

  • FairAppMap<String, FairModuleBuilder>? modules 使用
  • 自定义插件工作流程和使用
  • 带参数函数调用
  • json页面文件中方法被转化为在在methodMap和没有转化执行区别以及方法带参数时不能在methodMap中匹配执行区别
  • 对于自定义dart代码import 'package:fairdemo/fair_test/test_definemodule.dart'; import 'test_definemodule.dart';@FairPatch()页面中通过注解生成的js文件中 defineModule作用和生成规则,生成的defineModule js部分示例代码为:
  defineModule(1, function(__mod__) {
        with(__mod__.imports) {
            
            inherit(ScreenUtilPlugin, IFairPlugin);
        }
        __mod__.exports.ScreenUtilPlugin = ScreenUtilPlugin;
    }, []);```
转载自:https://juejin.cn/post/7273434389403811895
评论
请登录