一、用KMM写Flutter插件

Google官方有一个写Flutter例子How to write a Flutter plugin,这里把Google plugin_codelab 例子改成用KMM写Flutter插件。

二、如何运行

Github项目地址:kmm-flutter-plugin

Android: run shared/plugin_codelab/example/android

iOS:

1、build shared.framework

  1. use ./gradlew releaseIOSFramework
  2. or use new version Android Studio sync

2、run shared/plugin_codelab/example/ios

Tips: before run,shared/build/cocoapods/framework/shared.framework should be generated. The shared.h header file shared/build/cocoapods/framework/shared.framework/Headers/shared.h is generated.

三、设计思路

Android/iOS插件PluginCodelabPlugin只需要实现KMM Module的接口,不写任何逻辑,把逻辑通过接口放在KMM Module中。

1、定义接口中间层用于转发数据

如参考Flutter插件的MethodCall、MethodChannel,定义CommonMethodCall数据类、CommonMethodChannel.Result接口。

  1. data class CommonMethodCall(
  2. val method: String,
  3. val arguments: Any?,
  4. )
  5. class CommonMethodChannel {
  6. interface Result {
  7. fun success(result: Any?)
  8. fun error(errorCode: String?, errorMessage: String?, errorDetails: Any?)
  9. fun notImplemented()
  10. }
  11. }

2、在KMM中的commonMain实现CommonCodelabPlugin插件的公共逻辑

CommonCodelabPlugin需要初始化并启动synth?.start(),处理getPlatformVersion、onKeyDown、onKeyUp逻辑。

  1. class CommonCodelabPlugin {
  2. private val synth = Synth()
  3. init {
  4. synth?.start()
  5. }
  6. fun onMethodCall(call: CommonMethodCall, result: CommonMethodChannel.Result) {
  7. when (call.method) {
  8. "getPlatformVersion" -> {
  9. result.success(Platform().platform)
  10. }
  11. "onKeyDown" -> {
  12. try {
  13. val arguments = call.arguments as List<*>
  14. val numKeysDown = synth?.keyDown((arguments[0] as Int))
  15. result.success(numKeysDown)
  16. } catch (ex: Exception) {
  17. result.error("1", ex.message, ex.cause)
  18. }
  19. }
  20. "onKeyUp" -> {
  21. try {
  22. val arguments = call.arguments as List<*>
  23. val numKeysDown = synth?.keyUp((arguments[0] as Int))
  24. result.success(numKeysDown)
  25. } catch (ex: Exception) {
  26. result.error("1", ex.message, ex.cause)
  27. }
  28. }
  29. else -> {
  30. result.notImplemented()
  31. }
  32. }
  33. }
  34. }

还有包括插件名称也属于公共逻辑

  1. // 插件Channel名称
  2. const val PLUGIN_CODE_LAB_CHANNEL = "plugin_codelab"

3、实现平台差异特性

这里只列出expect接口,具体实现平台差异特性类请查看源码

  1. expect class Synth() {
  2. fun start()
  3. fun keyDown(key: Int): Int
  4. fun keyUp(key: Int): Int
  5. }
  6. expect class Platform() {
  7. val platform: String
  8. }

4、Android Flutter实现插件KMM接口

Android Flutter实现插件KMM接口,注意这里只实现接口用于中转Flutter与Android/iOS 数据,不能有任何业务逻辑

  1. class PluginCodelabPlugin : FlutterPlugin, MethodCallHandler {
  2. private var channel: MethodChannel? = null
  3. private var commonCodelabPlugin: CommonCodelabPlugin? = null
  4. override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
  5. setup(this, flutterPluginBinding.binaryMessenger)
  6. }
  7. override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
  8. commonCodelabPlugin?.onMethodCall(
  9. call = CommonMethodCall(call.method, call.arguments),
  10. result = object : CommonMethodChannel.Result {
  11. override fun success(successResult: Any?) {
  12. result.success(successResult)
  13. }
  14. override fun error(errorCode: String?, errorMessage: String?, errorDetails: Any?) {
  15. result.error(errorCode, errorMessage, errorDetails)
  16. }
  17. override fun notImplemented() {
  18. result.notImplemented()
  19. }
  20. })
  21. }
  22. override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
  23. channel?.setMethodCallHandler(null)
  24. }
  25. companion object {
  26. private fun setup(plugin: PluginCodelabPlugin, binaryMessenger: BinaryMessenger) {
  27. plugin.channel = MethodChannel(binaryMessenger, PLUGIN_CODE_LAB_CHANNEL)
  28. plugin.channel?.setMethodCallHandler(plugin)
  29. plugin.commonCodelabPlugin = CommonCodelabPlugin()
  30. }
  31. }
  32. }

