58Fair动态页面加载与变量值获取流程解析
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函数返回。
转载自:https://juejin.cn/post/7262913077312618553