Kotlin / native uses KMM to write fluent plug-ins
Google officially has an example of how to write a shuttle plugin. Here, Google plugin_ The codelab example is changed to write the flutter plug-in with KMM.
GitHub project address: KMM shuttle 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.
The Android / IOS plug-in plugincodelabplugin only needs to implement the KMM module interface without writing any logic, and put the logic in the KMM module through the interface.
For example, refer to the methodcall and methodchannel of the fluent plug-in to define the commonmethodcall data class and commonmethodchannel.result interface.
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()
}
}
Commoncodelabplugin needs to initialize and start synth Start(), processing getplatformversion, onkeydown, onkeyup logic.
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.cause)
}
}
else -> {
result.notImplemented()
}
}
}
}
Also, including the plug-in name also belongs to public logic
// 插件Channel名称
const val PLUGIN_CODE_LAB_CHANNEL = "plugin_codelab"
Only the expect interface is listed here. For the specific implementation of platform difference feature classes, please check the source code
expect class Synth() {
fun start()
fun keyDown(key: Int): Int
fun keyUp(key: Int): Int
}
expect class Platform() {
val platform: String
}
Android shuttle implements the plug-in KMM interface. Note that only the interface is implemented here to transfer data between shuttle and Android / IOS without any business logic
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?,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()
}
}
}
Android shuttle implements the plug-in KMM interface. Note that only the interface is implemented here to transfer data between shuttle and Android / IOS without any business logic
#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
Here, we have completed the development of a flutter plug-in using KMM. The advantage of using KMM to develop plug-ins is that the public logic is written in kotlin. Generally, the public logic is relatively simple, suitable for writing in kotlin and easy to maintain. Moreover, KMM write plug-in and fluent write UI are implemented.
Address: https://www.cnblogs.com/liqw/p/15477079.html GitHub project address: KMM shuttle plugin