native端实现(iOS)
FlutterBasicMessageChannel channel通道
ini
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
objectivec
- (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
less
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
javascript
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文件
javascript
GLOBAL['#FairKey#'] = (function(__initProps__) {
const __global__ = this;
return runCallback(function(__mod__) {
///.....省略
setState('#FairKey#', function dummy() {});
///.....省略
}
})(convertObjectLiteralToSetOrMap(JSON.parse('#FairProps#')));
逻辑JS文件FairWidget加载
FairWidget渲染界面定义
scss
@override
void didChangeDependencies() {
super.didChangeDependencies();
_fairApp ??= FairApp.of(context);
//加载js的文件地址
_resolveFairRes(_fairApp!, FairJSFairJSDecoderHelper.transformPath(widget.path));
}
加载所有JS逻辑文件
dart
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#
模式字符串匹配替换,替换成实际的运行时的变量值
python
@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事件调用
ini
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监听到事件后的分发处理
ini
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事件消息进行处理
kotlin
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中进行管理
scala
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通道交互都在同一处执行
scss
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多次使用重复问题。
scala
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 存储每一个页面的
javascript
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级别的对象:
scss
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 定义:
csharp
abstract class FairMessageCallback<T> {
void call(T t);
String getMessageKey();
}
FairState 实现 FairMessageCallback协议:
scala
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 定义:
typescript
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界面刷新的全部流程。