Flutter实现Android、iOS跨平台经验总结

2020-04-13 11:40:18 蜻蜓队长

    Flutter跨平台框架,有着较低的入门门槛,较好的开发效率和运行效率,在github上已有77.6k的star,故项目中有引用,以实现跨平台的需求。
    整体而言,项目中主要遇到如下问题可供参考:

一、多语言类S实例为null的问题

    默认的i18n库,使用语言环境类"S"来管理所有语言的字符,动态生成S,采用json配置文件的形式,动态生成所有语言对应的变量。如图所示:

而默认的i18n库,调用
R.of(context)
将返回null。经查看源代码发现,可调用
S.delegate.load(Locale("en"));
来实现S的初始化。

故新建一个"R",继承"S",在R的初始化方法,根据当前语言环境,先调用
S.delegate.load() 即可以解决,因S初始化失败,导致的crash问题。

二、安卓各个语言包strings,转成Flutter语言json文件问题;

因安卓有比较充分的strings原始翻译文件包,但是Flutter只支持json,且格化必须为:

安卓原生为xml文件格式:

故最好有一个自动将安卓strings.xml转成符合Flutter格式json文件的工具,以免一个人复制粘贴,辛苦易错又浪费时间。
小工具已发到外网:
strings.xml转Flutter json工具

其中,由strings.xml解决出来的字符串都进行了转义,读取出来插入到js对象时,不能再调用JSON.stringify再次转义,不然复到到Flutter工程中,将导致编译失败。

此处采用的是字符串拼接的方式:

      for (let key in obj) {
        json += "\n";
        json += JSON.stringify(key);
        json += ":";
        let v = obj[key];
        if (v.indexOf("\"") != -1 && v.indexOf("\\\"") == -1) {
          v = v.replace(/\"/g, "\\\"");
        }
        v = v.replace(/\\@/g, "@");
        json += "\"" + v + "\",";
      }
复制代码

还需要补充维吾尔语,多参数时,参数名相同的hotfix。

二、引用外部文件时,需要统一采用'package:'。

在项目中,如果采用相对路径,import外部文件,而该类是单例的情况下,单例将失效,不能起到状态保存的作用;如:
import '../manager/VmDataManager.dart';
应统一使用:
import 'package:yh_flutter/manager/VmDataManager.dart';

三、iOS下使用FlutterViewController的self指针作为binaryMessenger变量,导致循环引用问题;

代码如下:

 FlutterMethodChannel * channel = [FlutterMethodChannel methodChannelWithName:@"com.xxx.client/plugin" binaryMessenger:self];
复制代码

应在在前viewcontrolelr出栈时,将FlutterMethodChannel成员变量、FlutterEventChannel成员变量置为nil:

- (void)didMoveToParentViewController:(UIViewController *)parent{
    if (parent == nil) {
        self.settingPresenter.methodChannel = nil;
        self.settingPresenter.eventChannel = nil;
        self.settingPresenter = nil;
    }
}
复制代码

四、Flutter不允许StatefulWidget继承StatefulWidget组件,宜用扩展方式,实现类似java类重用的需求。

class _AboutPageState extends State<AboutPage> with BasePageMixin {}
复制代码

BasePageMixin实现了类似基类的效果,如"初始化navigationbar、返回上一页"等。

class BasePageMixin {
  Widget getAppBar(BuildContext context, String title, List actions) {
    return widget;
  }

  void back(BuildContext context){
    if (VmDataManager.getInstance().isStackTop(context)){
      return;
    }
    debugPrint("can pop=" + context.toString());
    Navigator.pop(context);
  }
}
复制代码



五、可通过设置initialRoute的方式实现,native控制Flutter首页及同步传递消息给Flutter的效果;

iOS端设置路由代码:

[self setInitialRoute:self.routes];
复制代码

Android设置路由代码:

  public FlutterView createFlutterView(Context context) {
    WindowManager.LayoutParams matchParent = new WindowManager.LayoutParams(-1, -1);
    FlutterNativeView nativeView = this.createFlutterNativeView();
    FlutterView flutterView = new FlutterView(this, (AttributeSet) null, nativeView);
//    flutterView.setInitialRoute("xxx");

    flutterView.setLayoutParams(matchParent);
    this.setContentView(flutterView);
    return flutterView;
  }
复制代码

Flutter端读取路由字符串代码:

window.defaultRouteName
复制代码

可在setInitialRoute传递Flutter在初始化时,就需要获取的信息,如"语言环境、是否登录、登录方式、缓存大小"等,可减少Flutter再异步调native,native再异步调Flutter的过程。

六、Flutter网络,防止https抓包,及自签名根证书信任问题;

Flutter的网络请求,如果在项目中不事先代码声明当前proxy代理的ip和port,则系统的代理设置将不生效。
所以只要发布包没有设置代理的方法,将不能被第三方应用抓包。代码如下;

 var client = HttpClient(context: context);
    client.findProxy = (uri) {
    return "PROXY 100.69.181.11:8888";
 };
复制代码

公司要求支持xxx.cer根证书,而此根证书是自签名的,故新增根证书信任。代码如下:

ByteData data = await rootBundle.load('assets/b.crt');
SecurityContext context = SecurityContext.defaultContext;
context.setTrustedCertificatesBytes(data.buffer.asUint8List());
复制代码

需要先将cer证书转成x509 crt格式。命令如下:

openssl x509 -inform DER -in 053-Actalis_root.cer -out b.crt
复制代码

以上内容来自于网络,如有侵权联系即删除
相关文章

上一篇: 【需求解决系列之四】Android App在线自动更新Library(V2.0)

下一篇: 设计模式总结——《Android源码设计模式解析与实战》笔记

客服紫薇:15852074331
在线咨询
客户经理