Android 6.0 多个权限

195

我知道Android 6.0有新的权限,我知道我可以像这样调用它们

if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) !=
    PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this,
        new String[] { 
            Manifest.permission.WRITE_EXTERNAL_STORAGE
        }, PERMISSION_WRITE_STORAGE);
}

今天我看到了一个谷歌应用程序,它需要三个权限:通讯录、短信和相机。它创建了一个1-3的页面,并同时调用它们来激活。

有人可以告诉我如何调用4个权限,例如短信、相机、通讯录和存储,以便同时激活它们吗?

例如(忘记了谷歌应用程序的名称 :( )
该应用需要短信、联系人和相机。

该应用让我(并创建了一个对话框页面1-3)激活短信,激活联系人,然后是相机。 因此,这个谷歌应用程序正在同时调用所有三个所需的权限,我的问题是如何做到这一点?


你能更具体地说明或分享一下你所见到的并想要实现的内容吗? - kandroidj
1
在Android 6.0中同时调用4个权限,因为“此”应用程序需要4个权限。 谷歌应用程序将它们全部智能地一起调用,并且正如我所提到的,使页面1-3激活所有3个。 那么我怎样才能做到同样的事情呢?调用4个权限并同时激活它们。 - Frank
只需在String[]数组中添加您希望的所有权限即可。 - natario
23个回答

387

只需在ActivityCompat.requestPermissions(...)调用中包含所有4个权限,Android会自动将它们像你提到的那样一起分组。

我有一个帮助方法来检查多个权限并查看是否有任何未被授予的权限。

public static boolean hasPermissions(Context context, String... permissions) {
    if (context != null && permissions != null) {
        for (String permission : permissions) {
            if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
    }
    return true;
}

还可以使用Kotlin:

fun hasPermissions(context: Context, vararg permissions: String): Boolean = permissions.all {
    ActivityCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
}

然后只需发送所有权限,Android 将仅请求它需要的那些权限。

// The request code used in ActivityCompat.requestPermissions()
// and returned in the Activity's onRequestPermissionsResult()
int PERMISSION_ALL = 1; 
String[] PERMISSIONS = {
  android.Manifest.permission.READ_CONTACTS, 
  android.Manifest.permission.WRITE_CONTACTS, 
  android.Manifest.permission.WRITE_EXTERNAL_STORAGE, 
  android.Manifest.permission.READ_SMS, 
  android.Manifest.permission.CAMERA
};

if (!hasPermissions(this, PERMISSIONS)) {
    ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSION_ALL);
}

2
嗨,詹姆斯。是的,你的解决方案非常有效!再次感谢!只是将DeviceUtils.Hasmarshmallow()更改为(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M),我认为这样更好。 - Frank
2
@maveň 我也遇到了同样的问题。如果我不授权其中的1个,它会再次要求所有权限,包括我已经授权的其他权限。 - chengsam
13
我很喜欢这篇文章的写作风格。但是你能否展示一下在onRequestPermissionsResult()方法中如何处理多个结果? - Keshav
很棒的解决方案!不过,我想知道是否真的需要API版本检查?我认为如果是在Marshmallow之前的操作系统上安装,则会授予权限,然后就没有理由检查版本了。 - Oleksandr Berdnikov
1
(!hasPermissions(this, PERMISSIONS)) 类型不匹配。 - Mike Debela
显示剩余14条评论

110

以下是多个权限请求的详细示例:

应用程序在启动时需要2个权限。SEND_SMS和ACCESS_FINE_LOCATION(这两者都在manifest.xml中提到)。

我正在使用为处理Android Marshmallow之前版本而准备的Support Library v4,因此无需检查构建版本。

一旦应用程序启动,它就会一起请求多个权限。如果两个权限都被授予,则正常流程会继续。

输入图像描述

输入图像描述

public static final int REQUEST_ID_MULTIPLE_PERMISSIONS = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    if(checkAndRequestPermissions()) {
        // carry on the normal flow, as the case of  permissions  granted.
    }
}

