58Fair动态页面加载与变量值获取流程解析

FairWidget加载动态页面

运用FairWidget加载fair 动态页面

FairWidget(name: name, path: path, data: {
   'fairProps': jsonEncode({
     "brokerInfo": {
       "photo":
           "https://img0.baidu.com/it/u=1223276832,3092894484&fm=253&fmt=auto&app=138&f=JPEG?w=666&h=500"
     }
   })
 });

原Widget页面

原widget页面:


import 'package:fair/fair.dart';
import 'package:flutter/material.dart';
@FairPatch()
class FairBrokerDetail extends StatefulWidget {
  const FairBrokerDetail({Key? key}) : super(key: key);
  @override
  State<FairBrokerDetail> createState() => _FairBrokerDetailState();
}
class _FairBrokerDetailState extends State<FairBrokerDetail> {
  @FairProps()
  var data;
  var brokerInfo;
  var photo;
  void onLoad() {
    brokerInfo = data['brokerInfo'];
    photo = brokerInfo.photo;
  }
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Padding(
        padding: EdgeInsets.only(top: 3),
        child: Image.network(
          photo,
          width: 72.0,
          height: 85.0,
          fit: BoxFit.cover,
        ),
      ),
    );
  }
}

页面转化为的json 文件:

widget json

{
  "className": "Scaffold",
  "na": {
    "body": {
      "className": "Container",
      "na": {
        "child": {
          "className": "Center",
          "na": {
            "child": {
              "className": "Image.network",
              "pa": [
                "^(photo)"
              ],
              "na": {
                "width": 300.0,
                "height": 300.0,
                "fit": "#(BoxFit.cover)"
              }
            }
          }
        }
      }
    }
  },
  "methodMap": {}
}

页面解析

^(photo) 将会解析为变量:

  dynamic bindRuntimeValueOf(String name) {
    // _delegateValues优先级高于JS,如果要运用JS的变量,需求重命名变量
    if (_values?[name] == null) {
      var result = _functions?['runtimeParseVar']?.call({name: ''});
      var value = jsonDecode(result);
      if (value['result'][name] != null) {
        return value['result'][name];
      }
    } else {
      if (_values != null && _values?[name] != null) {
        return Function.apply(_values![name]!, null);
      }
    }
    return null;
  }

页面中的变量解析

解析页面:

解析变量

解析为变量,经过dart-ffi通道发送音讯到native,有native 去履行 js办法

经过运行 runtimeParseVar 办法
runtimeParseVar 是一个 dart 办法
完成如下:

_bindFunctionsMap['runtimeParseVar'] = (varNames) {
   return runtime?.variablesSync(pageName, varNames);
};

经过runtime运行时, 调用channel

参数为:

{
    "pageName":"lib_test_fair_fair_broker_detail#0",
    "type":"variable",
    "args":{
        "photo":""
    }
}

dart 调用channel通道由native转发去运行js逻辑

String variablesSync(String pageName, Map<dynamic, dynamic> variableNames) {
 var msg = FairMessage(pageName, FairMessage.VARIABLE, variableNames);
 var from = msg.from();
 return _channel!.sendCommonMessageSync(jsonEncode(from));
}
dynamic sendCommonMessageSync(dynamic msg) =>
   FairUtf8.fromUtf8(invokeJSCommonFuncSync.call(FairUtf8.toUtf8(msg)));
Pointer<Utf8> Function(Pointer<Utf8>) invokeJSCommonFuncSync = dl
   .lookup<NativeFunction<Pointer<Utf8> Function(Pointer<Utf8>)>>(
       'invokeJSCommonFuncSync')
   .asFunction();

发送音讯到native

native端这儿经过dart-ffi对应c函数,c函数跳转到native oc delegate办法:

const char *invokeJSCommonFuncSync(char *args) {
    if ([FairDynamicFlutter sharedInstance].delegate &&
        [[FairDynamicFlutter sharedInstance].delegate respondsToSelector:@selector(executeScriptSyncImpl:)]) {
        return [[FairDynamicFlutter sharedInstance].delegate executeScriptSyncImpl:args];
    }
    return "";
}

native delegate完成为:

- (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);
    return result.UTF8String;
}

这儿functionName就是上一步的FairExecuteJSFunction
为 invokeJSFunc

