Flutter中如何嵌套weex来使用,总的来说跟嵌套原生是一样的,但是也有些需要注意的地方。
原生部分
1.定义show方法,用于flutter调用show方法来加载url
2.这里需要特别注意,需要定义close方法,来关闭销毁weex,如果不销毁,那么Flutter中的用于嵌套的widget的id就会一直增加,永远不销毁,造成的后果就是会创建多个weex页面,会产生不可预测的后果,或者app崩溃。
3.原生通过module来,来调用flutter中的方法。
4.flutter通过通道和通知来实现,flutter调用weex方法。
public class LiveRoomWeexViewFactory : NSObject,FlutterPlatformViewFactory{
public static let SIGN = "LiveRoomWeexView";
private var message : FlutterBinaryMessenger;
init(message : FlutterBinaryMessenger) {
self.message = message;
super.init()
}
public func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView {
return LiveRoomWeexView(frame: frame, viewIdentifier:viewId, binaryMessenger: message)
}
}
public class LiveRoomWeexView : NSObject,FlutterPlatformView{
public var weexView : ZPTRTCWeexView?;
private var channel: FlutterMethodChannel?
init(frame : CGRect, viewIdentifier viewId: Int64, binaryMessenger messenger: FlutterBinaryMessenger) {
self.weexView = ZPTRTCWeexView();
// 绑定方法监听
super.init()
channel = FlutterMethodChannel(
name: "\(LiveRoomWeexViewFactory.SIGN)_\(viewId)",
binaryMessenger: messenger
)
channel?.setMethodCallHandler(handle);
}
public func view() -> UIView {
return weexView!;
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method {
case "show":
self.show(call, result: result);
break;
case "close":
self.close(call, result: result);
break;
default:
result(FlutterMethodNotImplemented);
}
}
private func show(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
if let url = CommonUtils.getParamByKey(call: call, result: result, param: "url") as? String,
let weexUrl = RTCCloudBridge.shared.getWeexUrl(url) {
weexView?.isHideLoading = true
weexView?.weexStatusBlock = { (status) in
switch status {
case .jsDownloadedError:
result(["code": 2, "message": "加载Url失败"]);
break
case .renderFailed:
result(["code": 3, "message": "渲染失败"]);
break
case .renderFinish, .updateFinish, .createView:
result(["code": 0, "message": "成功"]);
break
default:
break
}
}
weexView?.weexHandle = { [weak self] (params, callback) in
self?.channel?.invokeMethod("weexHandle", arguments: params, result: { (result) in
if let resultData = result as? FlutterError,
let details = resultData.details {
callback?(["code": resultData.code == "0" ? 0 : 1, "params": details])
}
})
}
weexView?.url = weexUrl
} else {
result(["code": 1, "message": "清单获取失败"]);
}
}
private func close(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
self.weexView?.removeFromSuperview()
self.weexView = nil
}
}
原生调用flutter
-(void)flutterMethod:(NSDictionary *)params
callback:(WXModuleCallback)callback {
if ([self.weexInstance.rootView.superview isKindOfClass:ZPTRTCWeexView.class]) {
ZPTRTCWeexView *weexView = (ZPTRTCWeexView *)self.weexInstance.rootView.superview;
weexView.weexHandle(params, ^(id _Nullable result) {
callback(result);
});
}
}
flutter调用weex
1.weexView中注册通知。
2.通过建立通道来发送通知
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor clearColor];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(globalEvent:) name:@"TRTCGlobalEvent" object:nil];
}
return self;
}
-(void)globalEvent:(NSNotification *)notification {
NSString *event = notification.userInfo[@"event"];
NSDictionary *params = notification.userInfo[@"params"];
if (event &&
[event isKindOfClass:NSString.class]) {
[self.instance fireGlobalEvent:event params:params ?: @{}];
}
}
private func fireGlobalEvent(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
if let event = CommonUtils.getParamByKey(call: call, result: result, param: "event") as? String,
let params = CommonUtils.getParamByKey(call: call, result: result, param: "params") as? [String: Any] {
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "TRTCGlobalEvent"),
object: nil,
userInfo:["event": event,
"params":params])
}
result(nil);
}
Flutter部分
class LiveRoomWeexView extends StatefulWidget {
/// channel标识符
static String channelType = "LiveRoomWeexView";
final ValueChanged<int>? onViewCreated;
final Set<Factory<OneSequenceGestureRecognizer>>? gestureRecognizers;
const LiveRoomWeexView(
{Key? key, this.onViewCreated, this.gestureRecognizers})
: super(key: key);
@override
State<StatefulWidget> createState() => LiveRoomWeexViewState();
}
//// @nodoc
class LiveRoomWeexViewState extends State<LiveRoomWeexView> {
@override
Widget build(BuildContext context) {
if (Platform.isAndroid) {
return AndroidView(
viewType: LiveRoomWeexView.channelType,
onPlatformViewCreated: _onPlatformViewCreated,
gestureRecognizers: widget.gestureRecognizers,
);
} else if (Platform.isIOS) {
return UiKitView(
viewType: LiveRoomWeexView.channelType,
onPlatformViewCreated: _onPlatformViewCreated,
gestureRecognizers: widget.gestureRecognizers,
);
} else {
return Text("该平台不支持Platform View");
}
}
void _onPlatformViewCreated(int id) {
if (widget.onViewCreated != null) {
widget.onViewCreated!(id);
}
}
}
/// @nodoc
/// Weex页面控制器方法
class LiveRoomWeexViewController {
late final MethodChannel _channel;
LiveRoomWeexViewController(int id) {
// commonEventLog("szfdzf", "LiveRoomWeexViewController create");
_channel = new MethodChannel(LiveRoomWeexView.channelType + '_$id');
_channel.setMethodCallHandler((methodCall) async {
switch (methodCall.method) {
case 'weexHandle':
LiveRoomManager? manager = await LiveRoomManager.sharedInstance();
Map<String, dynamic>? result =
await manager?.onWeexHandle(id, methodCall.arguments);
throw PlatformException(
details: result, code: result == null ? '-1' : '0');
default:
throw MissingPluginException();
}
});
}
LiveRoomWeexViewController.listener(
int id, LiveRoomWeexListener? weexListener) {
_channel = new MethodChannel(LiveRoomWeexView.channelType + '_$id');
_channel.setMethodCallHandler((methodCall) async {
switch (methodCall.method) {
case 'weexHandle':
Map<String, dynamic>? result;
if (weexListener != null) {
result = await weexListener(id, methodCall.arguments);
}
throw PlatformException(
details: result, code: result == null ? '-1' : '0');
default:
throw MissingPluginException();
}
});
}
// 加载weex
Future<Map> show(String url) async {
Map? result = await _channel.invokeMethod('show', {"url": url});
return result ?? {'500': 'fail'};
}
// 销毁weex
Future<void> close() async {
return await _channel.invokeMethod('close');
}
}
通道
static TRTCCloud _trtcCloud;
static const MethodChannel _channel = const MethodChannel('trtcCloudChannel');
static TRTCCloudListenerObj listener;
/// 创建 TRTCCloud 单例。
static Future<TRTCCloud> sharedInstance() async {
if (_trtcCloud == null) {
_trtcCloud = new TRTCCloud();
await _channel.invokeMethod('sharedInstance');
}
return _trtcCloud;
}
/// 销毁 TRTCCloud 单例。
static Future<void> destroySharedInstance() async {
await _channel.invokeMethod('destroySharedInstance');
_trtcCloud = null;
}
/// weex全局通知
Future<void> fireGlobalEvent(String eventName, Map<String, dynamic> params) {
return _channel.invokeMethod(
'fireGlobalEvent', {'event': eventName, 'params': params});
}
记得销毁的方法一定close方法一定要加,对于不管是flutter套原生,还是flutter套weex,close方法都需要加。
这是踩过很多坑才得出的结论。