在 Android > 6.0 中,第二次从图库中访问图像时出现安全权限异常

Posted

技术标签:

【中文标题】在 Android > 6.0 中,第二次从图库中访问图像时出现安全权限异常【英文标题】:In Android >6.0 getting Security Permission Exception while accessing image from gallery the second time 【发布时间】:2016-11-08 22:46:30 【问题描述】:

我是 android 新手,我正在一个 android 现有项目中工作。该应用程序在 android 版本 >6.0 上崩溃,但有以下异常。基本上应用程序正在从图库中选择照片,这在第一次和第二次都可以正常工作以后应用程序崩溃,出现权限拒绝异常。

java.lang.SecurityException: Permission Denial: 读取 com.google.android.apps.photos.contentprovider.MediaContentProvider 乌里 content://com.google.android.apps.photos.contentprovider/0/1/content%3A%2F%2Fmedia%2Fexternal%2Fimages%2Fmedia%2F1022/ORIGINAL/NONE/256350537 从 pid=7789, uid=10145 需要导出提供程序,或者 grantUriPermission()

我浏览了几个链接并检查了 android 是否引入了运行时权限,并且我使用下面的代码来检查运行时权限。

到目前为止我尝试过的事情......

    在清单中添加了权限。

2.从代码中检查运行时权限。

@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" />

【问题讨论】:

试试这个link。 我可以看看你的清单文件吗?? @jankigadhiya 我在问题中添加了清单权限列表。 【参考方案1】:

问题不在于您的清单权限,而在于正在使用的 URI。您是如何获得 URI 的? logcat 输出告诉您该 URI 用于未导出的内容提供程序,或者该 URI 未在授予对 ContentProvider 的临时访问权限的 Intent 中提供。

【讨论】:

嗨@Larry 我刚刚发现这个异常我没有进入6.0(这也是Mashmello)。所以正如你所说,这不是运行时权限异常。但是由于我对 android 很陌生,我无法理解您的建议,如果我可以分享我的代码的某些部分,这将帮助您指出问题,请告诉我。 你从哪里得到的 Uri? 我知道对你的问题的回应有点晚了因为我的工作是在 ios 和 android 之间切换。对于您的问题-:有多个活动和 PhotoDetailsActivity 从 OnactivityResult URi = data.getDta(); 获取 URi当他们将存储的 URi 从共享偏好传递到其他活动时,它就会崩溃。所以问题在于其他活动无法访问 URi。我确实从图库应用程序中选择图像进行了测试,我的应用程序没有崩溃,但是如果用户从照片应用程序中选择图像,它就会崩溃。【参考方案2】:

经过大量研究,我能够解决该问题。导致该错误的原因是谷歌照片需要一个可持久的图像 URI,即使您在清单文件中拥有运行时权限和标志的所有代码。

在以下答案的帮助下,我已经解决了我的问题。 https://***.com/a/29588566/1842304

【讨论】:

【参考方案3】:

记下您在 android M 下面的清单中工作的所有权限。我们不需要 android M 的任何额外权限。我们只需要在运行时请求。

并像这样请求您的许可。更改清单中的权限(仅危险权限)。把它放在 onCreate 中

///  granting permission  ////
    if(!checkPermission())
    
        requestPermission();
    
 /////////////////////////////

在课堂上添加这些

    ///////////////////////   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;
    


////////////////////////////////////////////////////////////////////////

【讨论】:

嗨哈什米。我试图在我的运行时权限中使用 Manifest.permission.READ_USER_DICTIONARY 但它无法识别它。这可能看起来很愚蠢的问题,但我需要导入任何东西,以便班级能够识别此权限。我可以在清单中添加 READ_USER_DICTIONARY 权限。 奇怪的问题,你的其他权限是如何工作的。尝试添加这个'import android.Manifest' 缺少权限时会出现安全异常。因此,尝试跟踪错误。如果清单具有相同的权限并且它在 android M 下工作。您的运行时权限代码无法正常工作。查看编辑。【参考方案4】:

试试这个解决方案

在您的 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

它对我有用

【讨论】:

我尝试上述方法仍然崩溃,但出现相同的异常。而且我还使用 WRITE_EXTERNAL_STORAGE 和 READ_EXTERNAL_STORAGE 来获取图库图像访问运行时权限,还是我需要一些不同的运行时权限来访问照片?

以上是关于在 Android > 6.0 中,第二次从图库中访问图像时出现安全权限异常的主要内容,如果未能解决你的问题,请参考以下文章

第二次从相机拍摄时无法加载图像

fmdb 路径并第二次从另一个 viewController 使用 db

IBM Worklight 6.0 - iOS 应用程序总是停留在第二次启动

无法在类内第二次设置字符串类型[关闭]

选择排序

在移动设备上进行第二次音频录制后未触发 SampleDataEvent