1、需求背景
實現一個不全屏的,支持加載本地html資源的webview
2、結論先行
選用了官方的webview_flutter。總結了下實踐的過程,分析幾個插件有如下特點:
flutter_inappwebview:
問題:
1.鍵盤有時候收不起來.
2.文本框不響應文字輸入
3.部分Android機型上,js->flutter 不通.分析查看是native層的js接口沒有被回調,原生的js接口.(setJavaScriptEnable爲true),高頻概率性出現,危害程度可以說是致命性。
優勢:
1、能加載本地h5資源
2、支持不用全屏。
除了以上問題,特別是js的調用問題 。否則這個框架是非常適合目前的場景了。
flutter_webview_plugin
1.只能全屏
2.不能加載本地H5
3.無鍵盤問題
需求界面是flutter ui+webview混合組成。同時加載本地h5要解析成字符串後展示,感覺有點麻煩,挺不靠譜的感覺。諸多問題,放棄。
webview_flutter:
1.解決了鍵盤問題(目前只是實驗性,還是有出問題的概率,但還是能用)
2.IOS端不支持加載本地html。
3、官方插件。
3、優化過程
綜合上踩坑總結,最後選用了webview_flutter。接下來就是解決不支持加載本地html的問題。
在Android端,加載本地本地html,只需要使用:
"file:///android_asset/flutter_assets/assets/index.html
的方式即可加載本地html。
加壓過apk就你能看到,flutter的資源會被打包進文件夾flutter_assets下。可以加壓apk查看。按照Android WebView loadUrl加載本地html的方式拼上以上路徑即可找到本地html。
而在IOS端,加載html的實現方式爲:https://github.com/flutter/plugins/blob/master/packages/webview_flutter/ios/Classes/FlutterWebView.m
- (bool)loadUrl:(NSString*)url withHeaders:(NSDictionary<NSString*, NSString*>*)headers {
NSURL* nsUrl = [NSURL URLWithString:url];
if (!nsUrl) {
return false;
}
//創建請求
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:nsUrl];
[request setAllHTTPHeaderFields:headers];
//發起請求
[_webView loadRequest:request];
return true;
}
而ios加載本地html方式這樣是行不通的。需要先找到本地資源,然後調用loadFileURL:url的方式。爲了兼容而改成以下方式實現:
- (bool)loadUrl:(NSString*)url withHeaders:(NSDictionary<NSString*, NSString*>*)headers {
NSURL* nsUrl = [NSURL URLWithString:url];
NSLog(@"webview_flutter: %@", nsUrl);
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:nsUrl];
[request setAllHTTPHeaderFields:headers];
//判斷是url使用不用的加載方式
if([url hasPrefix:@"http"]) {
[_webView loadRequest:request];
}else{
//爲減少對三方插件的修改,加載本地html,文件名暫時只支持命名爲名index
if (@available(iOS 9.0, *)) {
NSURL *findUrl = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/Frameworks/App.framework/flutter_assets/webres/%@", [[NSBundle mainBundle] bundlePath], @"index.html"]];
NSLog(@"Debug >>>> %@", findUrl);
NSString *loadUrl = [findUrl.absoluteString stringByReplacingOccurrencesOfString:@"index.html" withString:url];
NSURL * url = [NSURL URLWithString:loadUrl];
NSLog(@"Debug >>>> load url %@", url);
[_webView loadFileURL:url allowingReadAccessToURL:[url URLByDeletingLastPathComponent]];
} else {
// Fallback on earlier versions
NSLog(@"webview_flutter: loadFileUrl error");
}
}
return true;
}
成功。因本人是Android出身,以上代碼花了大半個小時才寫出來,還是object-c。
總算搞出來了。
4、總結
webview_flutter不管在Android還是iOS,實現的方式首先於flutter的platforview的侷限性,導致了鍵盤的問題https://github.com/flutter/plugins/tree/master/packages/webview_flutter。目前還沒有一個完美的解決方案,不過勉強能用,能接受。從本質上最看好flutter_webview_plugin的實現方式,用了純flutter的方式來實現,但只能全屏。有空的話可以多研究下。而inappwebview的方式和官網本質上是一樣的,都是採用了原生的方式,但鍵盤問題inappwebview表現要好很多。綜上評估各方面評估還是選了官方的插件加以完善來適應當前的項目。
從去年下半年開始接觸Flutter預研了一個多月,後面中斷了,現在因產品需要重新操練了起來,Flutter越玩越發現好玩,菜鳥慢慢起飛吧,加油!