Flutter 与第三方 Native-SDK 的交互代理方案

这篇具有很好参考价值的文章主要介绍了Flutter 与第三方 Native-SDK 的交互代理方案。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

场景

在使用 Flutter 进行功能模块或者整体项目的开发时,如果需要(阶段性)频繁地和某个第三方 Native-SDK 进行交互,而该 Native-SDK 没有实现 Flutter 插件版本的情况下,如果直接把这部分交互 API 加入到原有的 channel 类里面,会使得该 channel 类变得臃肿,造成代码维护及迭代上的难度;而且,对于一些平常比较少用到的功能,也不需要一上来就初始化 channel-api,占用空间,而是在使用时才初始化,使用后也可以手动清除;

在此提出一种“Flutter 与第三方 Native-SDK 的交互代理方案”,通过一种“代理包装”的方式,尝试较好地解决以上提到的问题;

效果

该方案使用的是 Flutter+Android 进行 demo,全屏 loading、底部灰底 toast 为 Android 端实现,方块 loading、中间黑底 toast 为 Flutter 端实现

Flutter 与第三方 Native-SDK 的交互代理方案

范例

需要使用时才开启 channel,使用结束后关闭 channel 监听

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 端的交互,使用者不需要知道具体交互逻辑,但是在该代理类中,需要保证每次有回调的交互都能正确回调(不管是状态为成功的回调,还是状态为失败的回调)

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 调用 native ------------------------------

  void doSomethingAndListener(DoSomethingCallback callback) {
    _callback = callback;
    _channel.invokeMethod('doSomethingAndListener');
  }

  // ------------------------------ native 调用 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 实例;即该类负责 SDK 能力使用及拓展,而 channel 代理类只负责通讯(发起及监听等)

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 端的交互,使用者不需要知道具体交互逻辑,但是在该代理类中,需要保证每次有回调的交互都能正确回调(不管是状态为成功的回调,还是状态为失败的回调)文章来源地址https://www.toymoban.com/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 调用 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 调用 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)
                }
            })
    }
}

到了这里,关于Flutter 与第三方 Native-SDK 的交互代理方案的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 记录--@click和@click.native有什么区别,如何阻止第三方组件内部的冒泡

    vue @click.native 原生点击事件: 1,给vue组件绑定事件时候,必须加上native ,不然不会生效(监听根元素的原生事件,使用 .native 修饰符) 2,等同于在子组件中: 子组件内部处理click事件然后向外发送click事件: $emit(\\\"click\\\".fn) 不多说看代码: 直接在封装组件上使用@click,看看

    2024年02月10日
    浏览(37)
  • Flutter:第三方常用库整理

    随着Flutter的不断学习,接触了不少第三方的库。因此打算进行简单的整理。 简介 一个强大的Dart/FlutterHTTP客户端,支持全局配置, 拦截器、表单数据、请求取消、文件上传/下载、 超时和自定义适配器等。 官方地址 https://pub-web.flutter-io.cn/packages/dio 简单使用 flutter:网络请求

    2024年02月16日
    浏览(33)
  • Flutter 第三方 flutter_screenutil(屏幕适配)

    推荐一篇写的非常不过的文章:Flutter应用框架搭建(二)屏幕适配 iPhone 12 mini 初始化 - 设置参考尺寸1 ScreenUtilInit 初始化 - 设置方式2 ScreenUtil.init 可以在每个页面设置 使用这种方式只需在使用 flutter_screenutil 前进行初始化即可,一般放在根路由即第一个页面加载的时候进行初始化

    2024年02月19日
    浏览(25)
  • 安卓APP引入第三方SDK如何做安全检测?

    最近听说好多App都被下架处理了,隐私合规管理特别严格。隔壁王老板公司旗下的一款App就被通报了,说是嵌入的第三方SDK违规收集用户个人信息。 还记得,在2021年的315晚会,上海、北京有几家公司都被报道,其SDK均在未经用户授权,窃取用户个人信息。涉案App有 50多款,

    2024年02月05日
    浏览(31)
  • 【第三方SDK接入汇总】Unity接入VuforiaAR(图片识别)

    目录 一.注册Vuforia账号 二.获取许可秘钥 三.获取Vuforia的SDK导入unity 四.搭建创建AR场景 五.打包到手机 注册地址:Engine Developer Portal 申请地址:https://developer.vuforia.com/vui/develop/licenses 方式一: 官网下载 下载地址:SDK Download | Engine Developer Portal  下载后把package包导入unity即可。

    2024年04月08日
    浏览(42)
  • Flutter插件引入第三方jar包之armeabi

    然而我们这个相机厂商只提供 armeabi 架构的包 由于测试机是v8a的架构,而且flutter经过多个版本更新后,不能直接flutter run的时候指定平台架构为32位的,则 无法调用到so文件 ,所以有不小的麻烦。这先按下不表。 首先还是在 plugin/android 的目录新建一个 libs 文件夹,然后将

    2024年04月16日
    浏览(29)
  • Xcode通过Add package自动集成第三方SDK问题汇总

    问题1:  解决方法:这个问题可能是因为 Adjust 或者 Facebook 的库当中依赖的某些类库的仓库地址是 git:// 协议,通过这种协议与 GitHub 通讯时会使用到你的 SSH 配置,你电脑上相关的 ssh key 使用了 GitHub 不再支持的格式,请参考提示中的网址重新生成相关的 SSH key:https://githu

    2024年02月13日
    浏览(27)
  • ESP32工程中CMake使用及加入第三方SDK库文件

            本文中使用的是乐鑫官方推出的 ESP-IDF v5.1 对 ESP32S3 设备开发,并非是Arduino、Micro-python等第三方工具开发。在ESP-IDF框架中,乐鑫官方已经将 CMake 和 Ninja 编译构建工具 集成到了ESP-IDF中。         ESP-IDF 即乐鑫物联网开发框架,可为在 Windows、Linux 和 macOS 系统平台

    2024年02月20日
    浏览(32)
  • Flutter 应用间跳转应用,实现唤起第三方App

    最近因为工作需求,做了应用间跳转应用,因为是一个flutter新手,所以在工作之余随便总结记录一下。 1.使用第三方用户登录,跳转到需授权的App。如QQ登录,微信登录等。需要用户授权,还需要\\\"返回到调用的程序,同时返回授权的用户名、密码\\\"。 2.应用程序推广,跳转到

    2024年02月05日
    浏览(45)
  • vscode配置flutter开发环境,不需要安装第三方安卓模拟器

    点击下方的安装包,获取 stable 发行通道的 Flutter SDK 最新版本:Flutter SDK 将压缩包解压,然后把其中的 flutter 目录整个放在你想放置 Flutter SDK 的路径中**(注意不要出现中文目录)** 配置Windows系统的环境变量,在 用户变量 一栏中,在Path中添加 flutterbin 目录的完整路径。例

    2024年02月10日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包