在 Android >6.0 中第二次访问图库中的图像时出现安全权限异常
In Android >6.0 getting Security Permission Exception while accessing image from gallery the second time
我是 android 的新手,我正在使用 android 现有 project.The 应用程序在 android 版本 >6.0 上崩溃,低于 exception.Basically 应用程序正在从图库中选择照片,这是第一次工作正常,第二次后应用程序崩溃并给出权限拒绝异常。
java.lang.SecurityException: Permission Denial: reading
com.google.android.apps.photos.contentprovider.MediaContentProvider
uri
content://com.google.android.apps.photos.contentprovider/0/1/content%3A%2F%2Fmedia%2Fexternal%2Fimages%2Fmedia%2F1022/ORIGINAL/NONE/256350537
from pid=7789, uid=10145 requires the provider be exported, or
grantUriPermission()
我浏览了几个链接并检查了 android 是否引入了 运行 时间权限,我使用下面的代码来检查 运行 时间权限。
到目前为止我尝试过的东西...
- 在清单中添加权限。
2.Checking 来自代码的运行时间许可。
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
Log.d("Enter", "onRequestPermissionsResult: ");
switch (requestCode){
case REQUEST_CODE_PERMISSION:{
Map<String,Integer> perms = new HashMap<>();
//Initialize the map with the permissions
perms.put(Manifest.permission.ACCESS_COARSE_LOCATION,PackageManager.PERMISSION_GRANTED);
perms.put(Manifest.permission.CAMERA,PackageManager.PERMISSION_GRANTED);
perms.put(Manifest.permission.READ_EXTERNAL_STORAGE,PackageManager.PERMISSION_GRANTED);
// perms.put(Manifest.permission.READ_USER_DICTIONARY,PackageManager.PERMISSION_GRANTED);
//Fill with actual results from user
if (grantResults.length > 0){
for (int i = 0 ; i < permissions.length ; i++){
perms.put(permissions[i],grantResults[i]);
//check for all permissions
if (perms.get(Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED
&& perms.get(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
&& perms.get(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED){
Log.d("Permission Granted", "onRequestPermissionsResult: ");
}else{
Log.d("Some", "onRequestPermissionsResult: ");
//if (perms.get(Manifest.permission.ACCESS_COARSE_LOCATION))
if (ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.CAMERA)
|| ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.ACCESS_COARSE_LOCATION)
|| ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.READ_EXTERNAL_STORAGE)){
new DialogInterface.OnClickListener(){
@Override
public void onClick (DialogInterface dialog, int which){
switch (which){
case DialogInterface.BUTTON_POSITIVE:
checkAndRequestPermission();
break;
case DialogInterface.BUTTON_NEGATIVE:
break;
}
}
};
}else{
Toast.makeText(this,"Go to Settings and enable Permissions",Toast.LENGTH_LONG).show();
}
}
}
}
}
}
}
private void showDialogOK(String message, DialogInterface.OnClickListener okListener){
new AlertDialog.Builder(this)
.setMessage(message)
.setPositiveButton("OK",okListener)
.setNegativeButton("Cancel",okListener)
.create()
.show();
}
}
它崩溃的那一行是:-
if (checkAndRequestPermission()){
InputStream fis = getContentResolver().openInputStream(Uri.parse(url)); //Crashing Line
BitmapFactory.decodeStream(fis, null, o);
fis.close();
}
以下是我的清单中使用的权限:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_USER_DICTIONARY"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS"/>
<uses-permission android:name="com.google.android.apps.photos.permission.GOOGLE_PHOTOS"/>
<!-- <uses-permission android:name="com.google.android.apps.photos.permission.GOOGLE_PHOTOS"/>-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
<!-- The following two permissions are not required to use
Google Maps Android API v2, but are recommended. -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="com.google.android.apps.photos.permission.GOOGLE_PHOTOS"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-feature android:name="android.hardware.location" android:required="true" />
<uses-feature android:name="android.hardware.location.gps" android:required="false" />
记下您在 android M 下面的清单中有效的所有权限。我们不需要 android M 的任何额外权限。我们只需在运行时请求即可。
并像这样请求您的许可。更改清单中的权限(仅危险权限)。把这个放在 onCreate
/// granting permission ////
if(!checkPermission())
{
requestPermission();
}
/////////////////////////////
并在 class 中添加这些
/////////////////////// permission for marshmallow ///////////////////
private boolean checkPermission(){
int result1 = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE);
int result2 = ContextCompat.checkSelfPermission(this, Manifest.permission.MODIFY_PHONE_STATE);
int result3 = ContextCompat.checkSelfPermission(this, Manifest.permission.PROCESS_OUTGOING_CALLS);
int result4 = ContextCompat.checkSelfPermission(this, Manifest.permission.PROCESS_INCOMING_CALLS);
int result5 = ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE);
if (result1 == PackageManager.PERMISSION_GRANTED && result2 == PackageManager.PERMISSION_GRANTED &&
result3 == PackageManager.PERMISSION_GRANTED && result4 == PackageManager.PERMISSION_GRANTED
&& result5 == PackageManager.PERMISSION_GRANTED){
return true;
} else {
//Toast.makeText(this,"You don't have permission to use further features",Toast.LENGTH_LONG).show();
return false;
}
}
private void requestPermission(){
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_PHONE_STATE) &&
ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.MODIFY_PHONE_STATE) &&
ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.PROCESS_OUTGOING_CALLS) &&
ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.PROCESS_INCOMING_CALLS) &&
ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CALL_PHONE)){
Toast.makeText(this,"Application needs permission to use your camera, calls, storage and location.",Toast.LENGTH_LONG).show();
} else {
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_PHONE_STATE,
Manifest.permission.MODIFY_PHONE_STATE, Manifest.permission.PROCESS_OUTGOING_CALLS,
Manifest.permission.PROCESS_INCOMING_CALLS, Manifest.permission.CALL_PHONE},1);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED &&
grantResults[1] == PackageManager.PERMISSION_GRANTED &&
grantResults[2] == PackageManager.PERMISSION_GRANTED &&
grantResults[3] == PackageManager.PERMISSION_GRANTED &&
grantResults[4] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this,"Permission Granted.",Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this,"Permission Denied.",Toast.LENGTH_LONG).show();
}
break;
}
}
////////////////////////////////////////////////////////////////////////
问题不在于您的清单权限,而在于所使用的 URI。你是怎么得到URI的? logcat 输出告诉您 URI 用于未导出的内容提供者,或者 URI 未在 Intent
中提供,该 Intent
授予对 ContentProvider
.[=12 的临时访问权限=]
试试这个解决方案
在您的 OnCreate() 方法中
@Override
protected void onCreate(Bundle savedInstanceState)
{
// your code
.................
// call dynamic permission
check_SD_CARD_Permissions();
}
public void check_SD_CARD_Permissions()
{
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int permissionCheck = this.checkSelfPermission("Manifest.permission.WRITE_EXTERNAL_STORAGE");
permissionCheck += this.checkSelfPermission("Manifest.permission.READ_EXTERNAL_STORAGE");
if (permissionCheck != 0) {
this.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, 1001); //Any number
}
}else{
Log.d(TAG, "checkBTPermissions: No need to check permissions. SDK version < LOLLIPOP.");
}
}
在AndroidManifest.xml
添加这些权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
并且targetSdkVersion必须是23
<uses-sdk
android:minSdkVersion="13"
android:targetSdkVersion="23" />
用
构建你的项目
Version : Android 6.0
最后在 project.properties 目标必须是 23
target=android-23
对我有用
经过大量研究,我能够修复 issue.The 错误,因为 google 照片需要一个持久的图像 URI,即使您拥有运行时权限和标志的所有代码在清单文件中。
在以下答案的帮助下,我已经解决了我的问题。
我是 android 的新手,我正在使用 android 现有 project.The 应用程序在 android 版本 >6.0 上崩溃,低于 exception.Basically 应用程序正在从图库中选择照片,这是第一次工作正常,第二次后应用程序崩溃并给出权限拒绝异常。
java.lang.SecurityException: Permission Denial: reading com.google.android.apps.photos.contentprovider.MediaContentProvider uri content://com.google.android.apps.photos.contentprovider/0/1/content%3A%2F%2Fmedia%2Fexternal%2Fimages%2Fmedia%2F1022/ORIGINAL/NONE/256350537 from pid=7789, uid=10145 requires the provider be exported, or grantUriPermission()
我浏览了几个链接并检查了 android 是否引入了 运行 时间权限,我使用下面的代码来检查 运行 时间权限。
到目前为止我尝试过的东西...
- 在清单中添加权限。
2.Checking 来自代码的运行时间许可。
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
Log.d("Enter", "onRequestPermissionsResult: ");
switch (requestCode){
case REQUEST_CODE_PERMISSION:{
Map<String,Integer> perms = new HashMap<>();
//Initialize the map with the permissions
perms.put(Manifest.permission.ACCESS_COARSE_LOCATION,PackageManager.PERMISSION_GRANTED);
perms.put(Manifest.permission.CAMERA,PackageManager.PERMISSION_GRANTED);
perms.put(Manifest.permission.READ_EXTERNAL_STORAGE,PackageManager.PERMISSION_GRANTED);
// perms.put(Manifest.permission.READ_USER_DICTIONARY,PackageManager.PERMISSION_GRANTED);
//Fill with actual results from user
if (grantResults.length > 0){
for (int i = 0 ; i < permissions.length ; i++){
perms.put(permissions[i],grantResults[i]);
//check for all permissions
if (perms.get(Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED
&& perms.get(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
&& perms.get(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED){
Log.d("Permission Granted", "onRequestPermissionsResult: ");
}else{
Log.d("Some", "onRequestPermissionsResult: ");
//if (perms.get(Manifest.permission.ACCESS_COARSE_LOCATION))
if (ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.CAMERA)
|| ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.ACCESS_COARSE_LOCATION)
|| ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.READ_EXTERNAL_STORAGE)){
new DialogInterface.OnClickListener(){
@Override
public void onClick (DialogInterface dialog, int which){
switch (which){
case DialogInterface.BUTTON_POSITIVE:
checkAndRequestPermission();
break;
case DialogInterface.BUTTON_NEGATIVE:
break;
}
}
};
}else{
Toast.makeText(this,"Go to Settings and enable Permissions",Toast.LENGTH_LONG).show();
}
}
}
}
}
}
}
private void showDialogOK(String message, DialogInterface.OnClickListener okListener){
new AlertDialog.Builder(this)
.setMessage(message)
.setPositiveButton("OK",okListener)
.setNegativeButton("Cancel",okListener)
.create()
.show();
}
}
它崩溃的那一行是:-
if (checkAndRequestPermission()){
InputStream fis = getContentResolver().openInputStream(Uri.parse(url)); //Crashing Line
BitmapFactory.decodeStream(fis, null, o);
fis.close();
}
以下是我的清单中使用的权限:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_USER_DICTIONARY"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS"/>
<uses-permission android:name="com.google.android.apps.photos.permission.GOOGLE_PHOTOS"/>
<!-- <uses-permission android:name="com.google.android.apps.photos.permission.GOOGLE_PHOTOS"/>-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
<!-- The following two permissions are not required to use
Google Maps Android API v2, but are recommended. -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="com.google.android.apps.photos.permission.GOOGLE_PHOTOS"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-feature android:name="android.hardware.location" android:required="true" />
<uses-feature android:name="android.hardware.location.gps" android:required="false" />
记下您在 android M 下面的清单中有效的所有权限。我们不需要 android M 的任何额外权限。我们只需在运行时请求即可。
并像这样请求您的许可。更改清单中的权限(仅危险权限)。把这个放在 onCreate
/// granting permission ////
if(!checkPermission())
{
requestPermission();
}
/////////////////////////////
并在 class 中添加这些
/////////////////////// permission for marshmallow ///////////////////
private boolean checkPermission(){
int result1 = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE);
int result2 = ContextCompat.checkSelfPermission(this, Manifest.permission.MODIFY_PHONE_STATE);
int result3 = ContextCompat.checkSelfPermission(this, Manifest.permission.PROCESS_OUTGOING_CALLS);
int result4 = ContextCompat.checkSelfPermission(this, Manifest.permission.PROCESS_INCOMING_CALLS);
int result5 = ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE);
if (result1 == PackageManager.PERMISSION_GRANTED && result2 == PackageManager.PERMISSION_GRANTED &&
result3 == PackageManager.PERMISSION_GRANTED && result4 == PackageManager.PERMISSION_GRANTED
&& result5 == PackageManager.PERMISSION_GRANTED){
return true;
} else {
//Toast.makeText(this,"You don't have permission to use further features",Toast.LENGTH_LONG).show();
return false;
}
}
private void requestPermission(){
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_PHONE_STATE) &&
ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.MODIFY_PHONE_STATE) &&
ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.PROCESS_OUTGOING_CALLS) &&
ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.PROCESS_INCOMING_CALLS) &&
ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CALL_PHONE)){
Toast.makeText(this,"Application needs permission to use your camera, calls, storage and location.",Toast.LENGTH_LONG).show();
} else {
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_PHONE_STATE,
Manifest.permission.MODIFY_PHONE_STATE, Manifest.permission.PROCESS_OUTGOING_CALLS,
Manifest.permission.PROCESS_INCOMING_CALLS, Manifest.permission.CALL_PHONE},1);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED &&
grantResults[1] == PackageManager.PERMISSION_GRANTED &&
grantResults[2] == PackageManager.PERMISSION_GRANTED &&
grantResults[3] == PackageManager.PERMISSION_GRANTED &&
grantResults[4] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this,"Permission Granted.",Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this,"Permission Denied.",Toast.LENGTH_LONG).show();
}
break;
}
}
////////////////////////////////////////////////////////////////////////
问题不在于您的清单权限,而在于所使用的 URI。你是怎么得到URI的? logcat 输出告诉您 URI 用于未导出的内容提供者,或者 URI 未在 Intent
中提供,该 Intent
授予对 ContentProvider
.[=12 的临时访问权限=]
试试这个解决方案
在您的 OnCreate() 方法中
@Override
protected void onCreate(Bundle savedInstanceState)
{
// your code
.................
// call dynamic permission
check_SD_CARD_Permissions();
}
public void check_SD_CARD_Permissions()
{
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int permissionCheck = this.checkSelfPermission("Manifest.permission.WRITE_EXTERNAL_STORAGE");
permissionCheck += this.checkSelfPermission("Manifest.permission.READ_EXTERNAL_STORAGE");
if (permissionCheck != 0) {
this.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, 1001); //Any number
}
}else{
Log.d(TAG, "checkBTPermissions: No need to check permissions. SDK version < LOLLIPOP.");
}
}
在AndroidManifest.xml
添加这些权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
并且targetSdkVersion必须是23
<uses-sdk
android:minSdkVersion="13"
android:targetSdkVersion="23" />
用
构建你的项目Version : Android 6.0
最后在 project.properties 目标必须是 23
target=android-23
对我有用
经过大量研究,我能够修复 issue.The 错误,因为 google 照片需要一个持久的图像 URI,即使您拥有运行时权限和标志的所有代码在清单文件中。
在以下答案的帮助下,我已经解决了我的问题。