关注公众号: 微信搜索 前端工具人 ; 收货更多的干货
原文链接: 本人博客园文章
一、开场白:
- 目前截止
flutter github start数已经94.4K了,潜在的说明了这事以后App开发趋势。 - 作为新起之秀,后劲足但是社区生态不够完善。还有许多的功能还没有相应的插件。
- 很荣幸能为flutter社区做贡献, 插件地址 flutter_3des_plugin, github地址
二、步骤
2.1、 创建一个插件包
注:flutter 插件项目默认针对iOS代码使用Objective-C,Android代码使用Java 。 除非你手动更改过(我的就是)
flutter create --org com.example --template=plugin hello
// 改变原生语言
flutter create --template=plugin -i swift -a kotlin hello
// 或者
flutter create --template=plugin -i objc -a java hello
2.2 二、 部分结构
- 插件包的
Dart APIlib/hello.dart
- 插件包
API的Android实现lib/hello.dart
- 插件包
API的ios实现ios/Classes/HelloPlugin.m
- 一个依赖于该插件的
Flutter应用程序,来说明如何使用它example/
2.3 实现package包
编写业务代码 (注: 若修改了原生代码,则需要运行 flutter build apk, 你的example才能使用你编辑过的功能 )
使用Android Studio 或者 Vscode编辑Android代码, 编写代码之前,首先确保代码至少已经构建过一次(例如,cd 到 hello/example; 在 flutter build apk)
- 暴露出去的方法:目录为 根目录下的
lib/hello.dart
class Flutter3desPlugin {
static const MethodChannel _channel =
const MethodChannel('hello');
static Future<String> get platformVersion async {
final String version = await _channel.invokeMethod('getPlatformVersion');
return version;
}
// 加密方法
static Future<String> encrypt(String key, String data) async{
return await _channel.invokeMethod('encrypt' , <String,dynamic>{'data':data,'key':key});
}
}
- Android 改动的目录为
android/src/main/java/com/yourcompany/hello/HelloPlugin.java里面的onMethodCall方法,如下,注释部分是需要添加的
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
// 把 if 优雅的改成 switch 并添加 encrypt 条件, 这将对应你所暴露出去的方法名
switch (call.method) {
case "getPlatformVersion":
result.success("Android " + android.os.Build.VERSION.RELEASE);
break;
case "encrypt": // 方法映射
String body = call.argument("data");
String keys = call.argument("key");
String key = keys + keys.substring(0,16);
byte [] text = encrypt(hexStr2Bytes(key),hexStr2Bytes(body));
result.success(bytes2HexStr(text));
break;
default:
result.notImplemented();
break;
}
}
private static final String algorithm = "DESede";
// 方法的实现
public static byte[] encrypt(byte[] key, byte[] body) {
try {
SecretKey deskey = new SecretKeySpec(key, algorithm);
Cipher c1 = Cipher.getInstance(algorithm);
c1.init(Cipher.ENCRYPT_MODE, deskey);
return c1.doFinal(body);
} catch (java.security.NoSuchAlgorithmException e1) {
e1.printStackTrace();
} catch (javax.crypto.NoSuchPaddingException e2) {
e2.printStackTrace();
} catch (java.lang.Exception e3) {
e3.printStackTrace();
}
return null;
}
........... (此处省略其他方法的实现)
- ios 改动目录为
ios\Classes\hello.m里的handleMethodCall方法, 添加encrypt方法映射, 和java部分类似; 注释部分是需要添加的
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
FlutterMethodChannel* channel = [FlutterMethodChannel
methodChannelWithName:@"flutter_3des_plugin"
binaryMessenger:[registrar messenger]];
Flutter3desPlugin* instance = [[Flutter3desPlugin alloc] init];
[registrar addMethodCallDelegate:instance channel:channel];
}
- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
if ([@"getPlatformVersion" isEqualToString:call.method]) {
result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
} else if([@"encrypt" isEqualToString:call.method]) { // 方法名映射, 注意和你所暴露出去的方法名一致
NSDictionary* argsMap=call.arguments;
NSString * data=argsMap[@"data"];
NSString * key=argsMap[@"key"];
NSString *batteryLevel = [self encrypt:data key:key];
if (batteryLevel) {
result(batteryLevel);
} else
{
result([FlutterError errorWithCode:@"UNAVAILABLE"
message:@"Battery info unavailable"
details:nil]);
}
} else {
result(FlutterMethodNotImplemented);
}
}
// 业务代码的实现
- (NSString *)encrypt:(NSString *)data key:(NSString *)key {
JKEncrypt * en = [[JKEncrypt alloc]init];
//加密
NSString * encryptStr = [en encrypt3DesData:data key:key];
return encryptStr;
}
@end
2.4. 再然后就是运行测试你的代码
注: 不用你区分是android环境还是ios环境, 框架会自动区分, 你只需要编写原生代码就行, 目录 example\lib\main.dart
import 'package:flutter_3des_plugin/flutter_3des_plugin.dart';
@override
void initState() {
super.initState();
encrypt();
}
// 3des 加密
encrypt () {
Flutter3desPlugin.encrypt(_key, _data).then((res) {
// TODO: res就是加密后的数据
setState(() {
_result = res;
});
});
}
四、发布package包,至 pub.dev
- 在发布之前,检查
pubspec.yaml、README.md以及CHANGELOG.md文件,以确保其内容的完整性和正确性 - 并在根目录下的
pubspec.yaml文件顶部加上version, author, homepage等字段, 执行下面命令后会有提示;成功的提示:执行完第二个命令并且授权谷歌登录后显示:Successfully uploaded package.
flutter packages pub publish --dry-run --server=https://pub.dartlang.org;
flutter packages pub publish; 或者 flutter packages pub publish;
五、 可能遇到的问题
若第四步行云流水没问题就不用往下看了。接下来说发布的坑(坑的我身心疲惫)现在总结下方法
5.1. 先来看错误有哪些:
// 错误1, 一直卡着, 绝望.....看到这些报错我都.....
Waiting for your authorization...
Authorization received, processing...
It looks like accounts.google.com is having some trouble.
Pub will wait for a while before trying to connect again.
OS Error: Operation timed out, errno = 60, address = accounts.google.com, port = 53481
pub finished with exit code 69
// 错误2, 一直卡着
Package has 2 warnings. Upload anyway (y/n)? y
Uploading...
5.2. 解决; 先不管报哪类错, 跟着下面步骤执行命令就对了
1、第一步
- 用命令行(
git,cmd)打开你的项目根目录下,运行下面命令, - 目的:解除国内镜像; 因为是发包到国外 (注: 以下命令只在当前终端端口有效, 你在别的窗口运行就都重置了)
unset FLUTTER_STORAGE_BASE_URL
unset PUB_HOSTED_URL
2、第二步 设置本地代理
// windows端口号默认是1080. 除非你改过, mac的话1081
set http_proxy=http://127.0.0.1:1080
set https_proxy=http://127.0.0.1:1080
// 上面的没代理成功就换成下面的
export http_proxy=http://127.0.0.1:1080
export https_proxy=http://127.0.0.1:1080
3、第三步 设置终端代理
- 这时你需要一个国外服务器........ (这很尴尬, 便宜的100一年吧);
- 然后下载小飞机(
Shadowocks.exe)。添加你的服务器, 系统代理模式选为 全局模式**
4、第四步
- 测试你的终端代理设置成功没
- 上几部的命令行里输入
curl -vv http://www.google.com, 看是否能访问谷歌, 成功提示如下:
5、第五步
ping通google后在执行发包命令, 你就会看到如下, 说明就成功了,- 这时去
pub.dev去搜索你的插件就能搜到了。
Package has 2 warnings. Upload anyway (y/n)? y
Uploading...
Successfully uploaded package.