場景
在使用 Flutter 進行功能模塊或者整體項目的開發(fā)時,如果需要(階段性)頻繁地和某個第三方 Native-SDK 進行交互,而該 Native-SDK 沒有實現(xiàn) Flutter 插件版本的情況下,如果直接把這部分交互 API 加入到原有的 channel 類里面,會使得該 channel 類變得臃腫,造成代碼維護及迭代上的難度;而且,對于一些平常比較少用到的功能,也不需要一上來就初始化 channel-api,占用空間,而是在使用時才初始化,使用后也可以手動清除;
在此提出一種“Flutter 與第三方 Native-SDK 的交互代理方案”,通過一種“代理包裝”的方式,嘗試較好地解決以上提到的問題;
效果
該方案使用的是 Flutter+Android 進行 demo,全屏 loading、底部灰底 toast 為 Android 端實現(xiàn),方塊 loading、中間黑底 toast 為 Flutter 端實現(xiàn)
范例
需要使用時才開啟 channel,使用結(jié)束后關(guān)閉 channel 監(jiān)聽
class _TestPageState extends State<TestPage> {
void initState() {
super.initState();
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Channel')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
GestureDetector(
onTap: () => channelTest(),
child: const Text('開啟通道,進行交互'),
),
],
),
),
);
}
Future<void> channelTest() async {
TestChannelProxy? channel = await TestChannelProxy.openChannel();
if (channel != null) {
Function()? cancel;
channel.doSomethingAndListener(DoSomethingCallback(
onTestFirst: (result) {
cancel = MsgUtil.loading(msg: result);
},
onTestSecond: () {
cancel?.call();
},
onTestThird: (result) async {
MsgUtil.toast(result.toString());
return !result;
},
));
}
}
}
代碼(Flutter 端代理類)
維護與 Native 端的交互,使用者不需要知道具體交互邏輯,但是在該代理類中,需要保證每次有回調(diào)的交互都能正確回調(diào)(不管是狀態(tài)為成功的回調(diào),還是狀態(tài)為失敗的回調(diào))
import 'package:flutter/services.dart';
import 'platform_method_channel.dart';
const String _testChannelName = 'zzq.channel.TestChannelProxy';
class TestChannelProxy {
late MethodChannel _channel;
DoSomethingCallback? _callback;
TestChannelProxy._() {
_channel = const MethodChannel(_testChannelName);
_channel.setMethodCallHandler(_handleMethod);
}
/// [return] 為空表示開啟失敗,不為空表示開啟成功
static Future<TestChannelProxy?> openChannel() async {
bool success = await PlatformMethodChannel.getInstance()
.openPlatformChannel(_testChannelName);
return success ? TestChannelProxy._() : null;
}
/*Future<void> closeChannel() async {
await _channel.invokeMethod('closeChannel');
_channel.setMethodCallHandler(null);
}*/
// ------------------------------ flutter 調(diào)用 native ------------------------------
void doSomethingAndListener(DoSomethingCallback callback) {
_callback = callback;
_channel.invokeMethod('doSomethingAndListener');
}
// ------------------------------ native 調(diào)用 flutter ------------------------------
Future _handleMethod(MethodCall call) async {
var args = call.arguments;
switch (call.method) {
case 'getString':
return _getString();
case 'getBoolean':
return _getBoolean();
case 'onTestFirst':
_onTestFirst(args);
break;
case 'onTestSecond':
_onTestSecond();
break;
case 'onTestThird':
return _onTestThird(args);
default:
break;
}
}
Future<String> _getString() async {
await Future.delayed(const Duration(seconds: 2));
return 'String';
}
Future<bool> _getBoolean() async {
await Future.delayed(const Duration(seconds: 2));
return true;
}
void _onTestFirst(String result) {
_callback?.onTestFirst?.call(result);
}
void _onTestSecond() {
_callback?.onTestSecond?.call();
}
Future<bool> _onTestThird(bool result) async {
return (await _callback?.onTestThird?.call(result)) ?? false;
}
}
class DoSomethingCallback {
final Function(String result)? onTestFirst;
final Function()? onTestSecond;
final Future<bool> Function(bool result)? onTestThird;
DoSomethingCallback({
this.onTestFirst,
this.onTestSecond,
this.onTestThird,
});
}
需要在默認/全局的 channel 中定義通用的開啟 channel 的 api,提供代理交互 channel 的開啟能力
/// 開啟 flutter 與 native 端的交互通道,用于使用第三方 native-sdk 的能力
/// 可以是 BasicMessageChannel、MethodChannel、EventChannel
/// [return] 通道是否開啟成功
Future<bool> openPlatformChannel(String channelName) async {
var result = await _channel.invokeMethod('openPlatformChannel', channelName);
return result == true;
}
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
val args = call.arguments
when (call.method) {
"openPlatformChannel" -> openPlatformChannel(args as String, result)
else -> result.notImplemented()
}
}
/**
* 開啟 flutter 與 native 端的交互通道,用于 flutter 端使用第三方 native-sdk 的能力
* 可以是 BasicMessageChannel、MethodChannel、EventChannel
* [result.success] 通道是否開啟成功
*/
private fun openPlatformChannel(channelName: String, result: MethodChannel.Result) {
var success = true
when (channelName) {
TEST_CHANNEL_NAME -> TestTool.openChannel(binaryMessenger)
else -> success = false
}
result.success(success)
}
代碼(Android 端第三方 Native-SDK 包裝類)
該類用于包裝第三方 Native-SDK 所提供的能力,同時持有、維護 Flutter-Android-channel 中在 Android 端的代理 channel 實例;即該類負責(zé) SDK 能力使用及拓展,而 channel 代理類只負責(zé)通訊(發(fā)起及監(jiān)聽等)文章來源:http://www.zghlxwxcb.cn/news/detail-432525.html
import io.flutter.plugin.common.BinaryMessenger
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
object TestTool {
private var testChannelProxy: TestChannelProxy? = null
fun openChannel(messenger: BinaryMessenger) {
if (testChannelProxy == null) {
synchronized(TestTool::class.java) {
if (testChannelProxy == null) {
testChannelProxy = TestChannelProxy(messenger)
}
}
}
}
/*fun closeChannel() {
testChannelProxy = null
}*/
fun doSomethingAndListener() {
DialogManager.showLoading()
testChannelProxy?.getBoolean { it ->
DialogManager.hideLoading()
if (it) {
CoroutineScope(Dispatchers.Main).launch {
delay(2000)
testChannelProxy?.onTestFirst("點了")
delay(2000)
testChannelProxy?.onTestSecond()
delay(2000)
testChannelProxy?.onTestThird(true) {
DialogManager.toast(it.toString())
}
}
}
}
}
}
代碼(Android 端代理類)
維護與 Flutter 端的交互,使用者不需要知道具體交互邏輯,但是在該代理類中,需要保證每次有回調(diào)的交互都能正確回調(diào)(不管是狀態(tài)為成功的回調(diào),還是狀態(tài)為失敗的回調(diào))文章來源地址http://www.zghlxwxcb.cn/news/detail-432525.html
import android.os.Handler
import android.os.Looper
import io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
const val TEST_CHANNEL_NAME = "zzq.channel.TestChannelProxy"
class TestChannelProxy(messenger: BinaryMessenger) : MethodChannel.MethodCallHandler {
private val channel: MethodChannel
init {
channel = MethodChannel(messenger, TEST_CHANNEL_NAME)
channel.setMethodCallHandler(this)
}
// ------------------------------ flutter 調(diào)用 native ------------------------------
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
val args = call.arguments
when (call.method) {
"doSomethingAndListener" -> TestTool.doSomethingAndListener()
else -> result.notImplemented()
}
}
/*fun closeChannel() {
channel.setMethodCallHandler(null)
TestTool.closeChannel()
}*/
// ------------------------------ native 調(diào)用 flutter ------------------------------
/**
* Methods marked with @UiThread must be executed on the main thread. Current thread: AsyncTask
*/
private fun mainInvokeMethod(method: String, arguments: Any?, callback: MethodChannel.Result?) {
if (Looper.myLooper() == Looper.getMainLooper()) {
channel.invokeMethod(method, arguments, callback)
} else {
Handler(Looper.getMainLooper()).post {
channel.invokeMethod(method, arguments, callback)
}
}
}
fun getString(callback: (string: String?) -> Unit) {
mainInvokeMethod(
"getString",
null,
object : MethodChannel.Result {
override fun success(result: Any?) {
callback(if (result is String) result else null)
}
override fun error(code: String, msg: String?, details: Any?) {
callback(null)
}
override fun notImplemented() {
callback(null)
}
})
}
fun getBoolean(callback: (boolean: Boolean) -> Unit) {
mainInvokeMethod(
"getBoolean",
null,
object : MethodChannel.Result {
override fun success(result: Any?) {
callback(result == true)
}
override fun error(code: String, msg: String?, details: Any?) {
callback(false)
}
override fun notImplemented() {
callback(false)
}
})
}
fun onTestFirst(result: String) {
mainInvokeMethod("onTestFirst", result, null)
}
fun onTestSecond() {
mainInvokeMethod("onTestSecond", null, null)
}
fun onTestThird(result: Boolean, callback: (success: Boolean) -> Unit) {
mainInvokeMethod(
"onTestThird",
result,
object : MethodChannel.Result {
override fun success(result: Any?) {
callback(result == true)
}
override fun error(code: String, msg: String?, details: Any?) {
callback(false)
}
override fun notImplemented() {
callback(false)
}
})
}
}
到了這里,關(guān)于Flutter 與第三方 Native-SDK 的交互代理方案的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!