/// 同步履行JS
- (JSValue *)executeJSFunctionSync:(NSString *)functionName params:(NSArray *)params {
    return [[FairJSBridge sharedInstance] invokeJSFunctionSync:functionName params:params];
}
- (JSValue *)invokeJSFunctionSync:(NSString *)functionName params:(NSArray *)params
{
    return [self invokeJSFunctionOnJSThread:functionName params:params callback:nil];
}

到这儿就转为 办法名字为 invokeJSFunc

参数为

{
    "pageName":"lib_test_fair_fair_broker_detail#0",
    "type":"variable",
    "args":{
        "photo":""
    }
}
- (JSValue *)invokeJSFunctionOnJSThread:(NSString *)functionName params:(NSArray *)params callback:(FairCallback)callback
{
    JSValue *jsValue = self.context[functionName];
    JSValue *value = [jsValue callWithArguments:params];
    if (callback) {
        callback(value, nil);
    }
    return value;
}

这个js 办法 再 fair_core.js中界说了:

function invokeJSFunc(parameter) {
    if (parameter === null) {
        return null;
    }
    let map = JSON.parse(parameter);
    if ('method' === map['type']) {
        return _invokeMethod(map);
    } else if ('variable' === map['type']) {
        return _invokeVariable(map);
    }
    return null;
}
function _invokeVariable(par) {
    console.log('_invokeVariable' + JSON.stringify(par));
    let pName = par['pageName'];
    let varMap = par['args'];
    let curPage = GLOBAL[pName];
    let callResult = {
        pageName: pName,
        result: {}
    };
    if (!isNull(varMap) && Object.keys(varMap).length > 0) {
        Object.keys(varMap).forEach(function (varKey) {
            callResult['result'][varKey] = eval('curPage.' + varKey.toString());
        });
        return JSON.stringify(callResult);
    }
    //如果没有传参数,默认回来悉数的变量以及成果值
    Object.keys(curPage).forEach(function (key) {
        if (!isFunc(curPage[key])) {
            callResult['result'][key] = eval('curPage.' + key.toString());
        }
    });
    return JSON.stringify(callResult);
}

这样就履行到js 逻辑中去

页面生成js 业务逻辑文件为:

GLOBAL['#FairKey#'] = (function(__initProps__) {
    const __global__ = this;
    return runCallback(function(__mod__) {
        with(__mod__.imports) {
            function _FairBrokerDetailState() {
                const inner = _FairBrokerDetailState.__inner__;
                if (this == __global__) {
                    return new _FairBrokerDetailState({
                        __args__: arguments
                    });
                } else {
                    const args = arguments.length > 0 ? arguments[0].__args__ || arguments: [];
                    inner.apply(this, args);
                    _FairBrokerDetailState.prototype.ctor.apply(this, args);
                    return this;
                }
            }
            _FairBrokerDetailState.__inner__ = function inner() {
                this.data = __initProps__;
                this.brokerInfo = null;
                this.photo = null;
            };
            _FairBrokerDetailState.prototype = {
                onLoad: function onLoad() {
                    const __thiz__ = this;
                    with(__thiz__) {
                        brokerInfo = data.__op_idx__('brokerInfo');
                        photo = brokerInfo.photo;
                    }
                },
            };
            _FairBrokerDetailState.prototype.ctor = function() {};;
            return _FairBrokerDetailState();
        }
    },
    []);
})(convertObjectLiteralToSetOrMap(JSON.parse('#FairProps#')));

这儿界说了 经过fair compiler将原页面转化为js逻辑代码。履行js里边的逻辑办法。经过js获取变量值。
回来给dart端 FairWidget加载解析过程中,完成了变量的赋值。

总结

  • fair build工具将页面转化为json,bin和js文件。其间变量转化为js逻辑文件中js变量,对应变量的运用在json文件中的模式为^(photo)这种格局字符串。
  • 在FairWidge添加在中运用runtime,runtime是封装了native-dart通讯的通道。这个channel是总channel,包括 BasicMessageChannel、MethodChannel、MethodChannel 以及一个dart-ffi的函数指针 invokeJSCommonFuncSync
  • FairWidget解析json加载js逻辑,烘托页面过程中,dart 调用channel 同步办法 sendCommonMessageSync 去调用native,经过dart-ffi由native去调用加载好的js别离经过fair_core.js中心文件中的通用js办法 invokeJSFunc,然后经过参数type是method和 variable 来别离调用对应js办法。如果是variable则直接经过从js逻辑中获取到变量值,同步履行成果dart-ffi函数回来。