private  boolean checkAndRequestPermissions() {
    int permissionSendMessage = ContextCompat.checkSelfPermission(this,
            Manifest.permission.SEND_SMS);
    int locationPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION);
    List<String> listPermissionsNeeded = new ArrayList<>();
    if (locationPermission != PackageManager.PERMISSION_GRANTED) {
        listPermissionsNeeded.add(Manifest.permission.ACCESS_FINE_LOCATION);
    }
    if (permissionSendMessage != PackageManager.PERMISSION_GRANTED) {
        listPermissionsNeeded.add(Manifest.permission.SEND_SMS);
    }
    if (!listPermissionsNeeded.isEmpty()) {
        ActivityCompat.requestPermissions(this, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]),REQUEST_ID_MULTIPLE_PERMISSIONS);
        return false;
    }
    return true;
}

ContextCompat.checkSelfPermission(),ActivityCompat.requestPermissions()和ActivityCompat.shouldShowRequestPermissionRationale()是支持库的一部分。

如果一个或多个权限没有被授予,则ActivityCompat.requestPermissions()将请求授权,并将控制传递给onRequestPermissionsResult()回调方法。

您应该在onRequestPermissionsResult()回调方法中检查shouldShowRequestPermissionRationale()标志的值。

只有两种情况:

情况1:-任何时候用户点击拒绝权限(包括第一次),它都会返回true。因此,当用户拒绝时,我们可以显示更多解释并继续再次请求。

情况2:-仅当用户选择“不再询问”时,它才会返回false。在这种情况下,我们可以继续具有有限功能,并指导用户从设置中激活权限以获取更多功能,或者如果权限对于应用程序来说是微不足道的,我们可以完成设置。

情况-1

enter image description here

情况-2

enter image description here

    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           String permissions[], int[] grantResults) {
        Log.d(TAG, "Permission callback called-------");
        switch (requestCode) {
            case REQUEST_ID_MULTIPLE_PERMISSIONS: {

                Map<String, Integer> perms = new HashMap<>();
                // Initialize the map with both permissions
                perms.put(Manifest.permission.SEND_SMS, PackageManager.PERMISSION_GRANTED);
                perms.put(Manifest.permission.ACCESS_FINE_LOCATION, 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 both permissions
                    if (perms.get(Manifest.permission.SEND_SMS) == PackageManager.PERMISSION_GRANTED
                            && perms.get(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                        Log.d(TAG, "sms & location services permission granted");
                        // process the normal flow
                        //else any one or both the permissions are not granted
                    } else {
                            Log.d(TAG, "Some permissions are not granted ask again ");
                            //permission is denied (this is the first time, when "never ask again" is not checked) so ask again explaining the usage of permission
//                        // shouldShowRequestPermissionRationale will return true
                            //show the dialog or snackbar saying its necessary and try again otherwise proceed with setup.
                            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.SEND_SMS) || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) {
                                showDialogOK("SMS and Location Services Permission required for this app",
                                        new DialogInterface.OnClickListener() {
                                            @Override
                                            public void onClick(DialogInterface dialog, int which) {
                                                switch (which) {
                                                    case DialogInterface.BUTTON_POSITIVE:
                                                        checkAndRequestPermissions();
                                                        break;
                                                    case DialogInterface.BUTTON_NEGATIVE:
                                                        // proceed with logic by disabling the related features or quit the app.
                                                        break;
                                                }
                                            }
                                        });
                            }
                            //permission is denied (and never ask again is  checked)
                            //shouldShowRequestPermissionRationale will return false
                            else {
                                Toast.makeText(this, "Go to settings and enable permissions", Toast.LENGTH_LONG)
                                        .show();
    //                            //proceed with logic by disabling the related features or quit the app.
                            }
                    }
                }
            }
        }

    }

    private void showDialogOK(String message, DialogInterface.OnClickListener okListener) {
        new AlertDialog.Builder(this)
                .setMessage(message)
                .setPositiveButton("OK", okListener)
                .setNegativeButton("Cancel", okListener)
                .create()
                .show();
    }

