以编程方式向用户请求权限?

Requesting permissions from user programmatically?

我想添加在用户第一次打开应用后就给用户一个权限列表来批准的功能。

我阅读了 this 篇关于如何执行此操作的文章。

但我对此仍有一些疑问,要使我的应用程序的此功能真正动态化:

运行 时间权限从 Android 6.0(API 级别 23)添加到 Android 中,在此之前权限只能在清单中定义。但是如果是 Android 6 或更高,您需要在执行任务之前从用户那里获得 运行 时间许可(危险)。

来自问题中包含的文档

If your app needs a dangerous permission, you must check whether you have that permission every time you perform an operation that requires that permission.

因此,如果您正在执行需要危险权限的任务,那么必须要求用户接受它,否则它会抛出 运行 时间异常。

您可以阅读 this 获取权限的最佳方式

当您想要执行与该权限相关的某些操作时,您需要在每次授予或未授予您的应用天气权限时进行检查。

因为用户可以随时从设置中禁用该权限。

危险权限和权限组:

日历

READ_CALENDAR
WRITE_CALENDAR

CALL_LOG

READ_CALL_LOG 
WRITE_CALL_LOG 
PROCESS_OUTGOING_CALLS

相机

CAMERA

联系人

READ_CONTACTS
WRITE_CONTACTS
GET_ACCOUNTS

位置

ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION

微型PHONE

RECORD_AUDIO

PHONE

READ_PHONE_STATE
READ_PHONE_NUMBERS
CALL_PHONE
ANSWER_PHONE_CALLS
ADD_VOICEMAIL
USE_SIP

传感器

BODY_SENSORS

短信

SEND_SMS
RECEIVE_SMS
READ_SMS
RECEIVE_WAP_PUSH
RECEIVE_MMS

存储空间

READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE

来源Dangerous permissions

普通权限:

ACCESS_LOCATION_EXTRA_COMMANDS
ACCESS_NETWORK_STATE
ACCESS_NOTIFICATION_POLICY
ACCESS_WIFI_STATE
BLUETOOTH
BLUETOOTH_ADMIN
BROADCAST_STICKY
CHANGE_NETWORK_STATE
CHANGE_WIFI_MULTICAST_STATE
CHANGE_WIFI_STATE
DISABLE_KEYGUARD
EXPAND_STATUS_BAR
FOREGROUND_SERVICE
GET_PACKAGE_SIZE
INSTALL_SHORTCUT
INTERNET
KILL_BACKGROUND_PROCESSES
MANAGE_OWN_CALLS
MODIFY_AUDIO_SETTINGS
NFC
READ_SYNC_SETTINGS
READ_SYNC_STATS
RECEIVE_BOOT_COMPLETED
REORDER_TASKS
REQUEST_COMPANION_RUN_IN_BACKGROUND
REQUEST_COMPANION_USE_DATA_IN_BACKGROUND
REQUEST_DELETE_PACKAGES
REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
SET_ALARM
SET_WALLPAPER
SET_WALLPAPER_HINTS
TRANSMIT_IR
USE_FINGERPRINT
VIBRATE
WAKE_LOCK
WRITE_SYNC_SETTINGS

来源Normal permissions

以编程方式获取所需权限的列表:

public void readPermission()
{
    try {
        PackageInfo info = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_PERMISSIONS);
        if (info.requestedPermissions != null) {
            for (String p : info.requestedPermissions) {
                Log.d(TAG, "Permission : " + p);
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

清单中定义的权限 <使用权限 android:name="..."/> 将自动适用于 android 级别低于 23 的 API 设备。对于高于 android (6.0) 的设备,您必须在运行时检查权限。

https://developer.android.com/guide/topics/security/permissions.html 这个 link 有一个危险权限列表

据我所知,无法以编程方式从清单中读取所有权限。但是,由于您在发布 APK 之前已经将它们列在清单中,因此您已经知道需要请求哪些权限。不是吗?

假设您的清单中有 READ_PHONE_STATE 和 WRITE_EXTERNAL_STORAGE,您可以在 MainActivity.java:

的权限检查中添加它
ArrayList<String> arrPerm = new ArrayList<>();
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
    arrPerm.add(Manifest.permission.READ_PHONE_STATE);
}
if(ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
    arrPerm.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
if(!arrPerm.isEmpty()) {
    String[] permissions = new String[arrPerm.size()];
    permissions = arrPerm.toArray(permissions);
    ActivityCompat.requestPermissions(this, permissions, MY_PERMISSIONS_REQUEST);
}

这将依次触发 WRITE_EXTERNAL_STORAGE 和 READ_PHONE_STATE 的权限请求。要检查授予了哪些权限,请执行以下操作:

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

    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0) {
                for(int i = 0; i < grantResults.length; i++) {
                    String permission = permissions[i];
                    if(Manifest.permission.READ_PHONE_STATE.equals(permission)) {
                        if(grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                            // you now have permission
                        }
                    }
                    if(Manifest.permission.WRITE_EXTERNAL_STORAGE.equals(permission)) {
                        if(grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                            // you now have permission
                        }
                    }
                }
            } else {
                // permission denied, boo! Disable the
                // functionality that depends on this permission.
            }
            break;
        }
    }

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