<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hans-CN">
	<id>https://wiki.riguz.com/index.php?action=history&amp;feed=atom&amp;title=Blog%3A%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AAFlutter%E7%9A%84%E6%8F%92%E4%BB%B6</id>
	<title>Blog:创建一个Flutter的插件 - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.riguz.com/index.php?action=history&amp;feed=atom&amp;title=Blog%3A%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AAFlutter%E7%9A%84%E6%8F%92%E4%BB%B6"/>
	<link rel="alternate" type="text/html" href="https://wiki.riguz.com/index.php?title=Blog:%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AAFlutter%E7%9A%84%E6%8F%92%E4%BB%B6&amp;action=history"/>
	<updated>2026-06-02T19:46:09Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.42.3</generator>
	<entry>
		<id>https://wiki.riguz.com/index.php?title=Blog:%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AAFlutter%E7%9A%84%E6%8F%92%E4%BB%B6&amp;diff=2645&amp;oldid=prev</id>
		<title>imported&gt;Riguz：​最近需要在Flutter中实现AES加解密和KDF，但搜索了一下貌似网络上没有现成的库可以用，因此尝试手写了一个Flutter的插件，实现两个功能：

* AES256/CBC/NoPadding 加解密
* Argon2（Argon2d)</title>
		<link rel="alternate" type="text/html" href="https://wiki.riguz.com/index.php?title=Blog:%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AAFlutter%E7%9A%84%E6%8F%92%E4%BB%B6&amp;diff=2645&amp;oldid=prev"/>
		<updated>2019-05-13T00:00:00Z</updated>

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