关于uri部分未适配7.0,需要的可以添加
图片工具类
public class ImageUtil {
private static final String TAG ="ImageUtil";
/**
* go for Album. 相册
*/
public static final Intent choosePicture() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
return Intent.createChooser(intent, null);
}
/**
* go for camera. 相机
*/
public static final Intent takeBigPicture() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, newPictureUri(getNewPhotoPath()));
return intent;
}
public static final String getDirPath() {
return Environment.getExternalStorageDirectory().getPath() + "/UploadImage";
}
private static final String getNewPhotoPath() {
return getDirPath() + "/" + System.currentTimeMillis() + ".jpg";
}
public static final String retrievePath(Context context, Intent sourceIntent, Intent dataIntent) {
String picPath = null;
try {
Uri uri;
if (dataIntent != null) {
uri = dataIntent.getData();
if (uri != null) {
picPath = ContentUtil.getPath(context, uri);
}
if (isFileExists(picPath)) {
return picPath;
}
Log.w(TAG, String.format("retrievePath failed from dataIntent:%s, extras:%s", dataIntent, dataIntent.getExtras()));
}
if (sourceIntent != null) {
uri = sourceIntent.getParcelableExtra(MediaStore.EXTRA_OUTPUT);
if (uri != null) {
String scheme = uri.getScheme();
if (scheme != null && scheme.startsWith("file")) {
picPath = uri.getPath();
}
}
if (!TextUtils.isEmpty(picPath)) {
File file = new File(picPath);
if (!file.exists() || !file.isFile()) {
Log.w(TAG, String.format("retrievePath file not found from sourceIntent path:%s", picPath));
}
}
}
return picPath;
} finally {
Log.d(TAG, "retrievePath(" + sourceIntent + "," + dataIntent + ") ret: " + picPath);
}
}
private static final Uri newPictureUri(String path) {
return Uri.fromFile(new File(path));
}
private static final boolean isFileExists(String path) {
if (TextUtils.isEmpty(path)) {
return false;
}
File f = new File(path);
if (!f.exists()) {
return false;
}
return true;
}
}
第二个工具类
public class ContentUtil {
@SuppressLint("NewApi")
public static final String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return String.format("%s/%s", Environment.getExternalStorageDirectory().getPath(), split[1]);
}
// TODO handle non-primary volumes
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{split[1]};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
// Return the remote address
if (isGooglePhotosUri(uri)) {
return uri.getLastPathSegment();
}
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @param selection (Optional) Filter used in the query.
* @param selectionArgs (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
*/
public static final String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
Cursor cursor = null;
try {
cursor = context.getContentResolver().query(uri, new String[]{MediaStore.Images.Media.DATA}
, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
final int index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
return cursor.getString(index);
}
} finally {
if (cursor != null) {
cursor.close();
}
}
return null;
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
public static final boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
public static final boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
public static final boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is Google Photos.
*/
public static final boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
}
权限处理工具类 这个可以使用其他的
/**
* 权限管理工具 (针对Android 6.0 系统)
* Created by AlexTam on 2016/10/14.
*/
public class PermissionUtil {
private static PermissionUtil permissionUtil = null;
private static final String PERMISSIONS_CAMERA = Manifest.permission.CAMERA;
private static final String PERMISSIONS_WRITE_STORAGE = Manifest.permission.WRITE_EXTERNAL_STORAGE;
private static final String PERMISSIONS_READ_STORAGE = Manifest.permission.READ_EXTERNAL_STORAGE;
private static final String PERMISSIONS_PHONE = Manifest.permission.READ_PHONE_STATE;
private static final String PERMISSIONS_ACCOUNTS = Manifest.permission.GET_ACCOUNTS;
private static final String PERMISSIONS_LOCATION = Manifest.permission.ACCESS_FINE_LOCATION;
private static final String PERMISSIONS_AUDIO = Manifest.permission.RECORD_AUDIO;
public static final boolean isOverMarshmallow() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
}
/**
* @param activity
* @param permissionName such as Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE.
* @return
*/
public static final boolean isPermissionValid(Activity activity, String permissionName) {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int checkCallPhonePermission = ContextCompat.checkSelfPermission(activity, permissionName);
if (checkCallPhonePermission == PackageManager.PERMISSION_GRANTED) {
return true;
} else {
return false;
}
} else {
return true;
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* to find the permissions which were denied in this device.
*/
@TargetApi(value = Build.VERSION_CODES.M)
public static final List<String> findDeniedPermissions(Activity activity, List<String> permissions) {
if (permissions == null || permissions.size() == 0) {
return null;
} else {
List<String> denyPermissions = new ArrayList<>();
for (String value : permissions) {
try {
if (activity.checkSelfPermission(value) != PackageManager.PERMISSION_GRANTED) {
denyPermissions.add(value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
return denyPermissions;
}
}
/**
* request Permissions.
*
* @param activity
* @param requestCode
* @param mListPermissions
*/
@TargetApi(value = Build.VERSION_CODES.M)
public static final void requestPermissions(Activity activity, int requestCode, List<String> mListPermissions) {
if (mListPermissions == null || mListPermissions.size() == 0) {
return;
}
if (!isOverMarshmallow()) {
// should not be invoked when it is below Android 6.0.
return;
} else {
List<String> deniedPermissionList = findDeniedPermissions(activity, mListPermissions);
if (deniedPermissionList != null && deniedPermissionList.size() > 0) {
activity.requestPermissions(deniedPermissionList.toArray(new String[deniedPermissionList.size()]),
requestCode);
}
}
}
}
自定义WebChomeClient
public class MyWebChomeClient extends WebChromeClient {
private OpenFileChooserCallBack mOpenFileChooserCallBack;
public MyWebChomeClient(OpenFileChooserCallBack openFileChooserCallBack) {
mOpenFileChooserCallBack = openFileChooserCallBack;
}
/**
* 4.4X以下回调 android 3.0以上,android4.0以下:
* @param uploadMsg
* @param acceptType
*/
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
mOpenFileChooserCallBack.openFileChooserCallBack(uploadMsg, acceptType);
}
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
openFileChooser(uploadMsg, "");
}
//android 4.0 - android 4.3 && android4.4.4
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
openFileChooser(uploadMsg, acceptType);
}
/**
* 该方法的作用:告诉当前app 打开一个文件选择器 如相册,启动拍照或打开本地文件管理器
* webView加载包含上传文件的表单按钮,html定义了input标签,同同时input的type为file,手指点击该按钮
* 回调onShowFileChooser方法,在这个重写的方法里打开相册 启动相机 或打开本地文件管理器,甚至做其他逻辑操作
* 点击一次回调一次的前提是请求被取消,而取消请求回调的方法:给ValueCallBack接口的onReceiveValue抽象方法传入null
* 同时onShowFileChooser方法返回true
*
* 4.4X以上回调onShowFileChooser(替代)4.4X以下回调openFileChooser(隐藏);只重写某一个会造成有的系统点击没有反应
* 区别:
* 1:前者ValueCallback接口回传一个Uri数组,后者回传一个Uri对象,在onActivityResult回调方法中调用
* ValueCallback接口方法onReceiveValue传入参数特别注意
* for android 5.0+ 回调onShowFileChooser方法,onReceiveVlue传入Uri对象数组
* for android 5.0- 回调openFileChooser方法,onReceiveVlue传入Uri对象
*
* 2:前者将后者的 acceptType、capture封装成FileChooserParams抽象类
*/
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback,
FileChooserParams fileChooserParams) {
return mOpenFileChooserCallBack.openFileChooserCallBackAndroid5(webView, filePathCallback, fileChooserParams);
}
public interface OpenFileChooserCallBack {
// for API - Version below 5.0.
void openFileChooserCallBack(ValueCallback<Uri> uploadMsg, String acceptType);
// for API - Version above 5.0 (contais 5.0).
boolean openFileChooserCallBackAndroid5(WebView webView, ValueCallback<Uri[]> filePathCallback,
FileChooserParams fileChooserParams);
}
将以上四个工具类放在同一包下,使用方法示例:
成员变量:
private WebView mWebView;
private static final int REQUEST_CODE_PICK_IMAGE = 0;
private static final int REQUEST_CODE_IMAGE_CAPTURE = 1;
private Intent mSourceIntent;
private ValueCallback<Uri> mUploadMsg;
public ValueCallback<Uri[]> mUploadMsgForAndroid5;
// permission Code
private static final int P_CODE_PERMISSIONS = 101;
onCreate()方法中:
mWebView.getSettings().setAllowContentAccess(true);
mWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true); //设置js可以直接打开窗口,如window.open(),默认为false
mWebView.getSettings().setJavaScriptEnabled(true); //是否允许执行js,默认为false。设置true时,会提醒可能造成XSS漏洞
mWebView.getSettings().setSupportZoom(true); //是否可以缩放,默认true
mWebView.getSettings().setAllowFileAccess(true); // 设置允许访问文件数据
mWebView.getSettings().setBuiltInZoomControls(false); //是否显示缩放按钮,默认false
mWebView.getSettings().setUseWideViewPort(true); //设置此属性,可任意比例缩放。大视图模式
mWebView.getSettings().setLoadWithOverviewMode(true); //和setUseWideViewPort(true)一起解决网页自适应问题
mWebView.getSettings().setAppCacheEnabled(true); //是否使用缓存
mWebView.getSettings().setDomStorageEnabled(true); //DOM Storage
mWebView.setWebViewClient(new android.webkit.WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
});
mWebView.addJavascriptInterface(new JsInterface(mActivity), "PartnerHome");
mWebView.setWebChromeClient(new MyWebChomeClient(this));
mWebView.setWebViewClient(new WebViewClient() {
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
handler.proceed();
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {//用于打开支付宝
/*view.loadUrl(url);
return true;*/
if (url.startsWith("http:") || url.startsWith("https:")) {
return false;
}
try {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
} catch (Exception e) {
}
return true;
}
@Override
public void onPageFinished(WebView view, String url) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
CookieSyncManager.getInstance().sync();
} else {
CookieManager.getInstance().flush();
}
}
});
fixDirPath();
mWebView.loadUrl(url);
其他方法
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != Activity.RESULT_OK) { //==Activity.RESULT_CANCELED
if (mUploadMsg != null) {
mUploadMsg.onReceiveValue(null);
}
if (mUploadMsgForAndroid5 != null) { // for android 5.0+
mUploadMsgForAndroid5.onReceiveValue(null);
}
return;
}
switch (requestCode) {
case REQUEST_CODE_IMAGE_CAPTURE:
case REQUEST_CODE_PICK_IMAGE: {
try {
//for android 5.0- 回调openFileChooser方法,onReceiveVlue传入Uri对象
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
if (mUploadMsg == null) {
return;
}
String sourcePath = ImageUtil.retrievePath(mActivity, mSourceIntent, data);
if (TextUtils.isEmpty(sourcePath) || !new File(sourcePath).exists()) {
Log.e(TAG, "sourcePath empty or not exists.");
break;
}
Uri uri = null;
uri = Uri.fromFile(new File(sourcePath));
mUploadMsg.onReceiveValue(uri);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (mUploadMsgForAndroid5 == null) { // for android 5.0+
return;
}
String sourcePath = ImageUtil.retrievePath(mActivity, mSourceIntent, data);
if (TextUtils.isEmpty(sourcePath) || !new File(sourcePath).exists()) {
Log.e(TAG, "sourcePath empty or not exists.");
break;
}
Uri uri = null;
try {
uri = Uri.fromFile(new File(sourcePath));
} catch (Exception e) {
e.printStackTrace();
}
//for android 5.0+ 回调onShowFileChooser方法,onReceiveVlue传入Uri对象数组
mUploadMsgForAndroid5.onReceiveValue(new Uri[]{uri});
}
} catch (Exception e) {
e.printStackTrace();
}
break;
}
}
}
/**
* 选择完文件之后调用
*
* @param uploadMsg
* @param acceptType
*/
@Override
public void openFileChooserCallBack(ValueCallback<Uri> uploadMsg, String acceptType) {
mUploadMsg = uploadMsg;
showOptions();
}
/**
* 选择完文件之后调用 5.0以上
*/
@Override
public boolean openFileChooserCallBackAndroid5(WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
mUploadMsgForAndroid5 = filePathCallback; //选中的图片uri数组
showOptions();
return true;
}
public void showOptions() {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(mActivity);
alertDialog.setOnCancelListener(new DialogOnCancelListener());
alertDialog.setTitle("请选择操作");
// gallery, camera.
String[] options = {"相册", "拍照"};
alertDialog.setItems(options, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == 0) {
//点击了相册
if (PermissionUtil.isOverMarshmallow()) {
if (!PermissionUtil.isPermissionValid(mActivity, Manifest.permission.READ_EXTERNAL_STORAGE)) {
ToastUtils.showToast("请去\"设置\"中开启本应用的图片媒体访问权限");
restoreUploadMsg();
requestPermissionsAndroidM();
return;
}
}
try {
mSourceIntent = ImageUtil.choosePicture();
startActivityForResult(mSourceIntent, REQUEST_CODE_PICK_IMAGE);
} catch (Exception e) {
e.printStackTrace();
ToastUtils.showToast("请去\"设置\"中开启本应用的图片媒体访问权限");
restoreUploadMsg();
}
} else {
//点击了拍照
if (PermissionUtil.isOverMarshmallow()) {
if (!PermissionUtil.isPermissionValid(mActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
ToastUtils.showToast("请去\"设置\"中开启本应用的图片媒体访问权限");
restoreUploadMsg();
requestPermissionsAndroidM();
return;
}
if (!PermissionUtil.isPermissionValid(mActivity, Manifest.permission.CAMERA)) {
ToastUtils.showToast("请去\"设置\"中开启本应用的相机权限");
restoreUploadMsg();
requestPermissionsAndroidM();
return;
}
}
try {
mSourceIntent = ImageUtil.takeBigPicture();
startActivityForResult(mSourceIntent, REQUEST_CODE_IMAGE_CAPTURE);
} catch (Exception e) {
e.printStackTrace();
ToastUtils.showToast("请去\"设置\"中开启本应用的相机和图片媒体访问权限");
restoreUploadMsg();
}
}
}
}
);
alertDialog.show();
}
private void fixDirPath() {
String path = ImageUtil.getDirPath();
File file = new File(path);
if (!file.exists()) {
file.mkdirs();
}
}
private class DialogOnCancelListener implements DialogInterface.OnCancelListener {
@Override
public void onCancel(DialogInterface dialogInterface) {
restoreUploadMsg();
}
}
//重置 解决无法重复选择
private void restoreUploadMsg() {
if (mUploadMsg != null) {
mUploadMsg.onReceiveValue(null);
mUploadMsg = null;
} else if (mUploadMsgForAndroid5 != null) {
mUploadMsgForAndroid5.onReceiveValue(null);
mUploadMsgForAndroid5 = null;
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case P_CODE_PERMISSIONS:
requestResult(permissions, grantResults);
restoreUploadMsg();
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
private void requestPermissionsAndroidM() { //请求权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
List<String> needPermissionList = new ArrayList<>();
needPermissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
needPermissionList.add(Manifest.permission.READ_EXTERNAL_STORAGE);
needPermissionList.add(Manifest.permission.CAMERA);
PermissionUtil.requestPermissions(mActivity, P_CODE_PERMISSIONS, needPermissionList);
} else {
return;
}
}
public void requestResult(String[] permissions, int[] grantResults) {
ArrayList<String> needPermissions = new ArrayList<String>();
for (int i = 0; i < grantResults.length; i++) {
if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
if (PermissionUtil.isOverMarshmallow()) {
needPermissions.add(permissions[i]);
}
}
}
if (needPermissions.size() > 0) {
StringBuilder permissionsMsg = new StringBuilder();
for (int i = 0; i < needPermissions.size(); i++) {
String strPermissons = needPermissions.get(i);
if (Manifest.permission.WRITE_EXTERNAL_STORAGE.equals(strPermissons)) {
permissionsMsg.append("," + getString(R.string.permission_storage));
} else if (Manifest.permission.READ_EXTERNAL_STORAGE.equals(strPermissons)) {
permissionsMsg.append("," + getString(R.string.permission_storage));
} else if (Manifest.permission.CAMERA.equals(strPermissons)) {
permissionsMsg.append("," + getString(R.string.permission_camera));
}
}
String strMessage = "请允许使用\"" + permissionsMsg.substring(1).toString() + "\"权限, 以正常使用APP的所有功能.";
}
}
最后,如果打包发布时进行了混淆,应避免将这些类混淆,主要是集成WebChromeClient的那个类,加上这句话:
-keepclassmembers class * extends android.webkit.WebChromeClient {
public void openFileChooser(...);
}
网友评论