1
但它会多次显示所有权限对话框。 - Harsha
你说:“在onRequestPermissionsResult()回调方法中,应该检查shouldShowRequestPermissionRationale()标志的值。” 但是https://developer.android.com/training/permissions/requesting.html建议在请求权限之前调用shouldShowRequestPermissionRationale()。我很困惑。你的代码看起来更合理,但谷歌总是让人不知所措... - Yar
谢谢Nick,如何实现顺序权限弹出窗口?请指导我解决这个问题。 - MohanRaj S
各位好,为什么我一直在这个地方得到错误:无法解析符号:REQUEST_ID_MULTIPLE_PERMISSIONS? - Ahmed Samir
这个答案比谷歌文档更好,干得好! - Antonino
@AhmedSamir 你需要定义 REQUEST_ID_MULTIPLE_PERMISSIONS,例如:int REQUEST_ID_MULTIPLE_PERMISSIONS = 100; - Abilash

56

小代码:

 public static final int MULTIPLE_PERMISSIONS = 10; // code you want.

 String[] permissions= new String[]{
        Manifest.permission.WRITE_EXTERNAL_STORAGE,
        Manifest.permission.CAMERA,
        Manifest.permission.ACCESS_COARSE_LOCATION,
        Manifest.permission.ACCESS_FINE_LOCATION};


if (checkPermissions())
         //  permissions  granted.    
}

private  boolean checkPermissions() {
        int result;
        List<String> listPermissionsNeeded = new ArrayList<>();
        for (String p:permissions) {
            result = ContextCompat.checkSelfPermission(getActivity(),p);
            if (result != PackageManager.PERMISSION_GRANTED) {
                listPermissionsNeeded.add(p);
            }
        }
        if (!listPermissionsNeeded.isEmpty()) {
            ActivityCompat.requestPermissions(this, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]),MULTIPLE_PERMISSIONS );
            return false;
        }
        return true;
    }


   @Override
    public void onRequestPermissionsResult(int requestCode, String permissionsList[], int[] grantResults) {
        switch (requestCode) {
            case MULTIPLE_PERMISSIONS:{
                if (grantResults.length > 0) {
                String permissionsDenied = "";
                for (String per : permissionsList) {
                    if(grantResults[0] == PackageManager.PERMISSION_DENIED){
                        permissionsDenied += "\n" + per;

                    } 

                }
                // Show permissionsDenied 
                updateViews();
            }
                return;
            }
        }
     }

Android API 23中普通权限和危险权限列表


2
我知道这有点晚了,但是对于任何来到这里的人,始终检查索引0处的grantResults[0]是否可以,即使是在permissionsList中的其他项上?permissionsListgrantResults不应该被视为并排的数组吗? - superjos
什么是更新视图?在这里。 - DikShU

11
在一个片段中
public class Homefragment extends Fragment {
    View hfrag;
   Context context;
 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

//first we must check the permissions are already granted

        hfrag = inflater.inflate(R.layout.home, container, false);
        context = getActivity();
checkAndRequestPermissions();

}




}