5、iOS Flutter实现插件KMM接口

Android Flutter实现插件KMM接口,注意这里只实现接口用于中转Flutter与Android/iOS 数据,不能有任何业务逻辑

  1. #import "PluginCodelabPlugin.h"
  2. @implementation PluginCodelabPlugin{
  3. int _numKeysDown;
  4. FlutterResult _flutterResult;
  5. SharedCommonCodelabPlugin* _codelabPlugin;
  6. }
  7. - (instancetype)init {
  8. self = [super init];
  9. if (self) {
  10. // create music
  11. _codelabPlugin = [[SharedCommonCodelabPlugin alloc] init];
  12. }
  13. return self;
  14. }
  15. - (void)dealloc {
  16. // destroy music
  17. }
  18. + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
  19. FlutterMethodChannel* channel = [FlutterMethodChannel
  20. methodChannelWithName: SharedPluginCodeLabKt.PLUGIN_CODE_LAB_CHANNEL
  21. binaryMessenger:[registrar messenger]];
  22. PluginCodelabPlugin* instance = [[PluginCodelabPlugin alloc] init];
  23. [registrar addMethodCallDelegate:instance channel:channel];
  24. }
  25. - (void)handleMethodCall:(FlutterMethodCall *)call
  26. result:(FlutterResult)result {
  27. SharedCommonMethodCall *methodCall = [[SharedCommonMethodCall alloc] initWithMethod:call.method arguments:call.arguments];
  28. _flutterResult = result;
  29. [_codelabPlugin onMethodCallCall:methodCall result:self ];
  30. }
  31. - (void)errorErrorCode:(NSString * _Nullable)errorCode errorMessage:(NSString * _Nullable)errorMessage errorDetails:(id _Nullable)errorDetails {
  32. NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain code:errorCode.intValue userInfo:@{@"errorMessage":errorMessage, @"errorDetails":errorDetails}];
  33. if (_flutterResult) {
  34. _flutterResult(error);
  35. }
  36. }
  37. - (void)notImplemented {
  38. if (_flutterResult) {
  39. _flutterResult(FlutterMethodNotImplemented);
  40. }
  41. }
  42. - (void)successResult:(id _Nullable)result {
  43. if (_flutterResult) {
  44. _flutterResult(result);
  45. }
  46. }
  47. @end

到这里,已经完成了使用KMM开发一个Flutter插件。使用KMM开发插件的好处是公共逻辑都使用kotlin写,一般公共逻辑比较简单适合使用kotlin写,便于维护。而且,实现了KMM写插件,Flutter写UI。

四、参考链接

本文地址:https://www.cnblogs.com/liqw/p/15477079.html

Github项目地址:kmm-flutter-plugin

