Android 6.0(Marshmallow) API Level: 23
Android 7.0(Nougat) API Level: 24
虽然Android一直处于持续更新中,但是Android 6.0版本中的一些更新有可能会影响到所有的应用,例如新的Runtime Permission.
自从Android应用程序在安装的时候会将所有的权限进行设置以来,Android的权限系统一直都是最大的一个安全问题。因为一旦程序安装完成,应用就能够访问所有已经被授予的权限而且不通过用户的再次确认。
在Android 6.0 Marshmallow中,整个权限系统被重新设计,所有的应用程序将不会在安装的时候授予任何权限,取而代之的是,应用程序在每次使用相应权限的时候需要询问用户进行授权。
注意:在这里,权限请求对话框并不会自动的显示,而是需要开发者进行人为的调用。在开发人员尝试调用一些需要用户尚未授予权限的函数的情况下,函数会突然抛出一个异常,这将导致应用程序崩溃。
除此之外,用户可以在任何时候通过程序设置收回权限。
因此,作为一个开发这,程序的逻辑已经开始改变,你不能只是调用一个函数来做这样的工作,但你必须检查每一个功能的权限,否则你的应用程序将只是简单地崩溃!因此,我门必须对Android6.0及更高版本的SDK做适配。
对于那些已经安装的程序,在操作系统升级到6.0及以上时,将会发生什么呢?
如果应用程序的targetSdkVersion被设置成小于23(即Android6.0),它会假设应用程序并没有针对6.0进行测试,因此,将会转向旧的处理方式:用户不得不接受每一个权限在安装的时候都被授予。因此,以前版本的应用程序依然能正常的工作。
但是,需要注意的是:随用Android6.0将会对用户进行警告,但是,用户依然能在任何时候收回任何应用程序使用的权限。
如果这种老版本的应用程序被收回了权限,那么所在的函数没有任何异常将被抛出。相反,它只是简单地什么都不做。对于返回值的函数,它将返回零或0取决于情况。因此,程序一半并不会直接崩溃。但是如果程序没有获取到相应的返回值,程序依然会崩溃。
警告:如果在Android Studio中做开发的话,targetSdkVersion将自动设置为最新版本,23或者更高。如果你还没有准备好让你的应用程序完全支持运行时的允许,我建议你设置targetSdkVersion 22以下。
自动授权:
这里有一些权限是自动在安装的时候被授予的,并且永远不会被收回,如下:
android.permission.ACCESS_LOCATION_EXTRA_COMMANDS
android.permission.ACCESS_NETWORK_STATE
android.permission.ACCESS_NOTIFICATION_POLICY
android.permission.ACCESS_WIFI_STATE
android.permission.ACCESS_WIMAX_STATE
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
android.permission.BROADCAST_STICKY
android.permission.CHANGE_NETWORK_STATE
android.permission.CHANGE_WIFI_MULTICAST_STATE
android.permission.CHANGE_WIFI_STATE
android.permission.CHANGE_WIMAX_STATE
android.permission.DISABLE_KEYGUARD
android.permission.EXPAND_STATUS_BAR
android.permission.FLASHLIGHT
android.permission.GET_ACCOUNTS
android.permission.GET_PACKAGE_SIZE
android.permission.INTERNET
android.permission.KILL_BACKGROUND_PROCESSES
android.permission.MODIFY_AUDIO_SETTINGS
android.permission.NFC
android.permission.READ_SYNC_SETTINGS
android.permission.READ_SYNC_STATS
android.permission.RECEIVE_BOOT_COMPLETED
android.permission.REORDER_TASKS
android.permission.REQUEST_INSTALL_PACKAGES
android.permission.SET_TIME_ZONE
android.permission.SET_WALLPAPER
android.permission.SET_WALLPAPER_HINTS
android.permission.SUBSCRIBED_FEEDS_READ
android.permission.TRANSMIT_IR
android.permission.USE_FINGERPRINT
android.permission.VIBRATE
android.permission.WAKE_LOCK
android.permission.WRITE_SYNC_SETTINGS
com.android.alarm.permission.SET_ALARM
com.android.launcher.permission.INSTALL_SHORTCUT
com.android.launcher.permission.UNINSTALL_SHORTCUT
使你的程序支持新的Runtime Permission
1.首先进行编译版本的设置:设置compileSdkVersion和targetSdkVersion为23
android {
compileSdkVersion 24
buildToolsVersion "23.0.3"
defaultConfig {
applicationId "XXXX"
minSdkVersion 17
targetSdkVersion 24
versionCode 1
versionName "1.0"
}
buildTypes {
......
}
}
2.在这个例子中将会使用到以下方法,对联系人应用程序进行添加新的人员。
private void insertDummyContact() {
// Two operations are needed to insert a new contact
ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>();
// 实现这些代码要求WRITE_CONTRACTS权限
// First, set up a new raw contact.
ContentProviderOperation.Builder op = ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null);
operations.add(op.build());
// Next, set the name for the contact.
op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,
"__DUMMY CONTACT from runtime permissions sample");
operations.add(op.build());
// Apply the operations
ContentResolver resolver = getContentResolver();
try {
resolver.applyBatch(ContactsContract.AUTHORITY, operations);
} catch (RemoteException e) {
Log.d(TAG, "Could not add a new contact: " + e.getMessage());
} catch (OperationApplicationException e) {
Log.d(TAG, "Could not add a new contact: " + e.getMessage());
}
}
上面的代码请求WRITE_CONTACT权限,如果没有权限进行调用时,程序将会直接崩溃。
3.在AndroidManifest.xml中添加相应的权限声明
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
4.在这一步,我门必须创建一个函数去检查权限是否被授予
权限被分组成为Permission Group,如下表所示:
(原文:If any permission in a Permission Group is granted. Another permission in the same group will be automatically granted as well. In this case, once WRITE_CONTACTS is granted, application will also grant READ_CONTACTS and GET_ACCOUNTS.)(翻译原文:如果获得Permission Group的权限,则分组中所有权限都会获取到。
WRITE_CONTACTS权限被授予以后,应用将会获得READ_CONTACTS和GET_ACCOUNTS的权限。)
5.使用Activity的checkSelfPermission和requestPermissions方法来进行权限的检查以及权限的请求,这些方法都是在API Level 23中添加的,即Android M(6.0)版本以上。
private void insertDummyContactWrapper() {
// 1。判断是否已经拥有AndroidManifest.xml中声明的权限
int hasWriteContactsPermission = checkSelfPermission(Manifest.permission.WRITE_CONTACTS);
if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
// 如果没有权限,则通过requestPermissions来调用权限请求对话框
requestPermissions(new String[] {Manifest.permission.WRITE_CONTACTS}, REQUEST_CODE_ASK_PERMISSIONS);
return;
}
// 2。如果有的话则直接执行insertDummyContact
insertDummyContact();
}
6.无论用户选择拒绝或者允许,Activity的onRequestPermissionsResult方法都会被调用。
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case REQUEST_CODE_ASK_PERMISSIONS:
// 通过这个requestCode来判断是那个函数请求的权限
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 权限被允许时
insertDummyContact();
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
这就是Android6.0及更高版本的Runtime Permission权限的申请和使用的过程。
这篇文章是在我遇到Android6.0权限申请时遇到问题时搜到的文章,文章写的很棒,由于是英文的。。。。。
然后就自己翻译了一下,如有不对,大家勿喷,请去看原版,
原版地址如下:
https://inthecheesefactory.com/blog/things-you-need-to-know-about-android-m-permission-developer-edition/en