Flutter 解决webview_flutter 插件Android端无法上传文件问题

最近在使用webview_flutter遇到在内嵌的h5中有上传文件的需求,但是官方的webview_flutter并没有对Android做相关的适配。做过Android的应该知道在Android源生中使用webview内嵌H5需要对上传文件的功能做相关的适配处理,否则会报错。由于webview_flutter内部还是使用Android源生的webview来展示H5,所以如果项目中有这方面需求还是需要自己处理。

1.我们要拿到webview_flutter插件的源码:
这里我是在flutter插件缓存中拷贝的(官网上可以下载,但是我没拿到最新的源码不知道是什么原因)
2.将webview_flutter插件源码复制的项目中去:
在项目根目录下创建一个文件夹放本地插件。
在这里插入图片描述
在pubspec.yaml中修改依赖:


dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  # WebView插件 https://github.com/flutter/plugins/tree/master/packages/webview_flutter
  webview_flutter:
    path: plugins/webview_flutter

然后找到插件Android的实现代码:
在这里插入图片描述修改WebViewFactory.java的相关实现:

public final class WebViewFactory extends PlatformViewFactory {
  private final BinaryMessenger messenger;
  private final View containerView;
  private  FlutterWebView flutterWebView;
  WebViewFactory(BinaryMessenger messenger, View containerView) {
    super(StandardMessageCodec.INSTANCE);
    this.messenger = messenger;
    this.containerView = containerView;
  }

  @SuppressWarnings("unchecked")
  @Override
  public PlatformView create(Context context, int id, Object args) {
    Map<String, Object> params = (Map<String, Object>) args;
    flutterWebView=new FlutterWebView(context, messenger, id, params, containerView);
    return flutterWebView;
  }

  public FlutterWebView getFlutterWebView() {
    return flutterWebView;
  }
}

修改WebViewFlutterPlugin.java相关实现:

public class WebViewFlutterPlugin implements FlutterPlugin, PluginRegistry.ActivityResultListener , ActivityAware {

  private FlutterCookieManager flutterCookieManager;
  public static Activity activity;
 private WebViewFactory factory;
  public WebViewFlutterPlugin() {}
  public static void registerWith(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();
    factory=new WebViewFactory(messenger, null);
    binding
        .getFlutterEngine()
        .getPlatformViewsController()
        .getRegistry()
        .registerViewFactory(
            "plugins.flutter.io/webview",factory);
    flutterCookieManager = new FlutterCookieManager(messenger);
  }
  @Override
  public void onDetachedFromEngine(FlutterPluginBinding binding) {
    if (flutterCookieManager == null) {
      return;
    }
    activity=null;
    flutterCookieManager.dispose();
    flutterCookieManager = null;
  }

  @Override
  public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
    Log.v("userlogin","onActivityResult in plugin");
    if (factory!=null&&factory.getFlutterWebView()!=null){
        return factory.getFlutterWebView().activityResult(requestCode,resultCode,data);
    }
    return false;
  }

  @Override
  public void onAttachedToActivity(ActivityPluginBinding binding) {
  	
    activity=binding.getActivity();
    binding.addActivityResultListener(this);
  }

  @Override
  public void onDetachedFromActivityForConfigChanges() {
  }
  @Override
  public void onReattachedToActivityForConfigChanges(ActivityPluginBinding binding) {
  }
  @Override
  public void onDetachedFromActivity() {
  }
}

在FlutterWebView.java中适配上传文件,通过 webView.setWebChromeClient监听h5选择文件的操作并拦截,然后打开文件管理选择要上传的文件,最后将文件返回给H5.

     webView.setWebChromeClient(new WebChromeClient() {
        
        // For Android < 3.0
        public void openFileChooser(ValueCallback<Uri> valueCallback) {
          uploadMessage = valueCallback;
          openImageChooserActivity();
        }

        // For Android  >= 3.0
        public void openFileChooser(ValueCallback valueCallback, String acceptType) {
          uploadMessage = valueCallback;
          openImageChooserActivity();
        }

        //For Android  >= 4.1
        public void openFileChooser(ValueCallback<Uri> valueCallback, String acceptType, String capture) {
          uploadMessage = valueCallback;
          openImageChooserActivity();
        }

        // For Android >= 5.0
        @Override
        public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
          uploadMessageAboveL = filePathCallback;
          openImageChooserActivity();
          return true;
        }

        @RequiresApi(api = Build.VERSION_CODES.KITKAT)
        @Override
        public void onProgressChanged(WebView view, int newProgress) {
          
        }
      });
private void openImageChooserActivity() {
    Intent i = new Intent(Intent.ACTION_GET_CONTENT);
    i.addCategory(Intent.CATEGORY_OPENABLE);
    i.setType("video/*;image/*;application/*;text/*;audio/*;");
    if (WebViewFlutterPlugin.activity!=null){
      WebViewFlutterPlugin.activity.startActivityForResult(Intent.createChooser(i, "选择文件"), FILE_CHOOSER_RESULT_CODE);
    }else {
      Log.v("userlogin","activity is null");
    }

  }
  public static final int RESULT_OK = -1;

  public boolean activityResult(int requestCode, int resultCode, Intent data) {
    Log.v("userlogin","回到onActivityResult");
    if (requestCode == FILE_CHOOSER_RESULT_CODE) {
      if (null == uploadMessage && null == uploadMessageAboveL) {
        return false;
      }
      Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
      if (uploadMessageAboveL != null) {
        onActivityResultAboveL(requestCode, resultCode, data);
      } else if (uploadMessage != null) {
        uploadMessage.onReceiveValue(result);
        uploadMessage = null;
      }
    }
    return false;
  }

  @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  private void onActivityResultAboveL(int requestCode, int resultCode, Intent intent) {
    if (requestCode != FILE_CHOOSER_RESULT_CODE || uploadMessageAboveL == null)
    {
      return;
    }
    Uri[] results = null;
    if (resultCode == Activity.RESULT_OK) {
      if (intent != null) {
        String dataString = intent.getDataString();
        ClipData clipData = intent.getClipData();
        if (clipData != null) {
          results = new Uri[clipData.getItemCount()];
          for (int i = 0; i < clipData.getItemCount(); i++) {
            ClipData.Item item = clipData.getItemAt(i);
            results[i] = item.getUri();
          }
        }
        if (dataString != null)
        {
          results = new Uri[]{Uri.parse(dataString)};
        }
      }
    }
    uploadMessageAboveL.onReceiveValue(results);
    uploadMessageAboveL = null;
  }

感兴趣的同学可以结合另一个插件:flutter_webview_plugin
来结合flutter_webview_plugin中上传文件的适配打造一个完美的webview_flutter。

相关代码:
https://github.com/qq1057119720/flutter_fish_local/tree/master/plugins/webview_flutter

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: Age of Ai 设计师:meimeiellie 返回首页