Kotlin/Native 用KMM写Flutter插件的更多相关文章

  1. Kotlin/Native KMM项目架构

    一.什么是KMM? Kotlin Multiplatform Mobile ( KMM ) 是一个 SDK,旨在简化跨平台移动应用程序的创建.在 KMM 的帮助下,您可以在 iOS 和 Android ...

  2. 移动端跨平台方案对比:React Native、weex、Flutter

    跨平台一直是老生常谈的话题,cordova.ionic.react-native.weex.kotlin-native.flutter等跨平台框架百花齐放,颇有一股推倒原生开发者的势头. 为什么我们需 ...

  3. 最火移动端跨平台方案盘点:React Native、weex、Flutter

    1.前言 跨平台一直是老生常谈的话题,cordova.ionic.react-native.weex.kotlin-native.flutter等跨平台框架的百花齐放,颇有一股推倒原生开发者的势头. ...

  4. Flutter实战:手把手教你写Flutter Plugin

    前言 如果你对移动端有所关注,那么你一定会听说过Flutter.得益于Google,Flutter一经推出便得受到了广泛关注.很多开发者跃跃欲试,国内部分大厂,诸如美团.闲鱼等团队已经开始了Flutt ...

  5. Flutter学习(9)——Flutter插件实现(Flutter调用Android原生

    原文地址: Flutter学习(9)--Flutter插件实现(Flutter调用Android原生) | Stars-One的杂货小窝 最近需要给一个Flutter项目加个apk完整性检测,需要去拿 ...

  6. 自己写jquery插件之模版插件高级篇(一)

    需求场景 最近项目改版中,发现很多地方有这样一个操作(见下图gif动画演示),很多地方都有用到.这里不讨论它的用户体验怎么样. 仅仅是从复用的角度,如果每个页面都去写text和select元素,两个b ...

  7. 锋利的jQuery--编写jQuery插件(读书笔记五)[完结篇]

    1.表单验证插件Validation   2.表单插件Form   3.动态事件绑定插件livequery 可以为后来的元素绑定事件   类似于jQuery中的live()方法     4.jQuer ...

  8. 什么?你还不会写JQuery 插件

    前言 如今做web开发,jquery 几乎是必不可少的,就连vs神器在2010版本开始将Jquery 及ui 内置web项目里了.至于使用jquery好处这里就不再赘述了,用过的都知道.今天我们来讨论 ...

  9. 写JQuery 插件 什么?你还不会写JQuery 插件

    http://www.cnblogs.com/Leo_wl/p/3409083.html 前言 如今做web开发,jquery 几乎是必不可少的,就连vs神器在2010版本开始将Jquery 及ui ...

随机推荐

  1. Nginx优化与防盗链

    目录: 一.隐藏版本号 二.修改用户与组 三.缓存时间 四.日志切割 五.连接超时 六.更改进程数 七.配置网页压缩 一.隐藏版本号 可以使用 Fiddler 工具抓取数据包,查看 Nginx版本 也 ...

  2. 记录一次sql注入绕过

    目标:http://www.xxxxx.net/temp.asp?ID=10359 通过 and 1=1 and 1=2 测试发现存在拦截 首先想到 and 空格 = 可能存在触发规则 一般遇到这种情 ...

  3. python中时间处理标准库DateTime加强版库:pendulum

    DateTime 的时区问题 Python的datetime可以处理2种类型的时间,分别为offset-naive和offset-aware.前者是指没有包含时区信息的时间,后者是指包含时区信息的时间 ...

  4. WPF 通过进程实现异常隔离的客户端

    当 WPF 客户端需要实现插件系统的时候,一般可以基于容器或者进程来实现.如果需要对外部插件实现异常隔离,那么只能使用子进程来加载插件,这样插件如果抛出异常,也不会影响到主进程.WPF 元素无法跨进程 ...

  5. error: subscripted value is neither array nor pointer问题解决

    在运行程序的时候报错:error: subscripted value is neither array nor pointer 原因分析:下标值不符合数组或指针要求,即操作的对象不允许有下标值. 出 ...

  6. 美团分布式定时调度框架XXL-Job基本使用

    一:XXL JOB 基本使用 1.官方中文文档:https://www.xuxueli.com/xxl-job/ 2.基本环境: 2.1:git下载项目, 执行xxl-job数据库初始化脚本 2.2: ...

  7. Orchard Core入门配方和主题

    包含Orchard Core入门配方和主题 可以通过两个不同的NuGet包使用Orchard Core. OrchardCore.Application.Cms.Core.Targets Orchar ...

  8. Java面向对象系列(10)- 什么是多态

    多态 即同一方法可以根据发送对象的不同而采取不同的行为方式 一个对象的实际类型是确定的,但可以指向对象的引用类型有很多 多态存在的条件 有继承关系 子类重写父类方法 父类引用指向子类对象 注意:多态是 ...

  9. Flutter 对状态管理的认知与思考

    前言 由 编程技术交流圣地[-Flutter群-] 发起的 状态管理研究小组,将就 状态管理 相关话题进行为期 两个月 的讨论. 目前只有内定的 5 个人参与讨论,如果你对 状态管理 有什么独特的见解 ...

  10. Jenkins启动配置

    http://172.17.0.1:8081/