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
复制代码