一、用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

use ./gradlew releaseIOSFramework
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接口。

data class CommonMethodCall(
val method: String,
val arguments: Any?,
) class CommonMethodChannel {
interface Result {
fun success(result: Any?) fun error(errorCode: String?, errorMessage: String?, errorDetails: Any?) fun notImplemented()
}
}

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

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

class CommonCodelabPlugin {

    private val synth = Synth()

    init {
synth?.start()
} fun onMethodCall(call: CommonMethodCall, result: CommonMethodChannel.Result) {
when (call.method) {
"getPlatformVersion" -> {
result.success(Platform().platform)
}
"onKeyDown" -> {
try {
val arguments = call.arguments as List<*>
val numKeysDown = synth?.keyDown((arguments[0] as Int))
result.success(numKeysDown)
} catch (ex: Exception) {
result.error("1", ex.message, ex.cause)
}
}
"onKeyUp" -> {
try {
val arguments = call.arguments as List<*>
val numKeysDown = synth?.keyUp((arguments[0] as Int))
result.success(numKeysDown)
} catch (ex: Exception) {
result.error("1", ex.message, ex.cause)
}
}
else -> {
result.notImplemented()
}
}
}
}

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

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

3、实现平台差异特性

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

expect class Synth() {
fun start() fun keyDown(key: Int): Int fun keyUp(key: Int): Int
} expect class Platform() {
val platform: String
}

4、Android Flutter实现插件KMM接口

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

class PluginCodelabPlugin : FlutterPlugin, MethodCallHandler {
private var channel: MethodChannel? = null
private var commonCodelabPlugin: CommonCodelabPlugin? = null override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
setup(this, flutterPluginBinding.binaryMessenger)
} override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
commonCodelabPlugin?.onMethodCall(
call = CommonMethodCall(call.method, call.arguments),
result = object : CommonMethodChannel.Result {
override fun success(successResult: Any?) {
result.success(successResult)
} override fun error(errorCode: String?, errorMessage: String?, errorDetails: Any?) {
result.error(errorCode, errorMessage, errorDetails)
} override fun notImplemented() {
result.notImplemented()
}
})
} override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
channel?.setMethodCallHandler(null)
} companion object {
private fun setup(plugin: PluginCodelabPlugin, binaryMessenger: BinaryMessenger) {
plugin.channel = MethodChannel(binaryMessenger, PLUGIN_CODE_LAB_CHANNEL)
plugin.channel?.setMethodCallHandler(plugin)
plugin.commonCodelabPlugin = CommonCodelabPlugin()
}
}
}

5、iOS Flutter实现插件KMM接口

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

#import "PluginCodelabPlugin.h"

@implementation PluginCodelabPlugin{
int _numKeysDown;
FlutterResult _flutterResult;
SharedCommonCodelabPlugin* _codelabPlugin;
} - (instancetype)init {
self = [super init];
if (self) {
// create music
_codelabPlugin = [[SharedCommonCodelabPlugin alloc] init];
}
return self;
} - (void)dealloc {
// destroy music
} + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
FlutterMethodChannel* channel = [FlutterMethodChannel
methodChannelWithName: SharedPluginCodeLabKt.PLUGIN_CODE_LAB_CHANNEL
binaryMessenger:[registrar messenger]];
PluginCodelabPlugin* instance = [[PluginCodelabPlugin alloc] init];
[registrar addMethodCallDelegate:instance channel:channel];
} - (void)handleMethodCall:(FlutterMethodCall *)call
result:(FlutterResult)result {
SharedCommonMethodCall *methodCall = [[SharedCommonMethodCall alloc] initWithMethod:call.method arguments:call.arguments];
_flutterResult = result;
[_codelabPlugin onMethodCallCall:methodCall result:self ];
} - (void)errorErrorCode:(NSString * _Nullable)errorCode errorMessage:(NSString * _Nullable)errorMessage errorDetails:(id _Nullable)errorDetails {
NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain code:errorCode.intValue userInfo:@{@"errorMessage":errorMessage, @"errorDetails":errorDetails}];
if (_flutterResult) {
_flutterResult(error);
}
} - (void)notImplemented {
if (_flutterResult) {
_flutterResult(FlutterMethodNotImplemented);
}
} - (void)successResult:(id _Nullable)result {
if (_flutterResult) {
_flutterResult(result);
}
} @end

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

四、参考链接

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

Github项目地址:kmm-flutter-plugin

最新文章

  1. 机器学习&amp;数据挖掘笔记_19(PGM练习三:马尔科夫网络在OCR上的简单应用)
  2. JDK-Logger
  3. Spring的scope=&quot;prototype&quot;属性
  4. cdoj 25 点球大战(penalty) 模拟题
  5. null和空 not null
  6. 关于APlayer播放器在打包安装后提示“没有注册类”的解决办法
  7. 关于安卓的log学习
  8. HoloLens开发手记 - 构建2D应用 Building 2D apps
  9. PHP进程信号处理
  10. spring mvc 总结
  11. Vue非父子级通信
  12. nginx负载均衡精简配置实例
  13. ascii、unicode、utf-8、gbk 区别
  14. tyvj/joyoi 1305 最大子序和
  15. POJ 1222 EXTENDED LIGHTS OUT (熄灯问题)
  16. ldap集成rabbitmq
  17. java中String与StringBuilder的区别
  18. Charles 使用(拦截与修改)
  19. Linux服务器---安装bind
  20. 自己写的jQuery 左右选择框,大家多多指教!

热门文章

  1. es6语法中promise的使用方法
  2. LVS+keepalived集群
  3. 前端框架VUE——安装及初始化
  4. 使用vsCode开发vue项目格式化通用配置
  5. 数据结构与算法——平衡二叉树(AVL树)
  6. c++ if语句讲解&amp;例题
  7. Nacos注册中心和配置中心流程原理
  8. django使用restframework序列化查询集合(querryset)
  9. redis小结 1-2
  10. 深入理解Python切片