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
複製程式碼