通信
Flutter 是如何与原生 Android、iOS 进行通信的?
Flutter 通过 PlatformChannel 与原生进行交互,其中 PlatformChannel 分为三种:
BasicMessageChannel :用于传递字符串和半结构化的信息。
MethodChannel :用于传递方法调用(method invocation)。
EventChannel : 用于数据流(event streams)的通信。
将 Flutter 集成到现有应用
Flutter 与 Android 的相互通信
可以从 Native 层调用 flutter 层的 dart 代码,也可以在 flutter 层调用 Native 的代码,而作为通讯桥梁就是 MethodChannel,这个类在初始化的时候需要注册一个渠道值。
这个值必须是唯一的,并且在使用到的 Native 层和 Flutter 层互相对应。
flutter 调用 Android
注册
1
| static const nativeChannel =const MethodChannel('com.example.flutter/native');
|
flutter
1 2
| Map<String, dynamic> result = {'message': '我从Flutter页面回来了'}; nativeChannel.invokeMethod('goBackWithResult', result);
|
Android
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| MethodChannel nativeChannel = new MethodChannel(flutterEngine.getDartExecutor(), CHANNEL_NATIVE); nativeChannel.setMethodCallHandler((methodCall, result) -> { switch (methodCall.method) { //回调 case "goBackWithResult": // 返回上一页,携带数据 ActivityManager.getInstance().finishActivity(FlutterActivity.class); Toast.makeText(this, (String) methodCall.argument("message"), Toast.LENGTH_SHORT).show(); break; case "getSendParams": result.success(getSendParams()); break; default: result.notImplemented(); break; } });
|
异步
1 2 3 4 5
| Future getSendParams() async { String params = await _SendFeedBackState.nativeChannel .invokeMethod('getSendParams', ""); print("getSendParams:" + params); }
|
Android 调用 flutter
Android
1 2 3 4 5
| Map<String, Object> result = new HashMap<>(); result.put("message", message);
MethodChannel flutterChannel = new MethodChannel(flutterEngine.getDartExecutor(), CHANNEL_FLUTTER); flutterChannel.invokeMethod("onActivityResult", result);
|
flutter
setMethodCallHandler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| @override void initState() { super.initState(); Future<dynamic> handler(MethodCall call) async { switch (call.method) { case 'onActivityResult': Fluttertoast.showToast( msg: call.arguments['message'], toastLength: Toast.LENGTH_SHORT, ); break; case 'goBack': if (Navigator.canPop(context)) { Navigator.of(context).pop(); } else { nativeChannel.invokeMethod('goBack'); } break; } } flutterChannel.setMethodCallHandler(handler); }
|
Flutter 页面放原生 view
将 Native UI 嵌入到 Flutter 中去使用, 需要准备四步
第一步
自定义 view
FVideoView , 要嵌入到 Flutter 的 iOS view 或者 Android view
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
| class FVideoView @JvmOverloads constructor( context: Context? = ContextManager.getContext(), attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : LinearLayout(context!!, attrs, defStyleAttr), DefaultLifecycleObserver { var flVideoView: FrameLayout? = null private val TAG = this.javaClass.simpleName private var currentVideoData: BookVideoLiteManager.VideoPlayerData? = null
init { BookLogger.i(TAG, "FVideoView--init") LayoutInflater.from(context).inflate(R.layout.flutter_video_view, this, true) flVideoView = findViewById(R.id.flVideoView)
if (context != null && context is FragmentActivity) { context.lifecycle.addObserver(this) } }
private fun initCurrentVideoData(fVideoPlayBean: FVideoPlayBean) { fVideoPlayBean.run { val module = if (module == 1) { BookVpDataSource.Module.VIP_MODULE } else { BookVpDataSource.Module.STUDY_MODULE } val playerType = if (playerType == 1) { BookVpPlayerTypeMode.ALI_YUN } else { BookVpPlayerTypeMode.PS_MEDIA } currentVideoData = BookVideoLiteManager .VideoPlayerData(WeakReference(flVideoView)) .setModule(module) .setBusinessType(businessType ?: 0) .setUrlType(BookVpDataSource.URL_TYPE_FID) .setPlayerType(playerType) .setFid(fid ?: "") .setScaleMode(BookVpScaleMode.SCALE_ASPECT_FIT) .setBusinessSensorMap(mutableMapOf()) .setIsVideoNoWifiPlay(true) } }
fun startPlay(json: String?) { val fVideoPlayBean = GsonUtil.getInstance().fromJson(json, FVideoPlayBean::class.java) initCurrentVideoData(fVideoPlayBean) resumePlay() }
fun pausePlay() { if(currentVideoData!=null){ BookVideoLiteManager.getInstance().videoPlayerPause(currentVideoData) } }
fun resumePlay() { if (currentVideoData != null) { BookVideoLiteManager.getInstance().videoPlayerResume(currentVideoData) } }
fun releasePlay() { BookVideoLiteManager.getInstance().videoPlayerRelease(currentVideoData) currentVideoData = null }
override fun onCreate(owner: LifecycleOwner) { super.onCreate(owner) BookLogger.i(TAG, "FVideoView--onCreate") }
override fun onPause(owner: LifecycleOwner) { pausePlay() super.onPause(owner) BookLogger.i(TAG, "FVideoView--onPause") }
override fun onStop(owner: LifecycleOwner) { super.onStop(owner) BookLogger.i(TAG, "FVideoView--onStop") }
override fun onResume(owner: LifecycleOwner) { super.onResume(owner) resumePlay() BookLogger.i(TAG, "FVideoView--onResume") }
override fun onDestroy(owner: LifecycleOwner) { releasePlay() super.onDestroy(owner) BookLogger.i(TAG, "FVideoView--onDestroy") if (context != null && context is FragmentActivity) { (context as FragmentActivity).lifecycle.removeObserver(this) } }
}
|
第二步
FVideoViewController , FVideoView 的控制器, 用来创建和管理 FVideoView
继承 PlatformView、MethodChannel
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| class FVideoViewController(context: Context?, messenger: BinaryMessenger, id: Int?, args: Any?) : PlatformView, MethodChannel.MethodCallHandler {
private var videoView: FVideoView = FVideoView(context) private var methodChannel: MethodChannel?=null
init { BookLogger.i("FlutterCacheManager", "FVideoViewController")
methodChannel = MethodChannel(messenger, "FVideoView_$id") methodChannel?.setMethodCallHandler(this) if (args!=null && args is String) { videoView.startPlay(args) } }
override fun getView(): View { return videoView }
override fun dispose() { BookLogger.i("FlutterCacheManager", "dispose") methodChannel?.setMethodCallHandler(null) methodChannel=null }
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { when (call.method) { "startPlay"->{ videoView.startPlay(call.arguments as? String) } "pausePlay"->{ videoView.pausePlay() } "resumePlay"->{ videoView.resumePlay() } "releasePlay"->{ videoView.releasePlay() } else -> { result.notImplemented() } } } }
|
第三步
继承 PlatformViewFactory,FVideoViewFactory , 用于向 Flutter 提供 FVideoView
1 2 3 4 5 6 7 8 9 10
| class FVideoViewFactory (private val messenger: BinaryMessenger) : PlatformViewFactory(StandardMessageCodec.INSTANCE) {
override fun create(context: Context?, viewId: Int, args: Any?): PlatformView { BookLogger.i("FlutterCacheManager", "FVideoViewFactory") return FVideoViewController(context, messenger, viewId, args) }
}
|
第四步
FVideoViewPlugin , 用于向 Flutter 注册 FVideoView
1 2 3 4 5 6 7 8 9 10 11 12
| class FVideoViewPlugin {
fun registerWith(flutterEngine: FlutterEngine) { flutterEngine.platformViewsController.registry.registerViewFactory( "FVideoView", FVideoViewFactory(flutterEngine.dartExecutor.binaryMessenger) ) } }
|
FVideoViewPlugin().registerWith(flutterEngine)
Flutter 注册
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| class FVideoViewController { late MethodChannel _channel;
FVideoViewController(int id) { _channel = MethodChannel("FVideoView_$id"); _channel.setMethodCallHandler(_handleMethod); tallog("FVideoViewController---$id"); }
Future<dynamic> _handleMethod(MethodCall call) async { switch (call.method) { case "method name": var text = call.arguments as String; return new Future.value("Text from native:$text"); } }
Future<void> startPlay() async { try { var map = { "fid": "VE_E8kdxv", "businessType": 1, "playerType": 0, "module": 1, }; await _channel.invokeMethod("startPlay", jsonEncode(map)); } on PlatformException catch (e) { tallog(e.message); } }
Future<void> pausePlay() async { try { await _channel.invokeMethod("pausePlay"); } on PlatformException catch (e) { tallog(e.message); } }
Future<void> resumePlay() async { try { await _channel.invokeMethod("resumePlay"); } on PlatformException catch (e) { tallog(e.message); } }
Future<void> releasePlay() async { try { await _channel.invokeMethod("releasePlay"); } on PlatformException catch (e) { tallog(e.message); } } }
|
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| Widget getPlatformView(TestVideoLogic logic, MaterialColor color) { if (Platform.isAndroid) { return Column( children: [ Container( color: color, child: SizedBox( height: 200, child: AndroidView( viewType: "FVideoView", creationParams: null, creationParamsCodec: StandardMessageCodec(), onPlatformViewCreated: (id) { var controller = FVideoViewController(id); logic.controller = controller; logic.startPlay(); }, ), ), ), ], ); } else { return UiKitView(viewType: "FVideoView"); }
|