private boolean checkAndRequestPermissions() {
        int permissionSendMessage = ContextCompat.checkSelfPermission(context,
                Manifest.permission.READ_SMS);
        int contactpermission = ContextCompat.checkSelfPermission(context, Manifest.permission.GET_ACCOUNTS);

        int writepermission = ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE);

        int callpermission = ContextCompat.checkSelfPermission(context, Manifest.permission.CALL_PHONE);

        int receivepermission = ContextCompat.checkSelfPermission(context, Manifest.permission.RECEIVE_SMS);
        int locationpermission = ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION);

        List<String> listPermissionsNeeded = new ArrayList<>();

        if (locationpermission != PackageManager.PERMISSION_GRANTED) {
            listPermissionsNeeded.add(Manifest.permission.ACCESS_FINE_LOCATION);
        }

        if (contactpermission != PackageManager.PERMISSION_GRANTED) {
            listPermissionsNeeded.add(Manifest.permission.GET_ACCOUNTS);
        }
        if (writepermission != PackageManager.PERMISSION_GRANTED) {
            listPermissionsNeeded.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
        }
        if (permissionSendMessage != PackageManager.PERMISSION_GRANTED) {
            listPermissionsNeeded.add(Manifest.permission.READ_SMS);
        }
        if (receivepermission != PackageManager.PERMISSION_GRANTED) {
            listPermissionsNeeded.add(Manifest.permission.RECEIVE_SMS);
        }

        if (callpermission != PackageManager.PERMISSION_GRANTED) {
            listPermissionsNeeded.add(Manifest.permission.CALL_PHONE);
        }
        if (!listPermissionsNeeded.isEmpty()) {
            requestPermissions(listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]), REQUEST_ID_MULTIPLE_PERMISSIONS);
            return false;
        }
        return true;
    }



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


    if (requestCode == REQUEST_ID_MULTIPLE_PERMISSIONS) {


        if (grantResults.length > 0) {
            for (int i = 0; i < permissions.length; i++) {


                if (permissions[i].equals(Manifest.permission.GET_ACCOUNTS)) {
                    if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                        Log.e("msg", "accounts granted");
                        
                    }
                } else if (permissions[i].equals(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                    if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                        Log.e("msg", "storage granted");
                        
                    }
                } else if (permissions[i].equals(Manifest.permission.CALL_PHONE)) {
                    if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                        Log.e("msg", "call granted");
                        
                    }
                } else if (permissions[i].equals(Manifest.permission.RECEIVE_SMS)) {
                    if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                        Log.e("msg", "sms granted");
                        
                    }
                } else if (permissions[i].equals(Manifest.permission.ACCESS_FINE_LOCATION)) {
                    if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                        Log.e("msg", "location granted");
                        
                    }
                }


            }

        }


    }
}


}

7

很简单,按照以下步骤操作

private static final int REQUEST_READ_PHONE_STATE = 110 , REQUEST_ACCESS_FINE_LOCATION = 111, REQUEST_WRITE_STORAGE = 112;

在你的 onCreate 方法中

 //request permission
    boolean hasPermissionPhoneState = (ContextCompat.checkSelfPermission(getApplicationContext(),
            Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED);
    if (!hasPermissionPhoneState) {
        ActivityCompat.requestPermissions(LoginActivity.this,
                new String[]{Manifest.permission.READ_PHONE_STATE},
                REQUEST_READ_PHONE_STATE);
    }

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

    boolean hasPermissionWrite = (ContextCompat.checkSelfPermission(getApplicationContext(),
            Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED);
    if (!hasPermissionWrite) {
        ActivityCompat.requestPermissions(LoginActivity.this,
                new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                REQUEST_WRITE_STORAGE);
    }

然后检查结果。
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode)
    {
        case REQUEST_READ_PHONE_STATE: {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
            {
                Toast.makeText(LoginActivity.this, "Permission granted.", Toast.LENGTH_SHORT).show();
                //reload my activity with permission granted or use the features what required the permission
                finish();
                startActivity(getIntent());
            } else
            {
                Toast.makeText(LoginActivity.this, "The app was not allowed to get your phone state. Hence, it cannot function properly. Please consider granting it this permission", Toast.LENGTH_LONG).show();
            }
        }
        case REQUEST_ACCESS_FINE_LOCATION: {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
            {
                Toast.makeText(LoginActivity.this, "Permission granted.", Toast.LENGTH_SHORT).show();
                //reload my activity with permission granted or use the features what required the permission
                finish();
                startActivity(getIntent());
            } else
            {
                Toast.makeText(LoginActivity.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();
            }
        }

        case REQUEST_WRITE_STORAGE: {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
            {
                Toast.makeText(LoginActivity.this, "Permission granted.", Toast.LENGTH_SHORT).show();
                //reload my activity with permission granted or use the features what required the permission
                finish();
                startActivity(getIntent());
            } else
            {
                Toast.makeText(LoginActivity.this, "The app was not allowed to write to your storage. Hence, it cannot function properly. Please consider granting it this permission", Toast.LENGTH_LONG).show();
            }
        }
    }

}

这对我来说完美地运作了。只是一个问题,当这些警告对话框出现时,我们能否禁用警告对话框外的触摸事件。因为在我的情况下,我希望用户允许权限,然后才能访问应用程序。 - Yogesh Patel
1
@YogeshPatel 没问题,伙计。当这些警告对话框出现时,除了状态栏之外,外部触摸自动禁用。然后你只有两个选项 - 拒绝或允许。别忘了在你的主活动中添加所有权限。你可以隐藏状态栏,查看这个隐藏状态栏 - Tharindu Bandara

7

2022年全新易懂干净的请求多个权限方法

在你的活动类顶部编写以下内容:

private val multiplePermissionContract = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissionsStatusMap ->
    // permissionStatusMap is of type <String, Boolean>
    // if all permissions accepted
    if (!permissionsStatusMap.containsValue(false)) {

        // All persmissions are accepted, do here whatever you want 

    } else {
        Toast.makeText(this, "all permissions not accepted", Toast.LENGTH_SHORT).show()
    }
}

