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

Flutter中,`webview_flutter`插件提供了在WebView中嵌入网页和原生页面的功能,并允许进行一些交互。如果你想在WebView中模拟安卓的`postUrl`请求,可以使用`WebView`组件的`postUrl`方法。以下是一个简单的示例代码,展示了如何使用`postUrl`方法发送POST请求: ```dart import 'package:flutter/material.dart'; import 'package:webview_flutter/webview_flutter.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: MyHomePage(), ); } } class MyHomePage extends StatefulWidget { @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { String url = 'https://example.com'; // 目标URL String postData = 'user=test&password=test'; // POST数据 @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('WebView Flutter PostUrl Example'), ), body: WebView( initialUrl: url, javascriptMode: JavascriptMode.unrestricted, onWebViewCreated: (WebViewController controller) { controller.postUrl( Uri.parse(url).toString(), Uint8List.fromList(postData.codeUnits), ); }, ), ); } } ``` 这段代码创建了一个简单的Flutter应用,其中包含了一个`WebView`。在`onWebViewCreated`回调中,我们获取到了`WebView`的控制器,并通过调用`postUrl`方法发送了一个POST请求。`url`是请求的地址,`postData`是POST请求携带的数据,这里使用了`Uint8List`类型来表示要发送的数据,其中`codeUnits`属性会将字符串转换为字节列表。 请注意,使用`postUrl`方法时,需要确保目标URL允许从你应用的WebView中接收POST请求。此外,由于`webview_flutter`依赖于平台特定的WebView实现,因此某些功能的可用性可能会受到目标设备平台的限制。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

倚栏静望

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值