【问题标题】:Run Time Permission check in Android 7.0Android 7.0 中的运行时权限检查
【发布时间】:2017-03-21 05:53:19
【问题描述】:

当我尝试在 sdcard 中创建文件时:

newFile.createNewFile();

我得到的日志如下:

W/System.err: java.io.IOException: Permission denied

W/System.err:在 java.io.UnixFileSystem.createFileExclusively0(Native Method)

W/System.err:在 java.io.UnixFileSystem.createFileExclusively(UnixFileSystem.java:280)

W/System.err:在 java.io.File.createNewFile(File.java:948)

我知道原因是没有授予危险的运行时权限(WRITE_EXTERNAL_STORAGE),但是当我尝试在 PackageManagerService.java checkUidPermission() 中打印日志时,发现它没有被调用。

我想知道原生方法(如java.io.UnixFileSystem.createFileExclusively0)如何判断未授予运行时权限?

【问题讨论】:

  • 我有同样的错误
  • 你是怎么解决的......
  • 所有权限在运行时被破解

标签: java android android-permissions


【解决方案1】:

在 Android M 中,权限可以由用户在运行时授予/撤销,而不是在安装时。

因此,当针对具有 M 及更高版本的设备时,您需要检查权限是否被授予我使用此类来检查权限,希望对您有所帮助:

/**
 * Created by Mani on 17/09/16.
 * Making the runtime app permissions for android marshmallow+ devices cleaner
 * Specify all the requests here
 */
public class MarshMallowPermission {
    private static final int CALL_PERMISSION_REQUEST_CODE = 1;
    public static final int EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE = 2;
    public static final int CAMERA_PERMISSION_REQUEST_CODE = 3;
    public static final int SHORT_CUT_PERMISSION_REQUEST_CODE = 4;
    private Activity activity;


    public MarshMallowPermission(Activity activity) {
        this.activity = activity;
    }

    public boolean checkPermissionForCall(){
        int result = ContextCompat.checkSelfPermission(activity, Manifest.permission.CALL_PHONE);
        return result == PackageManager.PERMISSION_GRANTED;
    }

    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    public boolean checkPermissionForShortCut(){


        int result = PermissionChecker.checkSelfPermission(activity,Manifest.permission.INSTALL_SHORTCUT);
        return result == PermissionChecker.PERMISSION_GRANTED;
    }


    public boolean checkPermissionForExternalStorage(){
        int result = ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
        int readStorage = 0;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            readStorage = ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE);
        }

        return result == PackageManager.PERMISSION_GRANTED && readStorage == PackageManager.PERMISSION_GRANTED;
    }

    public boolean checkPermissionForCamera(){
        int result = ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA);
        return result == PackageManager.PERMISSION_GRANTED;
    }


    public void requestPermissionForCall(){
        if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.CALL_PHONE)){
            Toast.makeText(activity, "Call Phone Permission required to launch Dialer. Please allow in App Settings for additional functionality.", Toast.LENGTH_LONG).show();
        } else {
            ActivityCompat.requestPermissions(activity,new String[]{Manifest.permission.CALL_PHONE},CALL_PERMISSION_REQUEST_CODE);
        }
    }

    public void requestPermissionForExternalStorage(){
        if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)){
            Toast.makeText(activity, "External Storage permission required. Please allow in App Settings for additional functionality.", Toast.LENGTH_LONG).show();
        } else {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                ActivityCompat.requestPermissions(activity,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE},EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE);
            }else{
                ActivityCompat.requestPermissions(activity,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE);
            }
        }
    }

    public void requestPermissionForCamera(){
        if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.CAMERA)){
            Toast.makeText(activity, "Camera permission required. Please allow in App Settings for additional functionality.", Toast.LENGTH_LONG).show();
        } else {
            ActivityCompat.requestPermissions(activity,new String[]{Manifest.permission.CAMERA},CAMERA_PERMISSION_REQUEST_CODE);
        }
    }

    public void requestPermissionForShortCut(){
        if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.INSTALL_SHORTCUT)){
            Toast.makeText(activity, "Create ShortCut permission required. Please allow in App Settings for additional functionality.", Toast.LENGTH_LONG).show();
        } else {
            ActivityCompat.requestPermissions(activity,new String[]{Manifest.permission.INSTALL_SHORTCUT},SHORT_CUT_PERMISSION_REQUEST_CODE);
        }
    }
}

活动内部使用:

MarshMallowPermission marshMallowPermission = new MarshMallowPermission(MyActivity.this);

marshMallowPermission.checkPermissionForCall();

marshMallowPermission.requestPermissionForCall();

如果您有任何疑问,请在下方评论。

【讨论】:

  • 谢谢,我知道原因了,但是想知道native方法(比如java.io.UnixFileSystem.createFileExclusively0)是怎么判断runtime Permission没有被授予的?
  • 在 android 中,每个应用程序都作为一个单独的进程运行,并带有一个虚拟机和一个分配给它的专用 linux 用户 ID 和组 ID。在沙箱中运行。那里的 Linux 通过将应用程序彼此隔离开来,并将应用程序作为不同的实体与系统隔离开来。在程序运行期间,可能会在多个位置强制执行特定权限,因此任何试图访问系统/系统其他组件(该组件已为其设置了保护级别权限)的任何敏感数据的进程都应该设置其许可。
  • 在您的情况下,尝试访问的进程没有获得所需的权限,因此会引发运行时异常。
  • 使用“adb shell cat /proc/[pid]/status”,在Android M之前,我可以看到“Groups:”作为每个权限,但现在它不起作用。为什么?
猜你喜欢
  • 2016-07-16
  • 2017-07-27
  • 1970-01-01
  • 1970-01-01
  • 2017-09-24
  • 1970-01-01
  • 2012-05-09
  • 1970-01-01
  • 2016-07-22
相关资源
最近更新 更多