首页
随机
最近更改
特殊页面
社群首页
参数设置
关于WHY42
免责声明
WHY42
搜索
用户菜单
登录
欢迎来到Riguz的小站!这是一个私人wiki,用来记录一些我的笔记。
查看“︁Blog:创建一个Flutter的插件”︁的源代码
←
Blog:创建一个Flutter的插件
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
最近需要在Flutter中实现AES加解密和KDF,但搜索了一下貌似网络上没有现成的库可以用,因此尝试手写了一个Flutter的插件,实现两个功能: * AES256/CBC/NoPadding 加解密 * Argon2(Argon2d) = 插件定义= == 创建插件工程== 其实貌似也可以在Flutter项目中直接调用Platform channel相关的实现,考虑到把这一部分剥离出来可以单独维护和造福后人,还是选择创建一个Plugin。首先需要创建一个插件的工程,通过如下的命令: <syntaxhighlight lang="bash"> flutter create --org com.riguz --template=plugin encryptions </syntaxhighlight> 这样会生成一个项目,值得注意的是,这里Android会使用Java,IOS会使用Objective-C。但Objective-C对于我这种没有基础的人来说看着太麻烦了,我尝试了一些之后放弃了。于是需要切换成Swift。这里有一个小的方法可以只修改IOS的部分: <syntaxhighlight lang="bash"> cd encryptions rm -rf ios examples/ios flutter create -i swift --org com.riguz . </syntaxhighlight> 删除ios的目录后执行这个命令,可以重新生成ios的工程,基于swift的。 == 定义Dart接口== 首先定义出我们要暴露的接口。举个例子,对于AES加密的函数,我们可以这样写: <syntaxhighlight lang="dart"> class Encryptions { static const MethodChannel _channel = const MethodChannel('encryptions'); static Future<Uint8List> aesEncrypt( Uint8List key, Uint8List iv, Uint8List value) async { return await _channel .invokeMethod("aesEncrypt", {"key": key, "iv": iv, "value": value}); } </syntaxhighlight> 这里有几点值得注意的: * MethodChannel是用来调用原生接口,后面各个平台会注册同名的MethodChannel。 * 调用原生方法通过方法名 + 参数调用,参数的对应列表参见官方文档。这里我们希望的是Java中的byte[] 类型,所以用Uint8List * 参数通过key-value的map传递到原生接口,原生代码通过参数名取得参数值 = Platform实现= == ios== 首先需要先build一下: <syntaxhighlight lang="bash"> cd encryptions/example; flutter build ios --no-codesign </syntaxhighlight> 在Xcode中打开项目,有一个SwiftEncryptionsPlugin的类,在这个里面实现即可: <syntaxhighlight lang="swift"> public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { let args = call.arguments as! [String: Any]; switch call.method { case "aesEncrypt", "aesDecrypt": let key = args["key"] as! FlutterStandardTypedData; let iv = args["iv"] as! FlutterStandardTypedData; let value = args["value"] as! FlutterStandardTypedData; do { let cipher = try handleAes(key: key.data, iv: iv.data, value: value.data, method: call.method); result(cipher); } catch { result(nil); }; // ... } } </syntaxhighlight> 因为需要使用Argon2,需要在swift中调用原生c代码,试了一些办法都不行,后来发现其实比较简单,直接在Supported Files中有一个encryptions-umbrella.h文件中加入引用,就可以直接调用了: <syntaxhighlight lang="c"> #import "EncryptionsPlugin.h" #import "argon2.h" </syntaxhighlight> <syntaxhighlight lang="swift"> func argon2i(password: Data, salt: Data)-> Data { var outputBytes = [UInt8](repeating: 0, count: hashLength); password.withUnsafeBytes { passwordBytes in salt.withUnsafeBytes { saltBytes in argon2i_hash_raw(iterations, memory, parallelism, passwordBytes, password.count, saltBytes, salt.count, &outputBytes, hashLength); } } return Data(bytes: UnsafePointer<UInt8>(outputBytes), count: hashLength); } </syntaxhighlight> == Android== 在Android Studio中打开工程(第一次打开是需要build的,```cd encryptions/example; flutter build apk```, ios也类似)。Android中实现起来会简单一点,这里只说一下如何调用c原生代码: 首先在build.gradle中加入额外的步骤: <syntaxhighlight lang="groovy"> externalNativeBuild { cmake { path "src/main/cpp/CMakeLists.txt" } } </syntaxhighlight> 然后在CMakeLists.txt中指定编译步骤,我这里需要编译一个argon2的库,以及一个JNI调用的库。 <syntaxhighlight lang="cmake"> add_library( argon2 SHARED argon2/src/argon2.c argon2/src/core.c argon2/src/blake2/blake2b.c argon2/src/encoding.c argon2/src/ref.c argon2/src/thread.c ) add_library( argon2-binding SHARED argon2_binding.cpp ) target_include_directories( argon2 PRIVATE argon2/include ) target_include_directories( argon2-binding PRIVATE argon2/include ) find_library( log-lib log) target_link_libraries( native-lib ${log-lib}) target_link_libraries( argon2-binding argon2 ${log-lib}) </syntaxhighlight> 然后就通过JNI调用到argon2的方法: <syntaxhighlight lang="java"> public final class Argon2 { static { System.loadLibrary("argon2-binding"); } // ... private native byte[] argon2iInternal(int iterations, int memory, int parallelism, final byte[] password, final byte[] salt, int hashLength); private native byte[] argon2dInternal(int iterations, int memory, int parallelism, final byte[] password, final byte[] salt, int hashLength); } </syntaxhighlight> 详细的代码不再累述。 = Example= 在example工程中,用dart调用一下这些接口,然后可以分别在Xcode和Android Studio中运行起来,看一下不同平台是否都支持。不清楚是否有自动化的测试方法。 [[File:encryptions_example.jpeg|600px|example]] 如果想了解更多,[https://github.com/soleverlee/encryptions 这里]是详细的代码。 参考: * [https://flutter.dev/docs/development/platform-integration/platform-channels Writing custom platform-specific code] * [https://flutter.dev/docs/development/packages-and-plugins/developing-packages Developing packages & plugins]
返回
Blog:创建一个Flutter的插件
。