最近在做一套基于 H5 打包的在线客服APP,在即时通讯中需要用到调用本地照相、图库,之前也记录实践过的一篇《webView支持H5页面通过js实现文件上传、图片上传》,但这只是做到了通过 Android 的文件管理工具来选择图片上传,而且不是我们常见的可以选择相机拍照,或者是直接访问相册来取图片。
H5页面的标签
<input type="file" accept=".jpeg, .jpg, .png" name="upload_file" id="js-title-img-input">
AndroidManifest权限
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-feature android:name="android.hardware.camera" /> <!-- 使用照相机权限 -->
<uses-feature android:name="android.hardware.camera.autofocus" /> <!-- 自动聚焦权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
由于安卓6.0之后只在Manifest文件中写上个权限列表,已经不行了,需要写代码动态申请权限,请看
Android permission 访问权限大全
在 Application 的 onCreate 中
//兼容7.0拍照
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
}
自定义 WebChromeClien
class MyWebChromeClient extends WebChromeClient {
其他代码、、、
// For Android < 3.0
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
WebCameraHelper.getInstance().mUploadMessage = uploadMsg;
WebCameraHelper.getInstance().showOptions(CubeAndroid.this);
}
// For Android > 4.1.1
public void openFileChooser(ValueCallback<Uri> uploadMsg,
String acceptType, String capture) {
WebCameraHelper.getInstance().mUploadMessage = uploadMsg;
WebCameraHelper.getInstance().showOptions(CubeAndroid.this);
}
// For Android > 5.0支持多张上传
@Override
public boolean onShowFileChooser(WebView webView,
ValueCallback<Uri[]> uploadMsg,
FileChooserParams fileChooserParams) {
WebCameraHelper.getInstance().mUploadCallbackAboveL = uploadMsg;
WebCameraHelper.getInstance().showOptions(CubeAndroid.this);
return true;
}
}
最重要的核心类 WebCameraHelper
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.provider.MediaStore;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import com.example.…….util.FileUtil;
import com.example.…….util.PermissionUtil;
/**
* @desc web页面调用本地照相机、图库的相关助手
*/
public class WebCameraHelper {
private static class SingletonHolder {
static final WebCameraHelper INSTANCE = new WebCameraHelper();
}
public static WebCameraHelper getInstance() {
return SingletonHolder.INSTANCE;
}
/**
* 图片选择回调
*/
public ValueCallback<Uri> mUploadMessage;
public ValueCallback<Uri[]> mUploadCallbackAboveL;
public Uri fileUri;
public static final int TYPE_REQUEST_PERMISSION = 3;
public static final int TYPE_CAMERA = 1;
public static final int TYPE_GALLERY = 2;
/**
* 包含拍照和相册选择
*/
public void showOptions(final Activity act) {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(act);
alertDialog.setOnCancelListener(new ReOnCancelListener());
alertDialog.setTitle("选择");
alertDialog.setItems(new CharSequence[]{"相机", "相册"},
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == 0) {
PermissionUtil permissionUtil = new PermissionUtil(act);
if (permissionUtil.isCamera()) {
toCamera(act);
}
} else {
Intent i = new Intent(
Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI);// 调用android的图库
act.startActivityForResult(i,
TYPE_GALLERY);
}
}
});
alertDialog.show();
}
/**
* 点击取消的回调
*/
private class ReOnCancelListener implements
DialogInterface.OnCancelListener {
@Override
public void onCancel(DialogInterface dialogInterface) {
if (mUploadMessage != null) {
mUploadMessage.onReceiveValue(null);
mUploadMessage = null;
}
if (mUploadCallbackAboveL != null) {
mUploadCallbackAboveL.onReceiveValue(null);
mUploadCallbackAboveL = null;
}
}
}
/**
* 请求拍照
*
* @param act
*/
public void toCamera(Activity act) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);// 调用android的相机
// 创建一个文件保存图片
fileUri = Uri.fromFile(FileUtil.getImgFile(act.getApplicationContext()));
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
act.startActivityForResult(intent, TYPE_CAMERA);
}
/**
* startActivityForResult之后要做的处理
*
* @param requestCode
* @param resultCode
* @param intent
*/
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == TYPE_CAMERA) { // 相册选择
if (resultCode == -1) {//RESULT_OK = -1,拍照成功
if (mUploadCallbackAboveL != null) { //高版本SDK处理方法
Uri[] uris = new Uri[]{fileUri};
mUploadCallbackAboveL.onReceiveValue(uris);
mUploadCallbackAboveL = null;
} else if (mUploadMessage != null) { //低版本SDK 处理方法
mUploadMessage.onReceiveValue(fileUri);
mUploadMessage = null;
} else {
// Toast.makeText(CubeAndroid.this, "无法获取数据", Toast.LENGTH_LONG).show();
}
} else { //拍照不成功,或者什么也不做就返回了,以下的处理非常有必要,不然web页面不会有任何响应
if (mUploadCallbackAboveL != null) {
mUploadCallbackAboveL.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, intent));
mUploadCallbackAboveL = null;
} else if (mUploadMessage != null) {
mUploadMessage.onReceiveValue(fileUri);
mUploadMessage = null;
} else {
// Toast.makeText(CubeAndroid.this, "无法获取数据", Toast.LENGTH_LONG).show();
}
}
} else if (requestCode == TYPE_GALLERY) {// 相册选择
if (mUploadCallbackAboveL != null) {
mUploadCallbackAboveL.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, intent));
mUploadCallbackAboveL = null;
} else if (mUploadMessage != null) {
Uri result = intent == null || resultCode != Activity.RESULT_OK ? null : intent.getData();
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
} else {
// Toast.makeText(CubeAndroid.this, "无法获取数据", Toast.LENGTH_LONG).show();
}
}
}
}
还需要一个小小的文件管理类,来获取缓存图库
public class FileUtil {
public static final String IMAGE_NAME = "Image";
/**
* @param context 上下文对象
* @param dir 存储目录
* @return
*/
public static String getFilePath(Context context, String dir) {
String directoryPath = "";
//判断SD卡是否可用
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
directoryPath = context.getExternalFilesDir(dir).getAbsolutePath();
// directoryPath =context.getExternalCacheDir().getAbsolutePath() ;
} else {
//没内存卡就存机身内存
directoryPath = context.getFilesDir() + File.separator + dir;
// directoryPath=context.getCacheDir()+File.separator+dir;
}
File file = new File(directoryPath);
if (!file.exists()) {//判断文件目录是否存在
file.mkdirs();
}
// Common.Log("getFilePath", directoryPath);
return directoryPath;
}
// 其他代码
……
// 图片缓存路径
public static String getImageCacheDirPath(Context appContext) {
String imagePath = getFilePath(appContext, IMAGE_NAME);
return imagePath;
}
public static File getImgFile(Context context) {
File file = new File(getImageCacheDirPath(context));
if (!file.exists()) {
file.mkdirs();
}
String imgName = new SimpleDateFormat("yyyyMMdd_HHmmss")
.format(new Date());
File imgFile = new File(file.getAbsolutePath() + File.separator
+ "IMG_" + imgName + ".jpg");
return imgFile;
}
}
然后在Activity或Fragment中。只要设置一下WebChromeClient,然后在onActivityResult中做返回处理
webView.setWebChromeClient(new MyWebChromeClient());//设置WebChromeClient
……
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
WebCameraHelper.getInstance().onActivityResult(requestCode, resultCode, intent);
}
转载请注明:隨習筆記 » webView 调用本地照相、图库