在Android Marshmallow 6.0中,什么时候需要在运行时请求权限?

13
我正在测试我的应用程序,运行在Marshmallow 6.0上,但是它由于缺少android.permission.READ_EXTERNAL_STORAGE权限而被强制关闭。即使该权限已在清单文件中定义。我在某个地方读到,如果我在运行时请求权限,则不会强制关闭您的应用程序。我也阅读过这篇安卓文档,其中提供了请求运行时权限的方法。

所以,我知道我们可以按照安卓文档中所述的方式请求权限,如下:

// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
                Manifest.permission.READ_CONTACTS)
        != PackageManager.PERMISSION_GRANTED) {

    // Should we show an explanation?
    if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
            Manifest.permission.READ_CONTACTS)) {

        // Show an expanation to the user *asynchronously* -- don't block
        // this thread waiting for the user's response! After the user
        // sees the explanation, try again to request the permission.

    } else {

        // No explanation needed, we can request the permission.

        ActivityCompat.requestPermissions(thisActivity,
                new String[]{Manifest.permission.READ_CONTACTS},
                MY_PERMISSIONS_REQUEST_READ_CONTACTS);

        // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
        // app-defined int constant. The callback method gets the
        // result of the request.
    }
}

上述代码有一个回调方法 onRequestPermissionsResult,它获取结果。

@Override
public void onRequestPermissionsResult(int requestCode,
        String permissions[], int[] grantResults) {
    switch (requestCode) {

     }
}

我的问题是在哪里向用户请求权限?我们应该在应用程序开始时请求权限,还是在需要权限时才这样做?


请看这个视频:https://youtu.be/iZqDdvhTZj0 - 里面解释了一些最佳实践。 - Thomas R.
在需要权限时执行操作。同时,在 M 版本中,要在清单文件中验证 l-o-c 权限:<uses-permission-sdk-23 android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> - Pararth
因此,在需要时请求权限是最佳实践。 - Pankaj
尝试这个,它可能有效:https://dev59.com/J1wX5IYBdhLWcg3w-Thv#41221852 - Bipin Bharti
请参见此链接:https://dev59.com/B1wX5IYBdhLWcg3wjwJZ#41978011 - Zar E Ahmer
这回答您的问题吗?Android marshmallow 请求权限? - Josh Correia
11个回答

7

这对我很有用!!!在你的应用程序启动页中,按照以下步骤操作:

1)声明一个请求码的整型变量,

private static final int REQUEST_CODE_PERMISSION = 2;

2)声明一个包含所需权限数量的字符串数组,

 String[] mPermission = {Manifest.permission.READ_CONTACTS, Manifest.permission.READ_SMS,
 Manifest.permission.ACCESS_FINE_LOCATION,
 Manifest.permission.WRITE_EXTERNAL_STORAGE};

3)接下来,在onCreate方法中检查运行时权限的条件。

try {
            if (ActivityCompat.checkSelfPermission(this, mPermission[0])
                    != MockPackageManager.PERMISSION_GRANTED ||
                    ActivityCompat.checkSelfPermission(this, mPermission[1])
                            != MockPackageManager.PERMISSION_GRANTED ||
                    ActivityCompat.checkSelfPermission(this, mPermission[2])
                            != MockPackageManager.PERMISSION_GRANTED ||
                    ActivityCompat.checkSelfPermission(this, mPermission[3])
                            != MockPackageManager.PERMISSION_GRANTED) {

                ActivityCompat.requestPermissions(this,
                        mPermission, REQUEST_CODE_PERMISSION);

              // If any permission aboe not allowed by user, this condition will execute every tim, else your else part will work
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

4) 现在声明onRequestPermissionsResult方法,以检查请求代码,

@Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        Log.e("Req Code", "" + requestCode);
        if (requestCode == REQUEST_CODE_PERMISSION) {
            if (grantResults.length == 4 &&
                    grantResults[0] == MockPackageManager.PERMISSION_GRANTED &&
                    grantResults[1] == MockPackageManager.PERMISSION_GRANTED &&
                    grantResults[2] == MockPackageManager.PERMISSION_GRANTED &&
                    grantResults[3] == MockPackageManager.PERMISSION_GRANTED) {

               // Success Stuff here

            }
        }

    }

1
你的代码中有两个地方让我执行操作,但是我不确定哪一个是正确的。应该只有一个地方来执行我的操作,而且onRequestPermissionsResult方法应该如何调用? - Pankaj
抱歉,只需在onRequestPermissionResult中编写代码,然后告诉我你的结果。 - Nanda Gopal

4

按照以下步骤进行操作

private static final int  REQUEST_ACCESS_FINE_LOCATION = 111;

在你的onCreate方法中

