工作中经常实现 plugin 插件,随着项目人员的增加,功能的增加,代码有些混乱,随想实现一种通用的,标准化的实现方案,最终实现如下:
一. 创建插件 user(iOS 必须基于OC)
终端执行以下三个命令:
flutter create --template=plugin -i objc -a kotlin user
cd user
flutter create example
二. 实现插件方法
1. 定义插件 dart 方法
class User {
static const MethodChannel _channel = const MethodChannel('user');
static Future<String> getPlatformVersion() async {
String value = await _channel.invokeMethod('getPlatformVersion', "iOS");
return value;
}
static Future<String> getAppVersion() async {
String value = await _channel.invokeMethod('getAppVersion');
return value;
}
}
2. 实现 iOS 方法
···
├── Assets
├── Classes
│ ├── UserPlugin.h
│ └── UserPlugin.m
│ ├── UserManager.h(功能类)
│ ├── UserManager.m(功能类)
│ ├── ···
└── user.podspec
···
目录如上,如不想功能代码和插件代码混在一起,会创建功能类,便于维护,功能类示例如下;
UserManager.m 代码:
//
// UserManager.m
// User
//
// Created by shang on 2021/10/19.
//
#import "UserManager.h"
@implementation UserManager
- (void)getAppVersion:(id)params callback:(FlutterResult)callback{
NSDictionary *info = NSBundle.mainBundle.infoDictionary;
NSString *result = info[@"CFBundleShortVersionString"];
callback(result);
}
+ (void)getPlatformVersion:(id)params callback:(FlutterResult)callback{
callback(UIDevice.currentDevice.systemVersion);
}
@end
UserPlugin.m 代码:
#import "UserPlugin.h"
#import "UserManager.h"
@implementation UserPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
FlutterMethodChannel* channel = [FlutterMethodChannel methodChannelWithName:@"user" binaryMessenger:[registrar messenger]];
UserPlugin* instance = [[UserPlugin alloc] init];
[registrar addMethodCallDelegate:instance channel:channel];
}
- (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result{
// NSLog(@"call.arguments: %@", call.arguments);
[self reflectMethod:UserManager.class
instance:[UserManager new]
Call:call
result:result];
}
/// iOS 类方法/实例方法映射(方法格式: * (void)*MethodName*:(id)params callback:(FlutterResult)callback;)
///
/// @param cls 类参数: UserManager.class
/// @param instance 类方法传 nil, 实例方法传对应实例
/// @param call FlutterPlugin 参数
/// @param result FlutterPlugin 参数
- (void)reflectMethod:(Class)cls
instance:(nullable NSObject *)instance
Call:(FlutterMethodCall *)call
result:(FlutterResult)result {
NSLog(@"call.method: %@, call.arguments: %@", call.method, call.arguments);
NSString *method = call.method; //获取函数名
id arguments = call.arguments; //获取参数列表
SEL selector = NSSelectorFromString([NSString stringWithFormat:@"%@:callback:", method]);
if ([cls respondsToSelector:selector]) {
NSMethodSignature *methodSignature = [cls methodSignatureForSelector:selector]; // Signature
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
invocation.target = cls;// target
invocation.selector = selector;
[invocation setArgument:&arguments atIndex:2];
[invocation setArgument:&result atIndex:3];
[invocation invoke];
return;
}
if (instance && [instance respondsToSelector:selector]) {
NSMethodSignature *methodSignature = [cls instanceMethodSignatureForSelector:selector]; // Signature
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
invocation.target = instance;// target
invocation.selector = selector;
[invocation setArgument:&arguments atIndex:2];
[invocation setArgument:&result atIndex:3];
[invocation invoke];
return;
}
NSLog(@"%@--%@", cls, NSStringFromSelector(selector));
result(FlutterMethodNotImplemented);
}
@end
三. 方法标准化
1. 什么是方法标准化?
答案:按照一定规则声明 iOS 方法;
本实现指此方法定义应遵守方法格式:
//dart 方法名 + callback:(FlutterResult)callback
* (void)*MethodName*:(id)params callback:(FlutterResult)callback;
2. 为什么要方法标准化?
答案:dart 调用 oc 方法本质是方法的字符串转化,统一方法声明方法可以极大的减少冗余代码;且一次实现多插件复用;
3. 为什么要如此定义呢?
答案:flutter 调用 iOS 方法转化如下:
dart 方法1 《= Plugin 方法1 《= iOS 方法1
dart 方法2 《= Plugin 方法2 《= iOS 方法2
dart 方法3 《= Plugin 方法3 《= iOS 方法3
使用标准化,使 Plugin 方法通用化;
dart 方法1 《= Plugin 通用方法 《= iOS 方法1
dart 方法2 《= Plugin 通用方法 《= iOS 方法2
dart 方法3 《= Plugin 通用方法 《= iOS 方法3
是与 user.dart 文件方法保持一致;
通道的 invokeMethod 方法的参数是数组列表;为了方法标准化,我们缩减为一个固定参数,当 _channel.invokeMethod 方法没有传参时,UserManager.h 中的方法 params 参数为空;
//flutter 源码
@optionalTypeArgs
Future<T> invokeMethod<T>(String method, [ dynamic arguments ]) {
return _invokeMethod<T>(method, missingOk: false, arguments: arguments);
}
网友评论