详细源码地址:https://gitee.com/yugecse/WebViewUploadApplication/tree/master/
该功能主要是对谷歌的第三方库(webview_flutter)进行源码修改,如果升级版本后需要重新修改。
需要修改或新增的文件:
- 修改项目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'
}
- 修改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);
}
}
- 修改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);
}
}
- 新增加一个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;
}
}
- 修改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;
}
}
至此,你需要实现的图片文件选择的功能已经实现!
注明:原创内容,请注明出处,谢谢!
网友评论