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