并且,您可以随时像下面这样启动权限请求对话框(目前,我认为您需要在单击xyzButton时请求权限)。

    xyzButton.setOnClickListener {
        multiplePermissionContract.launch(
            arrayOf(
                android.Manifest.permission.READ_CONTACTS, 
                android.Manifest.permission.WRITE_CONTACTS, 
                android.Manifest.permission.WRITE_EXTERNAL_STORAGE, 
                android.Manifest.permission.READ_SMS, 
                android.Manifest.permission.CAMERA
            )
        )
    }

注意:

  • 每次单击xyzButton时,都将调用registerForActivityResult()方法。如果之前未接受任何权限,则会再次请求该特定权限;否则,它将直接执行if条件块。

6

我的处理程序类用于请求多个权限。你可以在这里完整使用

public class RequestPermissionHandler {
    private Activity mActivity;
    private RequestPermissionListener mRequestPermissionListener;
    private int mRequestCode;

    public void requestPermission(Activity activity, @NonNull String[] permissions, int requestCode,
            RequestPermissionListener listener) {
        mActivity = activity;
        mRequestCode = requestCode;
        mRequestPermissionListener = listener;

        if (!needRequestRuntimePermissions()) {
            mRequestPermissionListener.onSuccess();
            return;
        }
        requestUnGrantedPermissions(permissions, requestCode);
    }

    private boolean needRequestRuntimePermissions() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
    }

    private void requestUnGrantedPermissions(String[] permissions, int requestCode) {
        String[] unGrantedPermissions = findUnGrantedPermissions(permissions);
        if (unGrantedPermissions.length == 0) {
            mRequestPermissionListener.onSuccess();
            return;
        }
        ActivityCompat.requestPermissions(mActivity, unGrantedPermissions, requestCode);
    }

    private boolean isPermissionGranted(String permission) {
        return ActivityCompat.checkSelfPermission(mActivity, permission)
                == PackageManager.PERMISSION_GRANTED;
    }

    private String[] findUnGrantedPermissions(String[] permissions) {
        List<String> unGrantedPermissionList = new ArrayList<>();
        for (String permission : permissions) {
            if (!isPermissionGranted(permission)) {
                unGrantedPermissionList.add(permission);
            }
        }
        return unGrantedPermissionList.toArray(new String[0]);
    }

    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
            @NonNull int[] grantResults) {
        if (requestCode == mRequestCode) {
            if (grantResults.length > 0) {
                for (int grantResult : grantResults) {
                    if (grantResult != PackageManager.PERMISSION_GRANTED) {
                        mRequestPermissionListener.onFailed();
                        return;
                    }
                }
                mRequestPermissionListener.onSuccess();
            } else {
                mRequestPermissionListener.onFailed();
            }
        }
    }

    public interface RequestPermissionListener {
        void onSuccess();

        void onFailed();
    }
}

enter image description here


请给出一个Java示例。 - RonTLV

6

