最近在使用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的实现代码:
Flutter 解决webview_flutter 插件Android端无法上传文件问题_第1张图片修改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

更多相关文章

  1. APPS大乱斗:4大Android文件浏览器横评(一)
  2. Android Telephony启动过程源码分析
  3. Android RxJava:一步步带你源码分析 RxJava
  4. Android之网络请求5————OkHttp源码2:发送请求
  5. Android 4.0 Launcher2源码分析——导入eclipse进行调试【转】
  6. 如何在 iOS、Android、macOS、Windows 之间快速文件互传?
  7. Android资源文件夹及资源文件的详细介绍

随机推荐

  1. Android中的MessageQueue,Handler,Looper
  2. Android学习笔记之mainfest文件中android
  3. Android(安卓)使用com.j256.ormlite
  4. Android给View画边框
  5. android 动画总结
  6. android资料下载地址汇总
  7. Android获取本机Mac地址和IP地址
  8. Android(安卓)dependency ‘androidx.cor
  9. Android(安卓)SQLite是线程安全的吗?
  10. android viewholder