Flutter 页面放原生 view

将 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)
}
}

/**
* 用于返回Native View,这个View会被嵌入到Flutter的视图结构中
*/
override fun getView(): View {
return videoView
}

/**
* 当Flutter要决定销毁PlatformView时会调用这个方法,
* 通常在Flutter的一个widget销毁时调用,我们可以在这个方法中做一些资源释放的工作
*/
override fun dispose() {
BookLogger.i("FlutterCacheManager", "dispose")
methodChannel?.setMethodCallHandler(null)
methodChannel=null
}

//通信flutter调用原生
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 {

/**
* 需要在创建Flutter引擎的时候去注册(重要)
*/
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");
}

///来自native view的调用
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");
}

Flutter 页面放原生 view
http://peiniwan.github.io/2024/04/366b13ca51aa.html
作者
六月的雨
发布于
2024年4月6日
许可协议