美文网首页
Flutter-让webview支持图片上传(Android,

Flutter-让webview支持图片上传(Android,

作者: Cosecant | 来源:发表于2020-10-27 00:31 被阅读0次

    详细源码地址:https://gitee.com/yugecse/WebViewUploadApplication/tree/master/

    该功能主要是对谷歌的第三方库(webview_flutter)进行源码修改,如果升级版本后需要重新修改。

    需要修改或新增的文件:

    1. 修改项目app/build.gradle文件,增加一个图片选择库;修改如下:
        dependencies {
            implementation 'com.zhihu.android:matisse:0.5.3-beta3'
            implementation 'com.github.bumptech.glide:glide:4.11.0'
            annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
        }
    
    1. 修改FlutterWebview.java
    
       // 文件选择监听声明
       interface OnShowFileChooserListener {
    
            boolean onShowFileChooser(ValueCallback<Uri[]> filePathCallback, String acceptType);
    
        }
    
        private static final String JS_CHANNEL_NAMES_FIELD = "javascriptChannelNames";
        private final InputAwareWebView webView;
        private final MethodChannel methodChannel;
        private final FlutterWebViewClient flutterWebViewClient;
        private final Handler platformThreadHandler;
        // 声明监听器对象
        private OnShowFileChooserListener onShowFileChooserListener;
    
        // Verifies that a url opened by `Window.open` has a secure url.
        private class FlutterWebChromeClient extends WebChromeClient {
            @Override
            public boolean onCreateWindow(
                    final WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
                final WebViewClient webViewClient =
                        new WebViewClient() {
                            @TargetApi(Build.VERSION_CODES.LOLLIPOP)
                            @Override
                            public boolean shouldOverrideUrlLoading(
                                    @NonNull WebView view, @NonNull WebResourceRequest request) {
                                final String url = request.getUrl().toString();
                                if (!flutterWebViewClient.shouldOverrideUrlLoading(
                                        FlutterWebView.this.webView, request)) {
                                    webView.loadUrl(url);
                                }
                                return true;
                            }
    
                            @Override
                            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                                if (!flutterWebViewClient.shouldOverrideUrlLoading(
                                        FlutterWebView.this.webView, url)) {
                                    webView.loadUrl(url);
                                }
                                return true;
                            }
                        };
    
                final WebView newWebView = new WebView(view.getContext());
                newWebView.setWebViewClient(webViewClient);
    
                final WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
                transport.setWebView(newWebView);
                resultMsg.sendToTarget();
    
                return true;
            }
    
            // 重写文件选择函数
            @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
            @Override
            public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
                String[] acceptTypes = fileChooserParams.getAcceptTypes();
                if (acceptTypes != null && acceptTypes.length > 0 && onShowFileChooserListener != null)
                    return onShowFileChooserListener.onShowFileChooser(filePathCallback, acceptTypes[0]);
                return super.onShowFileChooser(webView, filePathCallback, fileChooserParams);
            }
        }
    
        @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
        @SuppressWarnings("unchecked")
        FlutterWebView(
                final Context context,
                BinaryMessenger messenger,
                int id,
                Map<String, Object> params,
                View containerView,
               // 传入文件选择监听器对象
                OnShowFileChooserListener onShowFileChooserListener) {
            // 监听器对象赋值
            this.onShowFileChooserListener = onShowFileChooserListener;
            DisplayListenerProxy displayListenerProxy = new DisplayListenerProxy();
            DisplayManager displayManager =
                    (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
            displayListenerProxy.onPreWebViewInitialization(displayManager);
            webView = new InputAwareWebView(context, containerView);
            displayListenerProxy.onPostWebViewInitialization(displayManager);
    
            platformThreadHandler = new Handler(context.getMainLooper());
            // Allow local storage.
            webView.getSettings().setDomStorageEnabled(true);
            webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
    
            // Multi windows is set with FlutterWebChromeClient by default to handle internal bug: b/159892679.
            webView.getSettings().setSupportMultipleWindows(true);
            webView.setWebChromeClient(new FlutterWebChromeClient());
    
            methodChannel = new MethodChannel(messenger, "plugins.flutter.io/webview_" + id);
            methodChannel.setMethodCallHandler(this);
    
            flutterWebViewClient = new FlutterWebViewClient(methodChannel);
            Map<String, Object> settings = (Map<String, Object>) params.get("settings");
            if (settings != null) applySettings(settings);
    
            if (params.containsKey(JS_CHANNEL_NAMES_FIELD)) {
                List<String> names = (List<String>) params.get(JS_CHANNEL_NAMES_FIELD);
                if (names != null) registerJavaScriptChannelNames(names);
            }
    
            Integer autoMediaPlaybackPolicy = (Integer) params.get("autoMediaPlaybackPolicy");
            if (autoMediaPlaybackPolicy != null) updateAutoMediaPlaybackPolicy(autoMediaPlaybackPolicy);
            if (params.containsKey("userAgent")) {
                String userAgent = (String) params.get("userAgent");
                updateUserAgent(userAgent);
            }
            if (params.containsKey("initialUrl")) {
                String url = (String) params.get("initialUrl");
                webView.loadUrl(url);
            }
        }
    
    1. 修改FlutterWebViewFactory.java
    public final class WebViewFactory extends PlatformViewFactory {
      private final BinaryMessenger messenger;
      private final View containerView;
      private final FlutterWebView.OnShowFileChooserListener onShowFileChooserListener;
    
      WebViewFactory(BinaryMessenger messenger, View containerView, FlutterWebView.OnShowFileChooserListener onShowFileChooserListener) {
        super(StandardMessageCodec.INSTANCE);
        this.messenger = messenger;
        this.containerView = containerView;
        this.onShowFileChooserListener = onShowFileChooserListener;
      }
    
      @SuppressWarnings("unchecked")
      @Override
      public PlatformView create(Context context, int id, Object args) {
        Map<String, Object> params = (Map<String, Object>) args;
        return new FlutterWebView(context, messenger, id, params, containerView, onShowFileChooserListener);
      }
    }
    
    1. 新增加一个WebViewFileUploader.java的类
    package io.flutter.plugins.webviewflutter;
    
    import android.app.Activity;
    import android.content.Intent;
    import android.content.pm.ActivityInfo;
    import android.net.Uri;
    import android.webkit.ValueCallback;
    import android.widget.Toast;
    
    import com.zhihu.matisse.Matisse;
    import com.zhihu.matisse.MimeType;
    import com.zhihu.matisse.engine.impl.GlideEngine;
    
    import java.util.List;
    
    public class WebViewFileUploader {
    
        private Activity activity;
    
        private ValueCallback<Uri[]> filePathCallback;
    
        private String acceptType;
    
        WebViewFileUploader(Activity activity ){
            this.activity = activity;
        }
    
        public void start(ValueCallback<Uri[]> filePathCallback, String acceptType){
            this.filePathCallback = filePathCallback;
            this.acceptType = acceptType;
            if(acceptType != null && acceptType.toLowerCase().contains("image/*")){
                pickImage();
            }else {
                this.filePathCallback.onReceiveValue(null);
                this.filePathCallback = null;
                Toast.makeText(activity, "您设置的AcceptType不是图片", Toast.LENGTH_SHORT).show();
            }
        }
    
        private void pickImage(){
            Matisse.from(activity)
                    .choose(MimeType.ofAll())
                    .countable(true)
                    .maxSelectable(1)
    //                .addFilter(new GifSizeFilter(320, 320, 5 * Filter.K * Filter.K))
    //                .gridExpectedSize(getResources().getDimensionPixelSize(R.dimen.grid_expected_size))
                    .restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)
                    .thumbnailScale(0.85f)
                    .imageEngine(new GlideEngine())
                    .showPreview(true)
                    .forResult(0x001ABC);
        }
    
        public boolean onActivityResult(int requestCode, int resultCode, Intent data){
            if(requestCode == 0x001ABC){
                if(resultCode == Activity.RESULT_OK){
                  List<Uri> uriPaths = Matisse.obtainResult(data);
                  if(uriPaths != null && uriPaths.size() > 0){
                      filePathCallback.onReceiveValue(new Uri[]{ uriPaths.get(0) });
                      filePathCallback = null;
                      return true;
                  }
                }
                filePathCallback.onReceiveValue(null);
                filePathCallback = null;
                return true;
            }
            return false;
        }
    
    }
    
    
    1. 修改FlutterWebViewPlugin.java类
    
    /**
     * Java platform implementation of the webview_flutter plugin.
     *
     * <p>Register this in an add to app scenario to gracefully handle activity and context changes.
     *
     * <p>Call {@link #registerWith(Registrar)} to use the stable {@code io.flutter.plugin.common}
     * package instead.
     */
    public class WebViewFlutterPlugin implements FlutterPlugin, ActivityAware, PluginRegistry.ActivityResultListener, FlutterWebView.OnShowFileChooserListener {
    
        private Activity activity;
        private FlutterCookieManager flutterCookieManager;
        private WebViewFileUploader fileUploader;
    
        /**
         * Add an instance of this to {@link io.flutter.embedding.engine.plugins.PluginRegistry} to
         * register it.
         *
         * <p>THIS PLUGIN CODE PATH DEPENDS ON A NEWER VERSION OF FLUTTER THAN THE ONE DEFINED IN THE
         * PUBSPEC.YAML. Text input will fail on some Android devices unless this is used with at least
         * flutter/flutter@1d4d63ace1f801a022ea9ec737bf8c15395588b9. Use the V1 embedding with {@link
         * #registerWith(Registrar)} to use this plugin with older Flutter versions.
         *
         * <p>Registration should eventually be handled automatically by v2 of the
         * GeneratedPluginRegistrant. https://github.com/flutter/flutter/issues/42694
         */
        public WebViewFlutterPlugin() {
        }
    
    //  /**
    //   * Registers a plugin implementation that uses the stable {@code io.flutter.plugin.common}
    //   * package.
    //   *
    //   * <p>Calling this automatically initializes the plugin. However plugins initialized this way
    //   * won't react to changes in activity or context, unlike {@link CameraPlugin}.
    //   */
    //  @SuppressWarnings("deprecation")
    //  public static void registerWith(io.flutter.plugin.common.PluginRegistry.Registrar registrar) {
    //    registrar
    //        .platformViewRegistry()
    //        .registerViewFactory(
    //            "plugins.flutter.io/webview",
    //            new WebViewFactory(registrar.messenger(), registrar.view()));
    //    new FlutterCookieManager(registrar.messenger());
    //  }
    
        @Override
        public void onAttachedToEngine(FlutterPluginBinding binding) {
            BinaryMessenger messenger = binding.getBinaryMessenger();
            binding
                    .getPlatformViewRegistry()
                    .registerViewFactory(
                            "plugins.flutter.io/webview",
                            new WebViewFactory(messenger, /*containerView=*/ null, this));
            flutterCookieManager = new FlutterCookieManager(messenger);
        }
    
        @Override
        public void onDetachedFromEngine(FlutterPluginBinding binding) {
            if (flutterCookieManager == null) {
                return;
            }
    
            flutterCookieManager.dispose();
            flutterCookieManager = null;
        }
    
        @Override
        public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
            this.activity = binding.getActivity();
            binding.addActivityResultListener(this);
        }
    
        @Override
        public void onDetachedFromActivityForConfigChanges() {
    
        }
    
        @Override
        public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {
            binding.removeActivityResultListener(this);
        }
    
        @Override
        public void onDetachedFromActivity() {
    
        }
    
        @Override
        public boolean onShowFileChooser(ValueCallback<Uri[]> filePathCallback, String acceptType) {
            if (fileUploader == null) fileUploader = new WebViewFileUploader(activity);
            fileUploader.start(filePathCallback, acceptType);
            return true;
        }
    
        @Override
        public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
            if (fileUploader != null)
                return fileUploader.onActivityResult(requestCode, resultCode, data);
            return false;
        }
    }
    
    

    至此,你需要实现的图片文件选择的功能已经实现!

    注明:原创内容,请注明出处,谢谢!

    相关文章

      网友评论

          本文标题:Flutter-让webview支持图片上传(Android,

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