【轉(zhuǎn)載】Flutter 安卓WebView拍照上傳圖片文件問題及InAppWebView使用

轉(zhuǎn)載自 簡書 http://www.itdecent.cn/p/8d8c45ffc4e5 供學(xué)習(xí)使用,轉(zhuǎn)載請聯(lián)系原作者

<article class="_2rhmJa">

前言

最近項目中加了一個H5的鏈接,里面有拍照、選照片和文件,以前用的原生的WebView,iOS功能還可以正常彈窗,安卓死活沒反應(yīng),就換了一種方案,使用InAppWebView看看。

webview_flutter官方的webview插件,很多功能缺失,H5上傳圖片,文件,但官方的插件并不支持。

實現(xiàn)過程

新建了頁面,創(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可以獲取到對應(yīng)的Widget的State對象
  // 當我們頁面內(nèi)容很多時,而需要改變的內(nèi)容只有很少的一部分且在樹的底層的時候,我們?nèi)绾稳崿F(xiàn)增量更新/通常情況下有兩種方式,第一種是通過方法的回調(diào),去實現(xiàn)數(shù)據(jù)更新,第二種是通過GlobalKey
  final GlobalKey webViewKey = GlobalKey();

  InAppWebViewController webViewController;
  InAppWebViewOptions viewOptions = InAppWebViewOptions(
    useShouldOverrideUrlLoading: true,
    mediaPlaybackRequiresUserGesture: true,
    // applicationNameForUserAgent: "dface-yjxdh-webview",
  );

  // webview配置
  // InAppWebViewGroupOptions viewOptions = InAppWebViewGroupOptions(
  // // 跨平臺配置
  // crossPlatform: InAppWebViewOptions (
  //   useShouldOverrideUrlLoading: true,
  //   mediaPlaybackRequiresUserGesture: true,
  // ),
  // // android平臺配置
  //   android: AndroidInAppWebViewOptions(
  //     //支持HybridComposition
  //     useHybridComposition: true
  //   ),
  //   // ios 平臺配置
  //   ios: IOSInAppWebViewOptions(
  //     allowsInlineMediaPlayback: true,
  //   )
  // );

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
  }

  @override
  void dispose() {
    // TODO: implement dispose
    webViewController?.clearCache();
    super.dispose();
  }

  // 設(shè)置頁面標題
  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);
              },
            ),
          ),
        ],
      ),
    );
  }
}

運行,頁面倒是加載出來了,但是一點擊拍照的按鈕就直接崩潰了,如下:

image

下面一大堆日志,關(guān)鍵報錯的原因:

Couldn't find meta-data for provider with authority com.foton.general.flutter_inappwebview.fileprovider

崩潰原因:
相機權(quán)限默認是禁止的。直接跳轉(zhuǎn)到相冊。
開啟相機權(quán)限,閃退。
授權(quán)被拒絕后,無法再彈出授權(quán)
無法直接跳轉(zhuǎn)到相機拍照

所以就百度一番,原來是沒加這個:

 <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 中添加上面的代碼,添加以上代碼后,在相機權(quán)限開啟的情況下,能正常彈出選擇彈框了。

結(jié)果運行直接報錯,下面的錯誤:

image

倒是說的聽明白的,沒加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>

完整的配置。

然后運行就OK了,可以拍照,選文件相冊了,記錄一下踩坑歷程。

image

</article>

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容