native端完成(iOS)
FlutterBasicMessageChannel channel通道
NSString * const FairMessageChannelExecuteID = @"com.wuba.fair/common_message_channel"; //
self.flutterBasicMessageChannel = [[FlutterBasicMessageChannel alloc] initWithName:FairMessageChannelExecuteID //运用FlutterBasicMessageChannel类型的channel通道
binaryMessenger:self.binaryMessenger
codec:[FlutterStringCodec sharedInstance]];
js调用dart,成果callback回调js
- (void)sendMessageToDart:(NSString *)message callback:(FairCallback)callback {
[self.flutterBasicMessageChannel sendMessage:message reply:^(id reply) { //调用dart
if (callback && FAIR_IS_NOT_EMPTY_STRING(reply)) {//dart回来成果,调用callback
callback(reply, nil);
}
}];
}
- (void)FairExecuteDartFunctionAsync:(NSString *)data callback:(JSValue *)callback
{
[[FairDartBridge sharedInstance] sendMessageToDart:data callback:^(id result, NSError *error) {//调用dart
[[FairJSBridge sharedInstance] invokeJSFunction:callback param:result]; //dart回来成果result,回调js callback
}];
}
通用js办法名界说
通用姓名的js办法界说,js办法名经过channel调用dart,dart履行成果callback 回传js
NSString * const FairExecuteDartFunctionAsync = @"jsInvokeFlutterChannel";
NSString * const FairExecuteDartFunctionSync = @"jsInvokeFlutterChannelSync";
// JS 异步调用 Dart
_context[FairExecuteDartFunctionAsync] = ^(id receiver, JSValue *callback) { //注册js 办法,通用的js办法名
FairStrongObject(strongSelf, weakSelf)
NSString *data = [strongSelf convertStringWithData:receiver];
if ([strongSelf.delegate respondsToSelector:@selector(FairExecuteDartFunctionAsync:callback:)]) {
[strongSelf.delegate FairExecuteDartFunctionAsync:data callback:callback];//js调用dart,成果回调js
}
};
// JS 同步调用 Dart
_context[FairExecuteDartFunctionSync] = ^(id receiver, JSValue *callback) {
FairStrongObject(strongSelf, weakSelf)
NSString *data = [strongSelf convertStringWithData:receiver];
if ([strongSelf.delegate respondsToSelector:@selector(FairExecuteDartFunctionSync: callback:)]) {
[strongSelf.delegate FairExecuteDartFunctionSync:data callback:callback];
}
};
JS端界说
fair_core.js
function setState(pageName, obj) {
console.log('JS:setState()_before' + pageName + '-' + obj);
let p = {};
p['funcName'] = 'setState';
p['pageName'] = pageName;
// console.log('JS:setState(states)'+JSON.stringify(Object.getOwnPropertySymbols(obj)));
obj();
p['args'] = null;
let map = JSON.stringify(p);
console.log('JS:setState()' + map);
invokeFlutterCommonChannel(map);
}
const invokeFlutterCommonChannel = (invokeData, callback) => {
console.log("invokeData" + invokeData)
jsInvokeFlutterChannel(invokeData, (resultStr) => {
console.log('resultStr' + resultStr);
if (callback) {
callback(resultStr);
}
});
};
业务逻辑js文件
GLOBAL['#FairKey#'] = (function(__initProps__) {
const __global__ = this;
return runCallback(function(__mod__) {
///.....省掉
setState('#FairKey#', function dummy() {});
///.....省掉
}
})(convertObjectLiteralToSetOrMap(JSON.parse('#FairProps#')));
逻辑JS文件FairWidget加载
FairWidget烘托界面界说
@override
void didChangeDependencies() {
super.didChangeDependencies();
_fairApp ??= FairApp.of(context);
//加载js的文件地址
_resolveFairRes(_fairApp!, FairJSFairJSDecoderHelper.transformPath(widget.path));
}
加载一切JS逻辑文件
Future<dynamic> _resolveFairRes(FairApp _mFairApp, String? jsPath) async {
final results = await Future.wait([
_mFairApp.runtime.addScript(state2key, resolveJS, widget.data),
_mFairApp.register(this)
]);
}
逻辑JS文件内容加载到内存,进行#FairKey#
和#fairProps#
形式字符串匹配替换,替换成实践的运行时的变量值
@override
Future<dynamic> addScript(String pageName, String scriptSource, dynamic props) async {
// var scriptSource = await rootBundle.loadString(script);
var fairProps;
if (props != null && props['fairProps'] != null) {
fairProps = props['fairProps'];
} else {
fairProps = '{}';
}
if (fairProps is String) {
fairProps = fairProps.replaceAll('\\', '\\\\');
}
scriptSource = scriptSource.replaceFirst(RegExp(r'#FairProps#'), fairProps);
scriptSource = scriptSource.replaceAll(RegExp(r'#FairKey#'), pageName);
var map = <dynamic, dynamic>{};
map[FairMessage.PATH] = scriptSource;
map[FairMessage.PAGE_NAME] = pageName;
return _channel!.loadJS(jsonEncode(map), null);
}
dart端完成
BasicMessageChannel通道注册handler回调,监听native事情调用
final String COMMON_MESSAGE_CHANNEL = 'com.wuba.fair/common_message_channel';
_commonChannel ??=
BasicMessageChannel<String?>(COMMON_MESSAGE_CHANNEL, StringCodec());
_commonChannel!.setMessageHandler((String? message) async { //监听native音讯
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); //履行native音讯,一般便是js调用dart,由js宣布的
return 'reply from dart';
});
callback办法绑定,即经过channel监听到事情后的分发处理
void setMessageHandler(StringMsgCallback callback) {
_callback = callback; //_callback
}
Runtime._internal() {
init(true);
_channel ??= FairMessageChannel();
//接纳setState()的信息
_channel!.setMessageHandler((message) { //_callback ①这个callback其实不会调用的
var data = json.decode(message ?? '');
var className = data['pageName'];
var call = _callBacks[className];
call?.call(message); //
return null;
});
}
另外一种办法callback的绑定
void bindCallback(String key, RuntimeCallback callback) { //_callback
_callBacks[key] = callback;
}
经过FairHandler目标对channel事情音讯进行处理
FairHandler(this._runtime) {
//接纳native发送过来的音讯,实践上是js发送的音讯,经过native端透传过来
_runtime.getChannel().setMessageHandler((String? message) { //callback ②会调用这个callback
var data = json.decode(message ?? '');
var funcName = data['funcName']?.toString();
var pageName = data['pageName'];
var args = data['args']??{};
if (funcName == null || funcName.isEmpty) {
return '';
}
//当用户调用setState的时分相当于改写了数据,告诉改写页更新
if (funcName == 'setState') {
_dispatchMessage(pageName, jsonEncode(args));
return '';
}
// //js 异步调用dart中的相关办法
// if (funcName == 'invokePlugin') {
// FairPluginDispatcher.dispatch(jsonEncode(args))
// .then((value) => _runtime.getChannel().sendCommonMessage(value));
// return '';
// }
return '';
});
}
AppState
每一个fairWidget的FairState状况都在大局AppState中进行管理
mixin AppState {
final modules = FairModuleRegistry();
final bindData = <String, BindingData>{};
final _proxy = ProxyMirror();
final runtime = Runtime(); //这儿一个runtime
final _mFairHandler = FairHandler(Runtime()); //这儿有一个runtime 这是两个不同的runtime目标
}
class FairApp extends InheritedWidget with AppState
Future<dynamic> register(FairState state) async {//每一个FairWidget都会调用
log('register state: ${state.state2key}');
_mFairHandler.register(state); //_mFairHandler 这儿用。内部一个runtime目标逻辑家
var delegate = state.delegate;
delegate.setRunTime(runtime); //这儿运用的runtime目标
// await delegate.bindAll({});
bindData.putIfAbsent(
state.state2key,
() => BindingData(
modules,
functions: delegate.bindFunction(),
values: delegate.bindValue(),
),
);
return Future.value(null);
}
runtime单例目标
经过界说单例目标,channel通道交互都在同一处履行
final runtime = Runtime(); //这儿一个runtime
delegate.setRunTime(runtime); //这儿运用的runtime目标
final _mFairHandler = FairHandler(Runtime()); //这儿也创立一个runtime
FairHandler(this._runtime) {
//接纳native发送过来的音讯,实践上是js发送的音讯,经过native端透传过来
_runtime.getChannel().setMessageHandler((String? message) {
}
}
class Runtime implements IRuntime {
static final Runtime _runtime = Runtime._internal();
factory Runtime() {//结构办法 创立出来的是一个静态大局变量。所以这个runtime目标是一个单例目标
return _runtime;
}
Runtime._internal() {
init(true);
_channel ??= FairMessageChannel();
}
}
FairWidget state setState调用
js如何调用dart setState改写界面?
每一个FairWidget对应的State都有一个stateKey做为键值在大局表中存储
因为runtime dart通道是一个大局目标,这儿面一切的js调用dart端的办法都将在上述所描绘的setMessageHandler音讯处理中分发,那一个页面中一起多个Fairwidget如何找到自己对应的Flutter State目标呢,这便是经过map存储:
咱们先了解到:每一个FairWidget都有一个自己仅有标识 state2key,这个state2key 是由pageName和静态ID自增拼接,防止同一个FairWidget多次运用重复问题。
class FairState extends State<FairWidget> with Loader, AutomaticKeepAliveClientMixin<FairWidget> implements FairMessageCallback<String> {
late String state2key;
@override
void initState() {
super.initState();
state2key = GlobalState.id(widget.name);
}
static String id(String? prefix) {
return '$prefix#${GlobalState._counter++}';
}
String getMessageKey() => state2key;
}
_mFairHandler.register(state);
界说一个map目标pageHistories 存储每一个页面的
class FairHandler {
final pageHistories = <String, FairMessageCallback<String>>{};
final Runtime _runtime;
String _dispatchMessage(String pageName, String message) {
pageHistories[pageName]?.call(message);
return 'Reply from Dart';
}
void register(FairMessageCallback<String> state) {
log('register state: ${state.getMessageKey}');
pageHistories[state.getMessageKey()] = state;
}
void unregister(FairMessageCallback<String> state) {
var key = state.getMessageKey();
log('unregister state: $key');
pageHistories.remove(key);
}
}
FairHandler是一个app等级的目标:
mixin AppState {
final _mFairHandler = FairHandler(Runtime());
Future<dynamic> register(FairState state) async {
_mFairHandler.register(state);
}
}
FairState 完成 FairMessageCallback协议
FairState持有 FairDelegate delegate目标,这个delegate 是Fair运行时一切相关运行时操作的一个封装,其间一个便是调用setState办法。
经过上面的FairHandler的pageHistories这个map表,经过stateKey找到对应state,由state的delegate目标,调用state_state?.setState(fn);办法。
FairMessageCallback 界说:
abstract class FairMessageCallback<T> {
void call(T t);
String getMessageKey();
}
FairState 完成 FairMessageCallback协议:
class FairState extends State<FairWidget> with Loader, AutomaticKeepAliveClientMixin<FairWidget> implements FairMessageCallback<String> {
@override
void call(String t) {
var params={};
try {
params= jsonDecode(t);
} catch (e) {
print(e);
}
delegate.notifyValue(params); //
}
@override
String getMessageKey() => state2key;
void initState() {
super.initState();
state2key = GlobalState.id(widget.name);
delegate = widget.delegate ?? GlobalState.of(widget.name).call(context, widget.data); //获取delegate目标从FairWidget传的或是是FairApp目标中创立的从中获取大局delegate
delegate._bindState(this);//保存当时 Widget state目标d
delegate.initState(); //调用delegate的initState办法 用户可以在FairDelegatec重写一些自界说操作
}
}
FairDelegate 界说:
class FairDelegate extends RuntimeFairDelegate {
FairState? _state;
late String _key;
void _bindState(FairState? state) {
assert(state != null, 'FairState should not be null');
_state = state!;
_key = state.state2key;
}
@override
void setState(VoidCallback fn) {
if (_state == null || !_state!.mounted) return;
// ignore: invalid_use_of_protected_member
_state?.setState(fn); //这儿调用state目标的setState的改写界面
_state?._reload();
}
//获取js端的数据,改写指定数据
void notifyValue(Map values) {
// values.forEach((key, value) {
// _valueMap[key]?.value = value;
// });
setState(() {});
}
}
总结
归纳上面代码分析,咱们就知道了FairWidget烘托完成后,页面中的逻辑部分转换成了js被加载到内存中,当履行js逻辑功用时,经过native端注册的js通用办法姓名的_context[FairExecuteDartFunctionAsync]办法,经过native端FlutterBasicMessageChannel类型的flutterBasicMessageChannel
和dart端类型为BasicMessageChannel
的_commonChannel
调用dart,dart经过音讯监听进行分发,每一个FairWidget对应一个仅有的statekey,每一个state存储到一个FairApp的大局map目标中,当履行setState办法时,js端传入pageName,从大局map中取出state调用其setState办法。这样的一个过程就完成了调用dart端履行setState界面改写的全部流程。