boolean hasPermissionLocation = (ContextCompat.checkSelfPermission(getApplicationContext(),
            Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED);
    if (!hasPermissionLocation) {
        ActivityCompat.requestPermissions(ThisActivity.this,
                new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                REQUEST_ACCESS_FINE_LOCATION);
    }

然后检查结果

   @Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode)
    {

        case REQUEST_ACCESS_FINE_LOCATION: {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
            {
                Toast.makeText(ThisActivity.this, "Permission granted.", Toast.LENGTH_SHORT).show();

                //reload my activity with permission granted
                finish();
                startActivity(getIntent());

            } else
            {
                Toast.makeText(ThisActivity.this, "The app was not allowed to get your location. Hence, it cannot function properly. Please consider granting it this permission", Toast.LENGTH_LONG).show();
            }
        }

    }

}

3
一般来说,只有在需要时才请求所需权限。这样可以告知用户为什么需要该权限,并更轻松地处理权限拒绝的情况。想象一下,在您的应用程序运行时用户撤销了权限的情况:如果您在启动时请求它并且后续没有再次检查,那么可能会导致意外行为或异常。

那么你的意思是说我们只需要在需要时请求权限,而不是在启动时请求权限。 - Pankaj
是的。你不知道用户在应用运行期间是否撤销了权限。 - Jörn Buitink

3
在我看来,你的问题没有一个正确的答案。我强烈建议您查看这个官方权限模式页面
Google建议的几件事情:
“您的权限策略取决于您请求的权限类型的清晰度和重要性。这些模式提供了介绍权限给用户的不同方法。”
“关键权限应该在前面请求。次要权限可以在上下文中请求。”
“较不清晰的权限应该提供有关权限涉及的教育,无论是在前面还是在上下文中完成。” 这个插图可能会让你更好地理解。
也许这里最关键的事情是,无论您是在上下文中还是在前面请求权限,您都应该时刻牢记,这些权限可以随时被用户撤销(例如,您的应用程序仍在运行,在后台)。

您应该确保您的应用程序不会因为在应用程序开头请求权限并假设用户没有更改有关该权限的偏好而崩溃。


这也是我的观点,对于这个问题没有正确的答案,UX团队应该根据产品来决定。 - xanexpt

1
我使用GitHub库来请求运行时权限。
Build.gradle文件中添加库。
dependencies {
     compile 'gun0912.ted:tedpermission:1.0.3'
}

创建Activity并添加PermissionListener
public class MainActivity extends AppCompatActivity{

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);



    PermissionListener permissionlistener = new PermissionListener() {
        @Override
        public void onPermissionGranted() {
            Toast.makeText(RationaleDenyActivity.this, "Permission Granted", Toast.LENGTH_SHORT).show();
            //Camera Intent and access Location logic here
        }

        @Override
        public void onPermissionDenied(ArrayList<String> deniedPermissions) {
            Toast.makeText(RationaleDenyActivity.this, "Permission Denied\n" + deniedPermissions.toString(), Toast.LENGTH_SHORT).show();
        }
    };


    new TedPermission(this)
            .setPermissionListener(permissionlistener)
            .setRationaleTitle(R.string.rationale_title)
            .setRationaleMessage(R.string.rationale_message) // "we need permission for access camera and find your location"
            .setDeniedTitle("Permission denied")
            .setDeniedMessage("If you reject permission,you can not use this service\n\nPlease turn on permissions at [Setting] > [Permission]")
            .setGotoSettingButtonText("Settings")
            .setPermissions(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE)
            .check();
   }
}

string.xml

<resources>

    <string name="rationale_title">Permission required</string>
    <string name="rationale_message">we need permission for read <b>camera</b> and find your <b>location</b></string>

</resources>

1
    Android Easy Runtime Permissions with Dexter:
    1. Dexter Permissions Library

    To get started with Dexter, add the dependency in your build.gradle

    dependencies {
        // Dexter runtime permissions
        implementation 'com.karumi:dexter:4.2.0'
    }

    1.1 Requesting Single Permission
    To request a single permission, you can use withPermission() method by passing the required permission. You also need a PermissionListener callback to receive the state of the permission.

    > onPermissionGranted() will be called once the permission is granted.

    > onPermissionDenied() will be called when the permission is denied. Here you can check whether the permission is permanently denied by using response.isPermanentlyDenied() condition.

    The below code requests CAMERA permission.

Dexter.withActivity(this)
                .withPermission(Manifest.permission.CAMERA)
                .withListener(new PermissionListener() {
                    @Override
                    public void onPermissionGranted(PermissionGrantedResponse response) {
                        // permission is granted, open the camera
                    }

                    @Override
                    public void onPermissionDenied(PermissionDeniedResponse response) {
                        // check for permanent denial of permission
                        if (response.isPermanentlyDenied()) {
                            // navigate user to app settings
                        }
                    }

                    @Override
                    public void onPermissionRationaleShouldBeShown(PermissionRequest permission, PermissionToken token) {
                        token.continuePermissionRequest();
                    }
                }).check();

