前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Kotlin/Native 用KMM写Flutter插件

Kotlin/Native 用KMM写Flutter插件

原创
作者头像
libill
修改2021-10-29 09:53:29
1.1K0
修改2021-10-29 09:53:29
举报
文章被收录于专栏:libill

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

代码语言:txt
复制
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接口。

代码语言:txt
复制
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逻辑。

代码语言:txt
复制
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()
            }
        }
    }
}

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

代码语言:txt
复制
// 插件Channel名称
const val PLUGIN_CODE_LAB_CHANNEL = "plugin_codelab"
3、实现平台差异特性

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

代码语言:txt
复制
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 数据,不能有任何业务逻辑

代码语言:txt
复制
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 数据,不能有任何业务逻辑

代码语言:txt
复制
#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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、用KMM写Flutter插件
  • 二、如何运行
  • 三、设计思路
    • 1、定义接口中间层用于转发数据
      • 2、在KMM中的commonMain实现CommonCodelabPlugin插件的公共逻辑
        • 3、实现平台差异特性
          • 4、Android Flutter实现插件KMM接口
            • 5、iOS Flutter实现插件KMM接口
            • 四、参考链接
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档