• 自定义 Flutter 插件(flutter_3des_plugin)步骤,以及上传插件的那些坑。


    本人掘金文章

    开场白:

    • 目前截止 flutter github start 数已经 94.4K了,潜在的说明了这事以后App开发趋势。
    • 作为新起之秀,后劲足但是社区生态不够完善。还有许多的功能还没有相应的插件。
    • 很荣幸能为flutter社区做贡献, 插件地址 flutter_3des_plugin, github地址

    步骤

    1. 创建一个插件包

    注:flutter 插件项目默认针对iOS代码使用Objective-CAndroid代码使用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. 部分结构

    1) 插件包的Dart API

    • lib/hello.dart

    2) 插件包APIAndroid实现

    • android/src/main/java/com/yourcompany/​hello/HelloPlugin.java

    3) 插件包APIios实现

    • ios/Classes/HelloPlugin.m

    4) 一个依赖于该插件的Flutter应用程序,来说明如何使用它

    • example/

    3. 实现package包, 编写业务代码 运行flutter build apk

    使用Android Studio 或者 Vscode编辑Android代码, 编写代码之前,首先确保代码至少已经构建过一次(例如,cdhello/example; 在 flutter build apk

    1. 暴露出去的方法:目录为 根目录下的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});
      }
    }  
    

    2. 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;
      } 
     ........... (此处省略其他方法的实现)
    

    3. ios 改动目录为 iosClasseshello.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
    

    4. 再然后就是运行测试你的代码: 注 不用你区分是android环境还是ios环境, 框架会自动区分, 你只需要编写原生代码就行, 目录 examplelibmain.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; 
          });
        });
      } 
    

    4. 发布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...
    
    1. 解决; 先不管报哪类错, 跟着下面步骤执行命令就对了
    • 第一步 用命令行(git,cmd)打开你的项目根目录下,运行下面命令, 目的:解除国内镜像: 因为是发包到国外
      (注: 以下命令只在当前终端端口有效, 你在别的窗口运行就都重置了)
    unset FLUTTER_STORAGE_BASE_URL
    
    • 第二步 设置本地代理
    // 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
    
    • 第三部 设置终端代理, 这时你需要一个国外服务器........ (这很尴尬, 便宜的100一年吧);然后下载小飞机(Shadowsock.exe)。添加你的服务器, 系统代理模式选为 全局模式

    测试你的终端代理设置成功没, 上几部的命令行里输入 curl -vv http://www.google.com, 看是否翻墙成功, 成功提示如下:

    pinggoogle 后在执行发包命令, 你就会看到如下, 说明就成功了, 这时去pub.dev 去搜索你的插件就能搜到了。

    Package has 2 warnings. Upload anyway (y/n)? y
    Uploading...
    Successfully uploaded package.
    

    5. 有问题欢迎留言

  • 相关阅读:
    桥接模式(从多个角度对实现进行分类)
    单例模式
    组合模式(解决 树形 ,局部与整体关系)
    备忘录模式
    适配器模式
    状态模式
    StartUML建模及生成java实体代码
    JPA删除接口报错 : org.hibernate.LazyInitializationException: failed to lazily initialize a collection, could not initialize proxy
    idea创建的gradle项目没有src目录怎么办?
    idea spring源码 gradle编译失败问题
  • 原文地址:https://www.cnblogs.com/ljx20180807/p/13155070.html
Copyright © 2020-2023  润新知