请点击此处,了解多个权限的完整理解以及完整源代码下载。

   private boolean checkAndRequestPermissions() {
    int permissionReadPhoneState = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE);
    int permissionProcessOutGogingCalls = ContextCompat.checkSelfPermission(this, Manifest.permission.PROCESS_OUTGOING_CALLS);
    int permissionProcessReadContacts = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS);
    int permissionProcessReadCallLog = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CALL_LOG);

    int permissionWriteStorage = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
    int permissionReadStorage = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE);

    List<String> listPermissionsNeeded = new ArrayList<>();
    if (permissionReadPhoneState != PackageManager.PERMISSION_GRANTED) {
        listPermissionsNeeded.add(Manifest.permission.READ_PHONE_STATE);
    }
    if (permissionProcessOutGogingCalls != PackageManager.PERMISSION_GRANTED) {
        listPermissionsNeeded.add(Manifest.permission.PROCESS_OUTGOING_CALLS);
    }
    if (permissionProcessReadContacts != PackageManager.PERMISSION_GRANTED) {
        listPermissionsNeeded.add(Manifest.permission.READ_CONTACTS);
    }
    if (permissionProcessReadCallLog != PackageManager.PERMISSION_GRANTED) {
        listPermissionsNeeded.add(Manifest.permission.READ_CALL_LOG);
    }
    if (permissionWriteStorage != PackageManager.PERMISSION_GRANTED) {
        listPermissionsNeeded.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
    }
    if (permissionReadStorage != PackageManager.PERMISSION_GRANTED) {
        listPermissionsNeeded.add(Manifest.permission.READ_EXTERNAL_STORAGE);
    }
    if (!listPermissionsNeeded.isEmpty()) {
        ActivityCompat.requestPermissions(this, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]), REQUEST_ID_MULTIPLE_PERMISSIONS);
        return false;
    }
    return true;
}

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (grantResults.length == 0 || grantResults == null) {
        /*If result is null*/
    } else if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        /*If We accept permission*/
    } else if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
        /*If We Decline permission*/
    }
}

1
这对我非常有帮助。 - LizG

6

我的方法基于尼克的答案,希望更适用于多个(尽可能多,不仅限于两个)权限。它建议添加单一责任的PermissionsHelper类:

import android.app.Activity;
import android.app.AlertDialog;
import android.content.pm.PackageManager;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.util.Log;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class PermissionsHelper {

private static final int REQUEST_ID_MULTIPLE_PERMISSIONS = 100; // any code you want.

public void checkAndRequestPermissions(Activity activity, String... permissions) {
    List<String> listPermissionsNeeded = new ArrayList<>();
    for (String permission : permissions) {
        if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {
            listPermissionsNeeded.add(permission);
        }
    }
    if (!listPermissionsNeeded.isEmpty()) {
        ActivityCompat.requestPermissions(activity, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]), REQUEST_ID_MULTIPLE_PERMISSIONS);
    }
}

public void onRequestPermissionsResult(Activity activity, int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
        case REQUEST_ID_MULTIPLE_PERMISSIONS: {
            Map<String, Integer> perms = new HashMap<>();

            for (String permission : permissions) {
                perms.put(permission, PackageManager.PERMISSION_GRANTED);
            }

            if (grantResults.length > 0) {
                for (int i = 0; i < permissions.length; i++)
                    perms.put(permissions[i], grantResults[i]);

                boolean allPermissionsGranted = true;
                for (String permission1 : permissions) {
                    allPermissionsGranted = allPermissionsGranted && (perms.get(permission1) == PackageManager.PERMISSION_GRANTED);
                }

                if (allPermissionsGranted) {
                    Log.d(PermissionsHelper.class.getSimpleName(), "onRequestPermissionsResult: all permissions granted");
                } else {
                    for (String permission2 : perms.keySet())
                        if (perms.get(permission2) == PackageManager.PERMISSION_GRANTED)
                            perms.remove(permission2);

                    StringBuilder message = new StringBuilder("The app has not been granted permissions:\n\n");
                    for (String permission : perms.keySet()) {
                        message.append(permission);
                        message.append("\n");
                    }
                    message.append("\nHence, it cannot function properly." +
                            "\nPlease consider granting it this permission in phone Settings.");

                    AlertDialog.Builder builder = new AlertDialog.Builder(activity);
                    builder.setTitle(R.string.permission_required)
                            .setMessage(message)
                            .setPositiveButton(android.R.string.ok, (dialog, id) -> dialog.cancel());
                    AlertDialog alert = builder.create();
                    alert.show();
                }
            }
        }
    }
}

