WebView爬坑之旅3--H5中选择本地文件
来源:互联网 发布:爆菊感受 知乎 编辑:程序博客网 时间:2024/05/22 11:34
把上一篇(WebView爬坑之旅2–a标签是target=”_blank”时创建新窗口)的问题解决后,继续上线APP,然后又发现不能选择本地文件,这不是坑爹吗@##¥继续改不由自主的想起这张图:
谁让我是开发呢?
网页中选择手机中的文件,这个主要是WebChromeClient中实现,具体实现如下:
代码的有些片段是参考腾讯x5内核demo中实现的,由于这个功能在自己项目中用的不多,所以没做兼容测试,按道理大部分手机是可以的=. =
import android.app.AlertDialog;import android.app.Dialog;import android.content.ComponentName;import android.content.DialogInterface;import android.content.Intent;import android.graphics.Bitmap;import android.net.Uri;import android.os.Environment;import android.os.Message;import android.provider.MediaStore;import android.support.annotation.NonNull;import android.text.TextUtils;import com.orhanobut.logger.Logger;import com.tencent.smtt.export.external.interfaces.ConsoleMessage;import com.tencent.smtt.export.external.interfaces.JsResult;import com.tencent.smtt.sdk.ValueCallback;import com.tencent.smtt.sdk.WebChromeClient;import com.tencent.smtt.sdk.WebView;import com.tencent.smtt.sdk.WebViewClient;import com.zhangzhong.jieqianban.common.frame.Constants;import com.zhangzhong.jieqianban.common.utils.CommonUtils;import java.io.File;/** * Created by ly on 2017/9/1 16:53. */public class CustomWebChromeClient extends WebChromeClient { private static final String TAG = "WebChromeClient"; public static final int FILECHOOSER_TAKEPICTURE = 1; public static final int FILECHOOSER_CHOOSERFILE = 2; /** * 用于展示在web端<input type=text>的标签被选择之后,文件选择器的制作和生成 */ private ValueCallback<Uri> uploadFile; private ValueCallback<Uri[]> uploadFiles; private BaseWebActivity activity; private File takePicFile;//拍照保存的图片 public CustomWebChromeClient(@NonNull BaseWebActivity activity) { this.activity = activity; } /** * 解析网页标题后的回调 * Created by ly on 2017/9/26 9:54 */ @Override public void onReceivedTitle(WebView webView, String s) { Logger.d(">>>>onReceivedTitle:" + s); if (activity != null) activity.setTopTitle(s); super.onReceivedTitle(webView, s); } /** * 当网页里a标签target="_blank",打开新窗口时,这里会调用 */ @Override public boolean onCreateWindow(WebView webView, boolean isDialog, boolean isUserGesture, Message resultMsg) { X5WebView newWebView = new X5WebView(activity); X5WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj; newWebView.setWebChromeClient(new CustomWebChromeClient(activity)); newWebView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if (activity != null) { //拦截url,跳转新窗口=,= Intent intent = new Intent(activity, CommWebActivity.class); intent.putExtra(Constants.INTENT_KEY_URL, url); activity.startActivity(intent); } //防止触发现有界面的WebChromeClient的相关回调 return true; } }); transport.setWebView(newWebView); resultMsg.sendToTarget(); return true;// return super.onCreateWindow(webView, isDialog, isUserGesture, message); } /** * 控制台消息输出 */ @Override public boolean onConsoleMessage(ConsoleMessage cm) { if (cm.messageLevel() == ConsoleMessage.MessageLevel.DEBUG) { Logger.d(TAG, String.format("%s -- From line %s of %s", cm.message(), cm.lineNumber(), cm.sourceId())); } else if (cm.messageLevel() == ConsoleMessage.MessageLevel.LOG || cm.messageLevel() == ConsoleMessage.MessageLevel.TIP) { Logger.i(TAG, String.format("%s -- From line %s of %s", cm.message(), cm.lineNumber(), cm.sourceId())); } else if (cm.messageLevel() == ConsoleMessage.MessageLevel.WARNING) { Logger.w(TAG, String.format("%s -- From line %s of %s", cm.message(), cm.lineNumber(), cm.sourceId())); } else if (cm.messageLevel() == ConsoleMessage.MessageLevel.ERROR) { Logger.e(TAG, String.format("%s -- From line %s of %s", cm.message(), cm.lineNumber(), cm.sourceId())); } return true; } @Override public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {// AlertDialog.Builder builder = new AlertDialog.Builder(BaseWebActivity.this);// builder.setMessage(message);// builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {// @Override// public void onClick(DialogInterface dialog, int which) {// result.confirm();// }// });// builder.setCancelable(false).create().show(); // 返回true表示自已处理,返回false表示由系统处理 return false; } /** * 页面加载进度 */ @Override public void onProgressChanged(WebView view, int newProgress) {// if (pb_web != null) {// pb_web.setVisibility(View.VISIBLE);// pb_web.setMax(100);// pb_web.setProgress(newProgress);// if (pb_web.getProgress() == 100) {// pb_web.setVisibility(View.GONE);// }// } super.onProgressChanged(view, newProgress); } /** * 针对网页里的<input type="file" accept="image/*" capture="camera" >, WebView默认是不会弹出选择文件对话框的 * 需要重写该方法,自己来弹出选择文件对话框。 * <p> * 注意SDK不同的版本会有不同的方法,需要统一处理 */ // For Android 3.0+ public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType) { openFileChooseProcess(uploadFile, acceptType); } // For Android < 3.0 public void openFileChooser(ValueCallback<Uri> uploadFile) { openFileChooseProcess(uploadFile, null); } // For Android > 4.1.1 @Override public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType, String capture) { openFileChooseProcess(uploadFile, acceptType); } // For Android >= 5.0 @Override public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) { super.onShowFileChooser(webView, filePathCallback, fileChooserParams); this.uploadFiles = filePathCallback; if (fileChooserParams.isCaptureEnabled() && Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { takePicture(); } else { String[] acceptTypes = fileChooserParams.getAcceptTypes(); String acceptType = null; if (acceptTypes != null && acceptTypes.length > 0) acceptType = acceptTypes[0]; showMenu4InputFile(acceptType); } return true;//返回true,filePathCallback被调用 } private void openFileChooseProcess(ValueCallback<Uri> uploadFile, String acceptType) { this.uploadFile = uploadFile; showMenu4InputFile(acceptType); } private void showMenu4InputFile(final String acceptType) { try { String[] menus = {"拍照", "相册"}; Dialog dialog = new AlertDialog.Builder(activity).setItems(menus, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { switch (which) { case 0: takePicture(); break; case 1: default: chooseFile(acceptType); break; } } }).create(); //这里很重要,如果弹出对话框,用户选择一个图片或者进行拍照,但是进行到一半的时候,用户cancel了,这个时候再去点击“选择文件”按钮时,网页会失去响应。 //原因是:点击“选择文件”按钮时,网页会缓存一个ValueCallback对象,必须触发了该对象的onReceiveValue()方法,WebView才会释放,进而才能再一次的选择文件。 //当弹层被取消时,返回未选择文件 dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { if (uploadFile != null) { uploadFile.onReceiveValue(null); uploadFile = null; } } }); dialog.show(); } catch (Exception e) { e.printStackTrace(); } } private void chooseFile(String acceptType) { try { Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.addCategory(Intent.CATEGORY_OPENABLE); //能够返回一个Uri结果 if (TextUtils.isEmpty(acceptType)) {//接收类型 acceptType = "*/*"; //选择的文件类型,例如:image/*表示图片 } intent.setType(acceptType); activity.startActivityForResult(Intent.createChooser(intent, "File Chooser"), FILECHOOSER_CHOOSERFILE); } catch (Exception e) { e.printStackTrace(); } } private void takePicture() { try { //这种方式拍照后onActivityResult data=null String pictureName = "webPic-" + System.currentTimeMillis() + ".jpg"; File file = new File(Constants.TEMP_PATH); if (!file.exists()) { file.mkdirs(); } takePicFile = new File(file, pictureName); Uri imageUri = CommonUtils.getUriForFile(takePicFile); Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); intent.putExtra("return-data", false); intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); intent.putExtra("noFaceDetection", true); ComponentName componentName = intent.resolveActivity(activity.getPackageManager()); if (componentName != null) { activity.startActivityForResult(intent, FILECHOOSER_TAKEPICTURE); }// 方式二// Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);// activity.startActivityForResult(takePictureIntent, FILECHOOSER_TAKEPICTURE); } catch (Exception e) { e.printStackTrace(); } } public ValueCallback<Uri> getUploadFile() { return uploadFile; } public ValueCallback<Uri[]> getUploadFiles() { return uploadFiles; } public void setUploadFile(ValueCallback<Uri> uploadFile) { this.uploadFile = uploadFile; } public void setUploadFiles(ValueCallback<Uri[]> uploadFiles) { this.uploadFiles = uploadFiles; } public File getTakePicFile() { return takePicFile; } public void setTakePicFile(File takePicFile) { this.takePicFile = takePicFile; }
需要注意的是,onActivityResult回调部分代码(详情请见WebView爬坑之旅1–腾讯x5内核(tbs) 中BaseWebActivity 的实现):
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); //从web页选择文件/拍照的处理 if (requestCode == CustomWebChromeClient.FILECHOOSER_CHOOSERFILE || requestCode == CustomWebChromeClient.FILECHOOSER_TAKEPICTURE) { Uri result; if (requestCode == CustomWebChromeClient.FILECHOOSER_CHOOSERFILE) { result = data == null ? null : data.getData(); } else { result = CommonUtils.getUriForFile(webChromeClient.getTakePicFile()); } ValueCallback<Uri> uploadFile = webChromeClient.getUploadFile(); ValueCallback<Uri[]> uploadFiles = webChromeClient.getUploadFiles(); if (null != uploadFile) { uploadFile.onReceiveValue(result); webChromeClient.setUploadFile(null); } if (null != uploadFiles) { uploadFiles.onReceiveValue(result == null ? null : new Uri[]{result}); webChromeClient.setUploadFiles(null); } } }
阅读全文
0 0
- WebView爬坑之旅3--H5中选择本地文件
- Android WebView选择本地文件上传
- Android 5.0WebView选择本地文件
- WinForm之选择本地文件
- 加载本地文件到 WebView 中
- Android webview调用本地文件选择失败解决
- IE浏览器中选择本地文件
- webview支持H5中的选择图片方法
- Webview打开本地文件、图片选择的解决方案。版本兼容问题
- Android Webview H5交互之LocalStorage
- Android中webView加载H5绑定cookie
- Android webview 和H5交互选择图片功能
- Android爬坑之旅之WebView
- Android爬坑之旅之WebView
- Android webview 加载本地文件
- android webview 加载本地文件
- H5学习之旅-H5的元素属性(3)
- C#窗体应用程序中 浏览本地文件 或 选择本地文件路径 的方法
- 2017秋招总结
- NDK_PROJECT_PATH = null
- Python如何实现两个服务器之间文件的上传
- QT之qss教程-QTabWidget
- 调整数组顺序使奇数位于偶数前面
- WebView爬坑之旅3--H5中选择本地文件
- 【C#】MemoryStream
- Image加载图片,设置图片,存入SD卡,所有方法
- 修改maven仓库为自己的私有仓库
- Estore电子商城 --- 知识的整合
- 2017VS2018年非工作日日期大集合
- 设计模式六大原则(5):迪米特法则
- [excel]公式中的文本限制在255个字符以内
- JavaScript之表单验证