美文网首页Flutter
Flutter 安卓WebView拍照上传图片文件问题及InAp

Flutter 安卓WebView拍照上传图片文件问题及InAp

作者: Superman168 | 来源:发表于2023-11-22 17:17 被阅读0次

    前言

    最近项目中加了一个H5的链接,里面有拍照、选照片和文件,以前用的原生的WebView,iOS功能还可以正常弹窗,安卓死活没反应,就换了一种方案,使用InAppWebView看看。

    实现过程

    新建了页面,创建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可以获取到对应的Widget的State对象
      // 当我们页面内容很多时,而需要改变的内容只有很少的一部分且在树的底层的时候,我们如何去实现增量更新/通常情况下有两种方式,第一种是通过方法的回调,去实现数据更新,第二种是通过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();
      }
    
      // 设置页面标题
      void setWebPageTitle(data) {
        if (widget.onWebTitleLoaded != null) {
          widget.onWebTitleLoaded(data);
        }
      }
    
      // flutter调用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);
                  },
                ),
              ),
            ],
          ),
        );
      }
    }
    

    运行,页面倒是加载出来了,但是一点击拍照的按钮就直接崩溃了,如下:

    报错信息

    下面一大堆日志,关键报错的原因:

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

    崩溃原因:
    相机权限默认是禁止的。直接跳转到相册。
    开启相机权限,闪退。
    授权被拒绝后,无法再弹出授权
    无法直接跳转到相机拍照

    所以就百度一番,原来是没加这个:

     <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 中添加上面的代码,添加以上代码后,在相机权限开启的情况下,能正常弹出选择弹框了。

    结果运行直接报错,下面的错误:

    image.png

    倒是说的听明白的,没加tools:replace="android:authorities",建议就加上了:

    添加的完整的配置参数:

    <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.png

    相关文章

      网友评论

        本文标题:Flutter 安卓WebView拍照上传图片文件问题及InAp

        本文链接:https://www.haomeiwen.com/subject/cpqwwdtx.html