如果用户没有授予所需的权限之一或多个,则会向其显示详细的AlertDialog消息。

在Activity中使用示例:

private PermissionsHelper permissionsHelper;

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

    checkPermissions();

    //any other code
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    permissionsHelper.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
}

private void checkPermissions() {
    permissionsHelper = new PermissionsHelper();
    permissionsHelper.checkAndRequestPermissions(this,
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.ACCESS_COARSE_LOCATION);
}

希望这对大家有用。

漂亮而整洁的解决方案。Helper类有助于简化主要代码。 - Oke Uwechue
@Andrew Vovk,太好了。你如何处理替代用户响应,例如允许位置和拒绝存储?我在测试允许和拒绝时遇到了这个错误:“FATAL EXCEPTION:main Failure delivering result ResultInfo {who = @ android:requestPermissions:,request = 100,result = -1,data = Intent {act = android.content.pm.action.REQUEST_PERMISSIONS(有额外信息)}}” - shinsky Paul

5
以下方法论涉及以下内容:
  • 动态请求权限;
  • 如果用户拒绝了任何权限,显示AlertDialog;
  • 循环直到用户接受权限。
创建一个“静态”类以用于权限方法
public class PermissionsUtil {
    public static final int PERMISSION_ALL = 1;

    public static boolean doesAppNeedPermissions(){
        return android.os.Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1;
    }

    public static String[] getPermissions(Context context)
            throws PackageManager.NameNotFoundException {
        PackageInfo info = context.getPackageManager().getPackageInfo(
                context.getPackageName(), PackageManager.GET_PERMISSIONS);

        return info.requestedPermissions;
    }

    public static void askPermissions(Activity activity){
        if(doesAppNeedPermissions()) {
            try {
                String[] permissions = getPermissions(activity);

                if(!checkPermissions(activity, permissions)){
                    ActivityCompat.requestPermissions(activity, permissions,
                            PERMISSION_ALL);
                }
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static boolean checkPermissions(Context context, String... permissions){
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && context != null &&
                permissions != null) {
            for (String permission : permissions) {
                if (ContextCompat.checkSelfPermission(context, permission) !=
                        PackageManager.PERMISSION_GRANTED) {
                    return false;
                }
            }
        }
        return true;
    }
}

在MainActivity.java文件中:
    private void checkPermissions(){
        PermissionsUtil.askPermissions(this);
    }

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

                if (grantResults.length > 0) {

                    List<Integer> indexesOfPermissionsNeededToShow = new ArrayList<>();

                    for(int i = 0; i < permissions.length; ++i) {
                        if(ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[i])) {
                            indexesOfPermissionsNeededToShow.add(i);
                        }
                    }

                    int size = indexesOfPermissionsNeededToShow.size();
                    if(size != 0) {
                        int i = 0;
                        boolean isPermissionGranted = true;

                        while(i < size && isPermissionGranted) {
                            isPermissionGranted = grantResults[indexesOfPermissionsNeededToShow.get(i)]
                                    == PackageManager.PERMISSION_GRANTED;
                            i++;
                        }

                        if(!isPermissionGranted) {

                            showDialogNotCancelable("Permissions mandatory",
                                    "All the permissions are required for this app",
                                    new DialogInterface.OnClickListener() {
                                        @Override
                                        public void onClick(DialogInterface dialogInterface, int i) {
                                            checkPermissions();
                                        }
                                    });
                        }
                    }
                }
            }
        }
    }

    private void showDialogNotCancelable(String title, String message,
                                         DialogInterface.OnClickListener okListener) {
        new AlertDialog.Builder(this)
                .setTitle(title)
                .setMessage(message)
                .setPositiveButton("OK", okListener)
                .setCancelable(false)
                .create()
                .show();
    }

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