1.FileProvider用于解决高版本的android系统出现的调用相机和相册不成功的问题
①. 权限申请
建议在你的BaseActivity中去增加两个方法。
public void onPermissionRequests(String permission, OnBooleanListener onBooleanListener) {
onPermissionListener = onBooleanListener;
Log.d("MainActivity", "0");
if (ContextCompat.checkSelfPermission(this,
permission)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
Log.d("MainActivity", "1");
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.READ_CONTACTS)) {
//权限已有
onPermissionListener.onClick(true);
} else {
//没有权限,申请一下
ActivityCompat.requestPermissions(this,
new String[]{permission},
1);
}
}else{
onPermissionListener.onClick(true);
Log.d("MainActivity", "2"+ContextCompat.checkSelfPermission(this,
permission));
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == 1) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//权限通过
if (onPermissionListener != null) {
onPermissionListener.onClick(true);
}
} else {
//权限拒绝
if (onPermissionListener != null) {
onPermissionListener.onClick(false);
}
}
return;
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
然后在你需要申请权限的地方调用这个方法就可以了
onPermissionRequests
②. 7.0相机问题
Android7.0中尝试传递 file:// URI 会触发 FileUriExposedException,因为在Android7.0之后Google认为直接使用本地
的根目录即file:// URI是不安全的操作,直接访问会抛出FileUriExposedExCeption异常,这就意味着在Android7.0以前
我们访问相机拍照存储时,如果使用URI的方式直接存储剪裁图片就会造成这个异常,那么如何解决这个问题呢?
Google为我们提供了FileProvider类,进行一种特殊的内容提供,FileProvider时ContentProvide的子类,它使用了和
内容提供器类似的机制来对数据进行保护,可以选择性地将封装过的Uri共享给外部,从而提高了应用的安全性。下面
就让我们看一下如何使用这个内容提供者进行数据访问的:
使用FileProvider获取Uri就会将以前的file:// URI准换成content:// URI,实现一种安全的应用间数据访问,内容提
供者作为Android的四大组件之一,使用同样需要在清单文件AndroidManifest.xml中进行注册的,注册方法如下:
首先
是准备工作,先在res文件夹下添加xml文件夹,然后创建一个文件file_paths,内容如下:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!--填写你要所要申请访问的目录地址,name最好是你的目录名,path是你要申请的目录--> <external-path name="camera_photos" path="." /> </paths>
然后在AndroidManifest.xml文件中添加
<!-- 这里直接复制就可以,需要注意的是authorities,以你的包名加上fileprovider,因为他需要唯一 --> <provider android:name="android.support.v4.content.FileProvider" android:authorities="包名.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"/> </provider>
这样准备工作就做好了,不要纠结着FileProvider,到时候直接用就可以,下面是调用代码:
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); File photoFile = createImagePathFile(MainActivity.this); intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); /* * 这里就是高版本需要注意的,需用使用FileProvider来获取Uri,同时需要注意getUriForFile * 方法第二个参数要与AndroidManifest.xml中provider的里面的属性authorities的值一致 * */ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); imageUriFromCamera = FileProvider.getUriForFile(MainActivity.this, "包名.fileprovider", photoFile); intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUriFromCamera); startActivityForResult(intent, GET_IMAGE_BY_CAMERA_U);
然后就没有然后了,结尾附几个Demo,很简单:
https://github.com/xuezj/FileProviderDemo
https://github.com/zhengzhong1/Android6.0PermissionsDemo
https://github.com/HelloWmz/PhotoDemo
2
.直接在webview中点击事件调用摄像头和相册就得重写webcromeClient方法
WebViewClient webViewClient = new WebViewClient() {
public OkHttpClient client = new OkHttpClient();
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
// ------5.0以上手机执行------
Uri uri = request.getUrl();
String url = uri.toString();
return shouldInterceptRequest(view, url);
}
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
String newUrl = StringUtil.getNewUrl(url);
Utils.CommonUtilLog(TAG, "old url=" + url);
Utils.CommonUtilLog(TAG, "new url=" + newUrl);
if (newUrl.equals(url)) {
return super.shouldInterceptRequest(view, url);
}
Request request1 = new Request.Builder()
.url(newUrl)
.build();
Response response = null;
try {
response = client.newCall(request1).execute();
} catch (IOException e) {
e.printStackTrace();
}
String type = Utils.getMimeType(newUrl);
Utils.CommonUtilLog(TAG, "type=" + type);
return new WebResourceResponse(type, response.header("content-encoding", "utf-8"), response.body().byteStream());
}
};
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && mWebView.canGoBack()) {
mWebView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
protected void onPause() {
super.onPause();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mWebView != null) {
mWebView.clearHistory();
((ViewGroup) mWebView.getParent()).removeView(mWebView);
mWebView.loadUrl("about:blank");
mWebView.stopLoading();
mWebView.setWebChromeClient(null);
mWebView.setWebViewClient(null);
mWebView.destroy();
mWebView = null;
}
}
/*
*=====HTML5调相机相册======
* 重写WebChromeClient方法
*/
WebChromeClient webChromeClient = new WebChromeClient() {
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
}
@Override
public boolean onShowFileChooser(WebView webView,
ValueCallback<Uri[]> filePathCallback,
FileChooserParams fileChooserParams) {
mUploadCallbackAboveL = filePathCallback;
take();
return true;
}
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
mUploadMessage = uploadMsg;
take();
}
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
mUploadMessage = uploadMsg;
take();
}
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
mUploadMessage = uploadMsg;
take();
}
};
private void take() {
File imageStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyApp"); // Create the storage directory if it does not exist
if (!imageStorageDir.exists()) {
imageStorageDir.mkdirs();
}
File file = new File(imageStorageDir + File.separator + "IMG_" + String.valueOf(System.currentTimeMillis()) + ".jpg");
imageUri = Uri.fromFile(file);
final List<Intent> cameraIntents = new ArrayList();
final Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
final PackageManager packageManager = getPackageManager();
final List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0);
for (ResolveInfo res : listCam) {
final String packageName = res.activityInfo.packageName;
final Intent i = new Intent(captureIntent);
i.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
i.setPackage(packageName);
i.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
cameraIntents.add(i);
}
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
Intent chooserIntent = Intent.createChooser(i, "Image Chooser");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[]{}));
RemoteWebActivity.this.startActivityForResult(chooserIntent, FILE_CHOOSER_RESULT_CODE);
}
@SuppressWarnings("null")
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void onActivityResultAboveL(int requestCode, int resultCode, Intent data) {
if (requestCode != FILE_CHOOSER_RESULT_CODE
|| mUploadCallbackAboveL == null) {
return;
}
Uri[] results = null;
if (resultCode == Activity.RESULT_OK) {
if (data == null) {
results = new Uri[]{imageUri};
} else {
String dataString = data.getDataString();
ClipData clipData = data.getClipData();
if (clipData != null) {
results = new Uri[clipData.getItemCount()];
for (int i = 0; i < clipData.getItemCount(); i++) {
ClipData.Item item = clipData.getItemAt(i);
results[i] = item.getUri();
}
}
if (dataString != null)
results = new Uri[]{Uri.parse(dataString)};
}
}
if (results != null) {
mUploadCallbackAboveL.onReceiveValue(results);
mUploadCallbackAboveL = null;
} else {
results = new Uri[]{imageUri};
mUploadCallbackAboveL.onReceiveValue(results);
mUploadCallbackAboveL = null;
}
return;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == FILE_CHOOSER_RESULT_CODE) {
if (null == mUploadMessage && null == mUploadCallbackAboveL) return;
Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
if (mUploadCallbackAboveL != null) {
onActivityResultAboveL(requestCode, resultCode, data);
} else if (mUploadMessage != null) {
if (result != null) {
String path = getPath(getApplicationContext(),
result);
Uri uri = Uri.fromFile(new File(path));
mUploadMessage
.onReceiveValue(uri);
} else {
mUploadMessage.onReceiveValue(imageUri);
}
mUploadMessage = null;
}
}
}
@SuppressLint("NewApi")
@TargetApi(Build.VERSION_CODES.KITKAT)
public static 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 Environment.getExternalStorageDirectory() + "/" + split[1];
} // TODO handle non-primary volumes
} 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);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {column};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null) cursor.close();
}
return null;
}
public static 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 boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
在h5界面必须有那么一行代码
<div class =” jdmodel-first-bottom “> |
|
|
<img class =” jdmodel-first-bottom-button ” src =” /statics/jdmodel/css/image/bottom.png “/> |
|
|
|
<input type =” file ” id =” cameraInput ” style =” display: none ” accept =” image/* “/> |
|
|
|
<img class =” jdmodel-first-bottom-photograph ” src =” /statics/jdmodel/css/image/photograph.png ” id =” photoBtnId “/> |
|
|
|
</div> |
返回后的图片会放到id为cameraInput的界面位置!!!