默认情况
WebView 不支持,WebView 点击没有反应。
兼容
重写 webview 的 webchromeClient 中的 openFileChooser 方法。Android 版本的多样性,就理所当然的各种兼容。
// For Android < 3.0
public void openFileChooser(ValueCallback uploadMsg) {
openFileChooser(uploadMsg, "");
}
//For Android 3.0 - 4.0
public void openFileChooser(ValueCallback uploadMsg, String acceptType) {
}
// For Android 4.0 - 5.0
public void openFileChooser(ValueCallback uploadMsg, String acceptType, String capture) {
openFileChooser(uploadMsg, acceptType);
}
// For Android > 5.0
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, FileChooserParams fileChooserParams) {
return true;
}
具体代码实现
网上也有很多实现方式,这边记录一下自己用到的一种
webview 调用时,弹出本地弹框,选择(相册/相机/取消),选择相册跳转到文件选择页面、选择相机注意权限配置,返回照片要做压缩、选择取消注意给webview一个空回应,要不点击没有反应。
public class ZpWebChromeClient extends WebChromeClient {
private OpenFileChooserCallBack mOpenFileChooserCallBack;
// For Android < 3.0
public void openFileChooser(ValueCallback uploadMsg) {
openFileChooser(uploadMsg, "");
}
//For Android 3.0 - 4.0
public void openFileChooser(ValueCallback uploadMsg, String acceptType) {
if (mOpenFileChooserCallBack != null) {
mOpenFileChooserCallBack.openFileChooserCallBack(uploadMsg, acceptType);
}
}
// For Android 4.0 - 5.0
public void openFileChooser(ValueCallback uploadMsg, String acceptType, String capture) {
openFileChooser(uploadMsg, acceptType);
}
// For Android > 5.0
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, FileChooserParams fileChooserParams) {
if (mOpenFileChooserCallBack != null) {
mOpenFileChooserCallBack.showFileChooserCallBack(filePathCallback, fileChooserParams);
}
return true;
}
public void setOpenFileChooserCallBack(OpenFileChooserCallBack callBack) {
mOpenFileChooserCallBack = callBack;
}
public interface OpenFileChooserCallBack {
void openFileChooserCallBack(ValueCallback uploadMsg, String acceptType);
void showFileChooserCallBack(ValueCallback filePathCallback, FileChooserParams fileChooserParams);
}
}
public class ZpWebView extends WebView {
private ZpWebChromeClient webChromeClient;
public ZpWebView(Context context) {
super(context);
initWebView();
}
public ZpWebView(Context context, AttributeSet attrs) {
super(context, attrs);
initWebView();
}
public ZpWebView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initWebView();
}
private void initWebView() {
webChromeClient = new ZpWebChromeClient();
setWebChromeClient(webChromeClient);
WebSettings webviewSettings = getSettings();
// 不支持缩放
webviewSettings.setSupportZoom(false);
// 自适应屏幕大小
webviewSettings.setUseWideViewPort(true);
webviewSettings.setLoadWithOverviewMode(true);
String cacheDirPath = getContext().getFilesDir().getAbsolutePath() + "cache/";
webviewSettings.setAppCachePath(cacheDirPath);
webviewSettings.setAppCacheEnabled(true);
webviewSettings.setDomStorageEnabled(true);
webviewSettings.setAllowFileAccess(true);
webviewSettings.setAppCacheMaxSize(1024 * 1024 * 8);
webviewSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
}
public void setOpenFileChooserCallBack(ZpWebChromeClient.OpenFileChooserCallBack callBack) {
webChromeClient.setOpenFileChooserCallBack(callBack);
}
}
public class MainActivity extends AppCompatActivity {
public static final int REQUEST_SELECT_FILE_CODE = 100;
private static final int REQUEST_FILE_CHOOSER_CODE = 101;
private static final int REQUEST_FILE_CAMERA_CODE = 102;
// 默认图片压缩大小(单位:K)
public static final int IMAGE_COMPRESS_SIZE_DEFAULT = 400;
// 压缩图片最小高度
public static final int COMPRESS_MIN_HEIGHT = 900;
// 压缩图片最小宽度
public static final int COMPRESS_MIN_WIDTH = 675;
private ValueCallback mUploadMsg;
private ValueCallback mUploadMsgs;
// 相机拍照返回的图片文件
private File mFileFromCamera;
private File mTakePhotoFile;
private BottomSheetDialog selectPicDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
ZpWebView webView = findViewById(R.id.webview);
webView.setOpenFileChooserCallBack(new ZpWebChromeClient.OpenFileChooserCallBack() {
@Override
public void openFileChooserCallBack(ValueCallback uploadMsg, String acceptType) {
mUploadMsg = uploadMsg;
showSelectPictrueDialog(0, null);
}
@Override
public void showFileChooserCallBack(ValueCallback filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
if (mUploadMsgs != null) {
mUploadMsgs.onReceiveValue(null);
}
mUploadMsgs = filePathCallback;
showSelectPictrueDialog(1, fileChooserParams);
}
});
}
/**
* 选择图片弹框
*/
private void showSelectPictrueDialog(final int tag, final WebChromeClient.FileChooserParams fileChooserParams) {
selectPicDialog = new BottomSheetDialog(this, R.style.Dialog_NoTitle);
selectPicDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialogInterface) {
if (mUploadMsgs != null) {
mUploadMsgs.onReceiveValue(null);
mUploadMsgs = null;
}
}
});
View view = LayoutInflater.from(this).inflate(R.layout.dialog_bottom_select_pictrue, null);
// 相册
TextView album = view.findViewById(R.id.tv_select_pictrue_album);
// 相机
TextView camera = view.findViewById(R.id.tv_select_pictrue_camera);
// 取消
TextView cancel = view.findViewById(R.id.tv_select_pictrue_cancel);
album.setOnClickListener(new View.OnClickListener() {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void onClick(View view) {
if (tag == 0) {
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
startActivityForResult(Intent.createChooser(i, "File Browser"), REQUEST_FILE_CHOOSER_CODE);
} else {
try {
Intent intent = fileChooserParams.createIntent();
startActivityForResult(intent, REQUEST_SELECT_FILE_CODE);
} catch (ActivityNotFoundException e) {
mUploadMsgs = null;
}
}
}
});
camera.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
takeCameraPhoto();
}
});
cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
selectPicDialog.dismiss();
}
});
selectPicDialog.setContentView(view);
selectPicDialog.show();
}
public void takeCameraPhoto() {
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) {
Toast.makeText(this, "设备无摄像头", Toast.LENGTH_SHORT).show();
return;
}
String filePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath();
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
mFileFromCamera = new File(filePath, System.nanoTime() + ".jpg");
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mTakePhotoFile));
startActivityForResult(intent, REQUEST_FILE_CAMERA_CODE);
} else {
try {
mTakePhotoFile = File.createTempFile("Zp" + System.nanoTime(), ".jpg", filePath);
Uri contentUri = FileProvider.getUriForFile(InnerBrowserActivity.this,
"com.zp.demo.ZpFileProvider", mTakePhotoFile);
intent.putExtra(MediaStore.EXTRA_OUTPUT, contentUri);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
startActivityForResult(intent, REQUEST_FILE_CAMERA_CODE);
} catch (IOException e) {
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case REQUEST_SELECT_FILE_CODE:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (mUploadMsgs == null) {
return;
}
mUploadMsgs.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, data));
mUploadMsgs = null;
}
break;
case REQUEST_FILE_CHOOSER_CODE:
if (mUploadMsg == null) {
return;
}
Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
mUploadMsg.onReceiveValue(result);
mUploadMsg = null;
break;
case REQUEST_FILE_CAMERA_CODE:
takePictureFromCamera();
break;
}
}
/**
* 处理相机返回的图片
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void takePictureFromCamera() {
if (mFileFromCamera != null && mFileFromCamera.exists()) {
String filePath = mFileFromCamera.getAbsolutePath();
// 压缩图片到指定大小
File imgFile = ZpImageUtils.compressImage(this, filePath, COMPRESS_MIN_WIDTH, COMPRESS_MIN_HEIGHT, IMAGE_COMPRESS_SIZE_DEFAULT);
Uri localUri = Uri.fromFile(imgFile);
Intent localIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, localUri);
this.sendBroadcast(localIntent);
Uri result = Uri.fromFile(imgFile);
if (mUploadMsg != null) {
mUploadMsg.onReceiveValue(Uri.parse(filePath));
mUploadMsg = null;
}
if (mUploadMsgs != null) {
mUploadMsgs.onReceiveValue(new Uri[]{result});
mUploadMsgs = null;
}
} else {
if (mUploadMsg != null) {
mUploadMsg.onReceiveValue(null);
mUploadMsg = null;
}
if (mUploadMsgs != null) {
mUploadMsgs.onReceiveValue(null);
mUploadMsgs = null;
}
}
}
}
备注:代码不规范的地方,自己抽取一下,这里就不做抽取了。
Github 地址
WebViewUploadFileDemo