将 Native UI 嵌入到 Flutter 中去使用, 需要准备四步
第一步
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
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() } } } }
|
第三步
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"); }
|