1.2 Requesting Multiple Permissions
To request multiple permissions at the same time, you can use withPermissions() method. Below code requests STORAGE and LOCATION permissions.

Dexter.withActivity(this)
                .withPermissions(
                        Manifest.permission.READ_EXTERNAL_STORAGE,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE,
                        Manifest.permission.ACCESS_FINE_LOCATION)
                .withListener(new MultiplePermissionsListener() {
                    @Override
                    public void onPermissionsChecked(MultiplePermissionsReport report) {
                        // check if all permissions are granted
                        if (report.areAllPermissionsGranted()) {
                            // do you work now
                        }

                        // check for permanent denial of any permission
                        if (report.isAnyPermissionPermanentlyDenied()) {
                            // permission is denied permenantly, navigate user to app settings
                        }
                    }

                    @Override
                    public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) {
                        token.continuePermissionRequest();
                    }
                })
                .onSameThread()
                .check();

0

这里可以找到一个很好的解释和操作指南:

https://inthecheesefactory.com/blog/things-you-need-to-know-about-android-m-permission-developer-edition/en

我编写了这段代码,用于在BaseActivity.class中检查和请求运行时权限,该类是我实现的每个其他Activity.class的父类:
public static final int PERMISSION_REQUEST = 42;
public static final int MULTIPLE_PERMISSION_REQUEST = 43;

//Marshmallow Permission Model
public boolean requestPermission(String permission /* Manifest.permission...*/) {
    if (ContextCompat.checkSelfPermission(this,
            permission) != PackageManager.PERMISSION_GRANTED) {
        if (Utils.hasMarshmallow())
            ActivityCompat.requestPermissions(this,
                    new String[]{permission}, PERMISSION_REQUEST
            );
        else {
            requestPermissions(new String[]{permission},
                    PERMISSION_REQUEST);
        }
        return false;
    } else {
        return true;
    }
}

public boolean requestPermission(String... permissions) {
    final List<String> permissionsList = new ArrayList<String>();

    for (String perm : permissions) {
        addPermission(permissionsList, perm);
    }

    if (permissionsList.size() > 0) {
        if (Utils.hasMarshmallow())
            requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
                    MULTIPLE_PERMISSION_REQUEST);
        else
            ActivityCompat.requestPermissions(this, permissionsList.toArray(new String[permissionsList.size()]),
                    MULTIPLE_PERMISSION_REQUEST);
        return false;
    } else
        return true;
}


private boolean addPermission(List<String> permissionsList, String permission) {
    if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
        permissionsList.add(permission);
        // Check for Rationale Option
        if (Utils.hasMarshmallow())
            if (!shouldShowRequestPermissionRationale(permission))
                return false;
    }
    return true;
}

@Override
public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) {
    switch (requestCode) {
        case PERMISSION_REQUEST:
        case MULTIPLE_PERMISSION_REQUEST: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // permission was granted, yay! Do the
                // contacts-related task you need to do.

            } else {

                // permission denied, boo! Disable the
                // functionality that depends on this permission.
            }
            return;
        }

        // other 'case' lines to check for other
        // permissions this app might request
    }
}

简单的调用示例:

activity.requestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE);

返回结果将告诉您权限是否已经被授予。

0

调用此函数,我们可以允许用户打开对话框以请求允许相机和录音权限。

    if ( ActivityCompat.shouldShowRequestPermissionRationale (this, Manifest.permission.CAMERA) ||
            ActivityCompat.shouldShowRequestPermissionRationale (this,
                    Manifest.permission.RECORD_AUDIO) ) {
        Toast.makeText (this,
                R.string.permissions_needed,
                Toast.LENGTH_LONG).show ();
    } else {
        ActivityCompat.requestPermissions (
                this,
                new String[]{Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO},
                CAMERA_MIC_PERMISSION_REQUEST_CODE);
    }

0

0

我喜欢短小的代码。我使用 RxPermission 来处理权限。

RxPermission 是最好的库之一,可以让权限代码只需要一行,让人意想不到。

RxPermissions rxPermissions = new RxPermissions(this);
rxPermissions
.request(Manifest.permission.CAMERA,
         Manifest.permission.READ_PHONE_STATE) // ask single or multiple permission once
.subscribe(granted -> {
    if (granted) {
       // All requested permissions are granted
    } else {
       // At least one permission is denied
    }
});

在你的 build.gradle 中添加:
allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}

dependencies {
    implementation 'com.github.tbruyelle:rxpermissions:0.10.1'
    implementation 'com.jakewharton.rxbinding2:rxbinding:2.1.1'
}

这不是很容易吗?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接