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

动态页面生成

编写页面的dart代码如下:

scala 复制代码
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文件:

json 复制代码
{
  "className": "Text",
  "pa": [
    "%(getHeight(100))"
  ],
  "methodMap": {},
  "digest": "fc6dd47c7b54434b70b954c981085540"
}

逻辑js文件:

javascript 复制代码
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加载:

less 复制代码
FairWidget(
  name: "test1",
  path: 'assets/fair/lib_fair_test_test2.fair.json',
)

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

ini 复制代码
var widget = _convert(context, layout!, methodMap, data: data);

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

通过遍历map

json 复制代码
{
  "className": "Text",
  "pa": [
    "%(getHeight(100))"
  ],
  "methodMap": {},
  "digest": "fc6dd47c7b54434b70b954c981085540"
}

tag值是className

ini 复制代码
var name = map[tag];

1、先在module中匹配

ini 复制代码
var module = bound?.modules?.moduleOf(name)?.call();

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

less 复制代码
FairApp(
      generated: AppGeneratedModule(),
      modules: {},
      delegate: { 
      },
      child: MyApp(),
    );

2、在方法和变量中匹配

ini 复制代码
mapper = bound?.functionOf(name) ?? bound?.valueOf(name);

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

ini 复制代码
var app = FairApp.of(context);
var bound = app?.bindData[page];

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

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

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

less 复制代码
FairApp(
     generated: AppGeneratedModule(),
     modules: {},
     delegate: {
      
     },
     child: MyApp(),
   );

FairApp继承自 AppState

scala 复制代码
class FairApp extends InheritedWidget with AppState 

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

scss 复制代码
Future<dynamic> register(FairState state) 

注册页面 的

less 复制代码
    bindData.putIfAbsent(
      state.state2key,
      () => BindingData(
        modules,
        functions: delegate.bindFunction(),
        values: delegate.bindValue(),
      ),
    );

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

less 复制代码
FairWidget(
  name: "test1",
  path: 'assets/fair/lib_fair_test_test2.fair.json',
)

这个name 进行计算得到:

ini 复制代码
state2key = GlobalState.id(widget.name);

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

javascript 复制代码
static String id(String? prefix) {
  return '$prefix#${GlobalState._counter++}';
}

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

ini 复制代码
mapper = bound?.functionOf(name) ?? bound?.valueOf(name);

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

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

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

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

scala 复制代码
class ProxyMirror with P {
  final _provider = BindingProvider();
}

分为3大部分:

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

BindingProvider 混入$BindingImpl类

scala 复制代码
class BindingProvider with $BindingImpl

$BindingImpl定义如下

javascript 复制代码
  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,
];}

一些特殊映射表:

ini 复制代码
specialBinding =
    SplayTreeMap.from({
  ...common.provider(),
  ...geometry.provider(),
  ...flow.provider(),
});

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

css 复制代码
{
    '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

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

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

GeneratedModule

less 复制代码
FairApp(
  generated: AppGeneratedModule(),
  modules: {},
  delegate: {
 
  },
  child: MyApp(),
)

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

scala 复制代码
class AppGeneratedModule extends GeneratedModule 

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

csharp 复制代码
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的映射查找关系。

kotlin 复制代码
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方法提取参数

ini 复制代码
var na = named(name, map['na'], methodMap, ctx, domain);
var pa = positioned(map['pa'], methodMap, ctx, domain);

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

json 复制代码
{
  "className": "Text",
  "pa": [
    "%(getHeight(100))"
  ],
  "methodMap": {},
  "digest": "fc6dd47c7b54434b70b954c981085540"
}

这个是多层widget嵌套样子:

css 复制代码
{
  "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往下遍历

dart 复制代码
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方法进行参数解析

ini 复制代码
var r = proxyMirror?.evaluate(context, bound, e, domain: domain);

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

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

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

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

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

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

python 复制代码
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格式:

json 复制代码
{
  "className": "Text",
  "pa": [
    "%(getHeight(100))"
  ],
  "methodMap": {},
  "digest": "fc6dd47c7b54434b70b954c981085540"
}

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

分别会提取 getHeight 和 参数 100

完整的postion方法实现如下:

csharp 复制代码
  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方法。

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

scss 复制代码
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文件如下:

javascript 复制代码
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如下:

bash 复制代码
{
  "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有和没有在解析过程中有什么区别

参数方法执行

csharp 复制代码
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)方法进行方法调用的解析

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

kotlin 复制代码
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方法:

json 复制代码
{
    "pageName": "test1#3",
    "type": "method",
    "args":
    {
        "funcName": "getHeight",
        "args":
        [
            "100"
        ]
    }
}

js方法调用:

ini 复制代码
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);
}

结果回调数据格式:

json 复制代码
{
    "pageName": "test1#3",
    "result":
    {
        "result": "100100"
    }
}

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

ini 复制代码
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部分示例代码为:
scss 复制代码
  defineModule(1, function(__mod__) {
        with(__mod__.imports) {
            
            inherit(ScreenUtilPlugin, IFairPlugin);
        }
        __mod__.exports.ScreenUtilPlugin = ScreenUtilPlugin;
    }, []);```
相关推荐
江上清风山间明月1 天前
Flutter开发的应用页面非常多时如何高效管理路由
android·flutter·路由·页面管理·routes·ongenerateroute
Zsnoin能2 天前
flutter国际化、主题配置、视频播放器UI、扫码功能、水波纹问题
flutter
早起的年轻人2 天前
Flutter CupertinoNavigationBar iOS 风格导航栏的组件
flutter·ios
HappyAcmen2 天前
关于Flutter前端面试题及其答案解析
前端·flutter
coooliang2 天前
Flutter 中的单例模式
javascript·flutter·单例模式
coooliang2 天前
Flutter项目中设置安卓启动页
android·flutter
JIngles1232 天前
flutter将utf-8编码的字节序列转换为中英文字符串
java·javascript·flutter
B.-2 天前
在 Flutter 中实现文件读写
开发语言·学习·flutter·android studio·xcode
freflying11192 天前
使用jenkins构建Android+Flutter项目依赖自动升级带来兼容性问题及Jenkins构建速度慢问题解决
android·flutter·jenkins
机器瓦力3 天前
Flutter应用开发:对象存储管理图片
flutter