項(xiàng)目背景
之前我介紹過(guò)Flutter建立JsBridge用于webview與h5通信,有時(shí)候h5頁(yè)面中需要喚醒其他應(yīng)用的功能,通過(guò)約定的Scheme協(xié)議肖揣,比如weixin://积蔚,這時(shí)候就需要我們的Webview組件處理,否則就會(huì)出現(xiàn)net:ERR_UNKNOWN_URL-SCHEME的頁(yè)面報(bào)錯(cuò)耕漱。
插件變更
上篇介紹Webview使用的文章算色,我用的是官方插件 webview_flutter,實(shí)際應(yīng)用的時(shí)候螟够,出現(xiàn)了個(gè)難以解決的bug灾梦,在華為mate30、android10環(huán)境下妓笙,h5的input元素調(diào)取手機(jī)系統(tǒng)鍵盤(pán)會(huì)失敗若河,據(jù)我們測(cè)試,目前只發(fā)現(xiàn)在該手機(jī)型號(hào)寞宫、安卓系統(tǒng)下出現(xiàn)該問(wèn)題萧福,而華為客戶(hù)占比很重,是必須要解決的辈赋,github上有類(lèi)似的closed issue鲫忍,推薦使用flutter_webview_plugin膏燕,所以就更改了webview插件,這兩個(gè)插件評(píng)分都很高悟民,提供的api類(lèi)似坝辫,使用方法也相似,組件改造工作量很小射亏。
組件改造
1近忙、安裝webview_flutter
flutter_webview_plugin: ^0.3.10+1
2、 ios中在ios/Runner/Info.plist中添加
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSAllowsArbitraryLoadsInWebContent</key>
<true/>
</dict>
3智润、改造WebView組件
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
import 'package:url_launcher/url_launcher.dart';
import '../configs/config.dart';
import '../utils/adapter.dart';
import '../utils/JsBridgeUtil.dart';
import '../widgets/AppIcon.dart';
import '../widgets/FixedSizeText.dart';
/// 與h5 端的一致 不然收不到消息
const String userAgent = 'FoxApp';
/// WebView頁(yè)面
class Webview extends StatefulWidget {
final String url;
final String title;
final VoidCallback backCallback;
Webview({
Key key,
@required this.url,
this.title = '',
this.backCallback,
}) : super(key: key);
@override
WebviewState createState() => WebviewState();
}
class WebviewState extends State<Webview> {
bool isPhone = Adapter.isPhone();
final flutterWebViewPlugin = FlutterWebviewPlugin();
final Set<JavascriptChannel> jsChannels = [
JavascriptChannel(
name: userAgent,
onMessageReceived: (JavascriptMessage msg) {
String jsonStr = msg.message;
JsBridgeUtil.executeMethod(JsBridgeUtil.parseJson(jsonStr));
}),
].toSet();
// On urlChanged stream
StreamSubscription<String> _onUrlChanged;
@override
void initState() {
super.initState();
flutterWebViewPlugin.close();
// Add a listener to on url changed
_onUrlChanged =
flutterWebViewPlugin.onUrlChanged.listen((String url) async {
if (url.contains('weixin:') || url.contains('alipay:')) {
await flutterWebViewPlugin.stopLoading();
await flutterWebViewPlugin.goBack();
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
});
}
@override
void dispose() {
_onUrlChanged.cancel();
flutterWebViewPlugin.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: isPhone ? Colors.white : Color(Config.foxColors.bg),
body: WebviewScaffold(
appBar: AppBar(
backgroundColor: isPhone ? null : Color(Config.foxColors.bg),
leading: AppIcon(Config.foxImages.backGreyUrl, callback: () {
flutterWebViewPlugin.close();
Navigator.of(context).pop(true);
widget.backCallback?.call();
}),
title: FixedSizeText(widget.title),
centerTitle: true,
elevation: 0,
),
url: widget.url,
userAgent: "Mozilla/5.0 $userAgent",
// h5 可以通過(guò)navigator.userAgent判斷當(dāng)前環(huán)境
javascriptChannels: jsChannels,
mediaPlaybackRequiresUserGesture: false,
withZoom: true,
withLocalStorage: true,
hidden: true,
),
);
}
}
測(cè)試同學(xué)提出了一個(gè)bug银锻,跳轉(zhuǎn)微信時(shí),會(huì)偶現(xiàn)net:ERR_UNKNOWN_URL-SCHEME頁(yè)面做鹰,這條issue也在討論這個(gè)問(wèn)題击纬,https://github.com/fluttercommunity/flutter_webview_plugin/issues/43,本質(zhì)是插件提供的功能不完善钾麸,沒(méi)有提供攔截頁(yè)面顯示的方法更振,社區(qū)提出了一些解決方式。
/// 兼容android進(jìn)入報(bào)錯(cuò)頁(yè)
_onStateChanged = flutterWebViewPlugin.onStateChanged
.listen((WebViewStateChanged state) async {
if (mounted) {
if (state.url.startsWith('weixin:') &&
state.type == WebViewState.abortLoad) {
if (await canLaunch(state.url)) {
await launch(state.url);
} else {
throw 'Could not launch ${state.url}';
}
}
}
});