前言
最近項(xiàng)目中加了一個(gè)H5的鏈接谱醇,里面有拍照、選照片和文件步做,以前用的原生的WebView副渴,iOS功能還可以正常彈窗,安卓死活沒反應(yīng)全度,就換了一種方案煮剧,使用InAppWebView看看。
webview_flutter官方的webview插件将鸵,很多功能缺失勉盅,H5上傳圖片,文件,但官方的插件并不支持顶掉。
實(shí)現(xiàn)過(guò)程
新建了頁(yè)面草娜,創(chuàng)建InAppWebView,具體代碼如下:
import 'dart:collection';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:magic/assets/styles/app_color.dart';
import '../../../common/utils/routers/fluro_navigator.dart';
import '../../../common/widgets/reza_app_bar.dart';
class WebViewInAppScreen extends StatefulWidget {
const WebViewInAppScreen({
Key key,
@required this.url,
this.title,
this.type,
this.onWebProgress,
this.onWebResourceError,
this.onLoadFinished,
this.onWebTitleLoaded,
this.onWebViewCreated,
}) : super(key: key);
final String url;
final String title;
final String type;
final Function(int progress) onWebProgress;
final Function(String errorMessage) onWebResourceError;
final Function(String url) onLoadFinished;
final Function(String webTitle) onWebTitleLoaded;
final Function(InAppWebViewController controller) onWebViewCreated;
@override
State<WebViewInAppScreen> createState() => _WebViewInAppScreenState();
}
class _WebViewInAppScreenState extends State<WebViewInAppScreen> {
// GlobalKey可以獲取到對(duì)應(yīng)的Widget的State對(duì)象
// 當(dāng)我們頁(yè)面內(nèi)容很多時(shí)痒筒,而需要改變的內(nèi)容只有很少的一部分且在樹的底層的時(shí)候宰闰,我們?nèi)绾稳?shí)現(xiàn)增量更新/通常情況下有兩種方式,第一種是通過(guò)方法的回調(diào)簿透,去實(shí)現(xiàn)數(shù)據(jù)更新移袍,第二種是通過(guò)GlobalKey
final GlobalKey webViewKey = GlobalKey();
InAppWebViewController webViewController;
InAppWebViewOptions viewOptions = InAppWebViewOptions(
useShouldOverrideUrlLoading: true,
mediaPlaybackRequiresUserGesture: true,
// applicationNameForUserAgent: "dface-yjxdh-webview",
);
// webview配置
// InAppWebViewGroupOptions viewOptions = InAppWebViewGroupOptions(
// // 跨平臺(tái)配置
// crossPlatform: InAppWebViewOptions (
// useShouldOverrideUrlLoading: true,
// mediaPlaybackRequiresUserGesture: true,
// ),
// // android平臺(tái)配置
// android: AndroidInAppWebViewOptions(
// //支持HybridComposition
// useHybridComposition: true
// ),
// // ios 平臺(tái)配置
// ios: IOSInAppWebViewOptions(
// allowsInlineMediaPlayback: true,
// )
// );
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
void dispose() {
// TODO: implement dispose
webViewController?.clearCache();
super.dispose();
}
// 設(shè)置頁(yè)面標(biāo)題
void setWebPageTitle(data) {
if (widget.onWebTitleLoaded != null) {
widget.onWebTitleLoaded(data);
}
}
// flutter調(diào)用H5方法
void callJSMethod() {
}
//返回
void back() async {
bool canGoBack = await webViewController.canGoBack();
if (canGoBack) {
webViewController.goBack();
} else {
NavigatorUtils.goBack(context);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: Platform.isIOS ? false : true,
appBar: RezaAppBar(
centerTitle: widget.title,
isBack: true,
isClose: true,
onBack: () {
back();
},
),
body: Column(
children: <Widget>[
Expanded(
child: InAppWebView(
key: webViewKey,
initialUrlRequest: URLRequest(url: Uri.parse(widget.url)),
initialOptions: InAppWebViewGroupOptions(
crossPlatform: viewOptions,
),
onWebViewCreated: (controller) {
webViewController = controller;
if (widget.onWebViewCreated != null) {
widget.onWebViewCreated(controller);
}
},
onTitleChanged: (controller, title) {
if (widget.onWebTitleLoaded != null) {
widget.onWebTitleLoaded(title);
}
},
onLoadStart: (controller, url) {},
shouldOverrideUrlLoading: (controller, navigationAction) async {
// 允許路由替換
return NavigationActionPolicy.ALLOW;
},
onLoadStop: (controller, url) async {
// 加載完成
widget.onLoadFinished(url.toString());
},
onProgressChanged: (controller, progress) {
if (widget.onWebProgress != null) {
widget.onWebProgress(progress);
}
},
onLoadError: (controller, Uri url, int code, String message) {
if (widget.onWebResourceError != null) {
widget.onWebResourceError(message);
}
},
onUpdateVisitedHistory: (controller, url, androidIsReload) {},
onConsoleMessage: (controller, consoleMessage) {
print(consoleMessage);
},
),
),
],
),
);
}
}
運(yùn)行,頁(yè)面倒是加載出來(lái)了老充,但是一點(diǎn)擊拍照的按鈕就直接崩潰了葡盗,如下:
下面一大堆日志,關(guān)鍵報(bào)錯(cuò)的原因:
Couldn't find meta-data for provider with authority com.foton.general.flutter_inappwebview.fileprovider
崩潰原因:
相機(jī)權(quán)限默認(rèn)是禁止的蚂维。直接跳轉(zhuǎn)到相冊(cè)戳粒。
開啟相機(jī)權(quán)限,閃退虫啥。
授權(quán)被拒絕后蔚约,無(wú)法再?gòu)棾鍪跈?quán)
無(wú)法直接跳轉(zhuǎn)到相機(jī)拍照
所以就百度一番,原來(lái)是沒加這個(gè):
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.flutter_inappwebview.fileprovider"
android:exported="false"
android:grantUriPermissions="true"
>
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
要在project->app->android->app->src->mian里的 AndroidManifest.xml 的 application 中添加上面的代碼涂籽,添加以上代碼后苹祟,在相機(jī)權(quán)限開啟的情況下,能正常彈出選擇彈框了。
結(jié)果運(yùn)行直接報(bào)錯(cuò)树枫,下面的錯(cuò)誤:
倒是說(shuō)的聽明白的直焙,沒加tools:replace="android:authorities",建議就加上了:
添加的完整的配置參數(shù):
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.flutter_inappwebview.fileprovider"
android:exported="false"
android:grantUriPermissions="true"
tools:replace="android:authorities"
>
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/jshare_file_provider_paths" />
</provider>
完整的配置砂轻。
然后運(yùn)行就OK了奔誓,可以拍照,選文件相冊(cè)了搔涝,記錄一下踩坑歷程厨喂。