Android M 新的运转时权限开发者需求知道的全部-Android-优质IT资源分享社区

admin
管理员
管理员
  • UID1
  • 粉丝27
  • 关注4
  • 发帖数581
  • 社区居民
  • 忠实会员
  • 原创写手
阅读:236回复:0

  Android M 新的运转时权限开发者需求知道的全部

楼主#
更多 发布于:2016-05-31 16:31

android M 的姓名官方刚发布不久,最终正式版即将来临!

android在不断发展,近来的更新 M

十分不相同,一些首要的变化例如运转时权限将有颠覆性影响。惊奇的是android社区鲜有谈论这事儿,虽然这事很主要或许在不远的将来会引发很严重的疑问。

这是今日我写这篇博客的原因。这里有全部关于android运转时权限你需求知道的,包含如何在代码中完成。如今亡羊补牢还不晚。

新运转时权限

android的权限体系一直是首要的安全概念,由于这些权限只在装置的时分被问询一次。一旦装置了,app能够在用户毫不知晓的状况下拜访权限内的全部东西。

难怪一些坏蛋运用这个缺点恶意搜集用户数据用来做坏事了!

android小组也知道这事儿。7年了!权限体系总算被重新规划了。在android6.0棉花糖,app将不会在装置的时分颁发权限。取而代之的是,app不得不在运转时一个一个问询用户颁发权限。

留意权限问询对话框不会自个弹出来。开发者不得不自个调用。假如开发者要调用的一些函数需求某权限而用户又回绝授权的话,函数将抛出反常直接致使程序溃散。

别的,用户也能够随时在设置里吊销现已授权的权限。

你或许现已感觉到背面生出一阵寒意。。。假如你是个android开发者,意味着要彻底改动你的程序逻辑。你不能像曾经那样直接调用办法了,你不得不为每个需求的地方查看权限,不然app就溃散了!

是的。我不能哄你说这是简略的事儿。虽然这对用户来说是功德,可是对开发者来说即是噩梦。咱们不得不修正编码不然不管短期仍是久远来看都是潜在的疑问。

这个新的运转时权限仅当咱们设置targetSdkVersion to

23(这意味着你现已在23上测验经过了)才起作用,当然还要是M体系的手机。app在6.0之前的设备仍然运用旧的权限体系。

现已发布了的app会发作啥

新运转时权限也许现已让你开端恐慌了。“hey,店员!我三年前发布的app可咋整呢。假如他被装到android

6.0上,我的app会溃散吗?!?”

莫紧张,放轻松。android小队又不傻,肯定考虑到了这状况。假如app的targetSdkVersion

低于 23,那将被以为app没有用23新权限测验过,那将被持续运用旧有规矩:用户在装置的时分不得不承受全部权限,装置后app就有了那些权限咯!

然后app像曾经相同奔跑!留意,此刻用户仍然能够吊销现已赞同的授权!用户吊销授权时,android

6.0体系会正告,但这不阻碍用户吊销授权。

疑问又来了,这时分你的app溃散吗?

好心的主把这事也告诉了android小组,当咱们在targetSdkVersion

低于23的app调用一个需求权限的函数时,这个权限假如被用户吊销授权了的话,不抛出反常。可是他将啥都不干,成果致使函数回来值是null或许0.

别高兴的太早。虽然app不会调用这个函数时溃散,回来值null或许0也许接下来仍然致使溃散。

好消息(最少如今看来)是这类吊销权限的状况比较少,我信任很少用户这么搞。假如他们这么办了,后果自负咯。

但从久远看来,我信任仍是会有许多用户会封闭一些权限。咱们app不能再新设备完美运转这是不可承受的。

怎样让他完美运转呢,你最佳修正代码支撑最新的权限体系,并且我主张你马上着手搞起!

代码没有成功改为支撑最新运转时权限的app,不要设置targetSdkVersion 23

发布,不然你就有麻烦了。只要当你测验过了,再改为targetSdkVersion 23 。

正告:如今你在android studio新建项目,targetSdkVersion 会主动设置为

23。假如你还没支撑新运转时权限,我主张你首先把targetSdkVersion 降级到22

PROTECTION_NORMAL类权限

当用户装置或更新应用时,体系将颁发应用所恳求的归于 PROTECTION_NORMAL

的全部权限(装置时授权的一类基本权限)。这类权限包含:

android.permission.ACCESS_LOCATION_EXTRA_COMMANDSandroid.permission.ACCESS_NETWORK_STATEandroid.permission.ACCESS_NOTIFICATION_POLICYandroid.permission.ACCESS_WIFI_STATEandroid.permission.ACCESS_WIMAX_STATEandroid.permission.BLUETOOTHandroid.permission.BLUETOOTH_ADMINandroid.permission.BROADCAST_STICKYandroid.permission.CHANGE_NETWORK_STATEandroid.permission.CHANGE_WIFI_MULTICAST_STATEandroid.permission.CHANGE_WIFI_STATEandroid.permission.CHANGE_WIMAX_STATEandroid.permission.DISABLE_KEYGUARDandroid.permission.EXPAND_STATUS_BARandroid.permission.FLASHLIGHTandroid.permission.GET_ACCOUNTSandroid.permission.GET_PACKAGE_SIZEandroid.permission.INTERNETandroid.permission.KILL_BACKGROUND_PROCESSESandroid.permission.MODIFY_AUDIO_SETTINGSandroid.permission.NFCandroid.permission.READ_SYNC_SETTINGSandroid.permission.READ_SYNC_STATSandroid.permission.RECEIVE_BOOT_COMPLETEDandroid.permission.REORDER_TASKSandroid.permission.REQUEST_INSTALL_PACKAGESandroid.permission.SET_TIME_ZONEandroid.permission.SET_WALLPAPERandroid.permission.SET_WALLPAPER_HINTSandroid.permission.SUBSCRIBED_FEEDS_READandroid.permission.TRANSMIT_IRandroid.permission.USE_FINGERPRINTandroid.permission.VIBRATEandroid.permission.WAKE_LOCKandroid.permission.WRITE_SYNC_SETTINGScom.android.alarm.permission.SET_ALARMcom.android.launcher.permission.INSTALL_SHORTCUTcom.android.launcher.permission.UNINSTALL_SHORTCUT

只需求在AndroidManifest.xml中简略声明这些权限就好,装置时就授权。不需求每次运用时都查看权限,并且用户不能吊销以上授权。

让你的app支撑新运转时权限

是时分让咱们的app支撑新权限模型了,从设置compileSdkVersion

andtargetSdkVersion 为 23开端吧.

android {     compileSdkVersion 23     ...    

defaultConfig {         ...         targetSdkVersion 23         ...    }}

比如,我想用一下办法增加联系人。

private static final String TAG =

"Contacts";private void insertDummyContact() {      // Two operations are needed

to insert a new contact.      ArrayListoperations =

new ArrayList(2);      // 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_CONTACTS权限。假如不问询授权,app就崩了。

下一步像曾经相同在AndroidManifest.xml增加声明权限。

下一步,不得不再写个办法查看有没有权限。假如没有弹个对话框问询用户授权。然后你才能够下一步创立联系人。

权限被分组了,如下表:

同一组的任何一个权限被授权了,别的权限也主动被授权。例如,一旦WRITE_CONTACTS被授权了,app也有READ_CONTACTS和GET_ACCOUNTS了。

源码中被用来查看和恳求权限的办法分别是Activity的checkSelfPermission和requestPermissions。这些办法api23引进。

final private int REQUEST_CODE_ASK_PERMISSIONS =

123;private void insertDummyContactWrapper() {      int

hasWriteContactsPermission =

checkSelfPermission(Manifest.permission.WRITE_CONTACTS);      if

(hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {          

requestPermissions(new String[] {Manifest.permission.WRITE_CONTACTS},

REQUEST_CODE_ASK_PERMISSIONS);           return;      }    

 insertDummyContact();}

假如已有权限,insertDummyContact()会履行。不然,requestPermissions被履行来弹出恳求授权对话框,如下:

不管用户赞同仍是回绝,activity的onRequestPermissionsResult会被回调来告诉成果(经过第三个参数),grantResults,如下:

@Overridepublic void

onRequestPermissionsResult(int requestCode, String[] permissions, int[]

grantResults) {     switch (requestCode) {         case

REQUEST_CODE_ASK_PERMISSIONS:              if (grantResults[0] ==

PackageManager.PERMISSION_GRANTED) {                   // Permission Granted    

              insertDummyContact();              } else {                   //

Permission Denied                   Toast.makeText(MainActivity.this,

"WRITE_CONTACTS Denied", Toast.LENGTH_SHORT).show();              }            

 break;        default:            

 super.onRequestPermissionsResult(requestCode, permissions, grantResults);      

 }}

这即是新权限模型作业过程。代码真杂乱可是只能去习气它。。。为了让app极好兼容新权限模型,你不得不必以上相似办法处理全部需求的状况。

假如你想捶墙,如今是时分了。。。

处理 “不再提示”

假如用户回绝某授权。下一次弹框,用户会有一个“不再提示”的选项的来防止app今后持续恳求授权。

假如这个选项在回绝授权前被用户勾选了。下次为这个权限恳求requestPermissions时,对话框就不弹出来了,成果即是,app啥都不干。

这将是很差的用户体验,用户做了操作却得不到呼应。这种状况需求好好处理一下。在恳求requestPermissions前,咱们需求查看是不是需求展现恳求权限的提示经过activity的shouldShowRequestPermissionRationale,代码如下:

final private int REQUEST_CODE_ASK_PERMISSIONS =

123;private void insertDummyContactWrapper() {      int

hasWriteContactsPermission =

checkSelfPermission(Manifest.permission.WRITE_CONTACTS);      if

(hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {          

 if (!shouldShowRequestPermissionRationale(Manifest.permission.WRITE_CONTACTS))

{                  showMessageOKCancel("You need to allow access to Contacts",  

                      new DialogInterface.OnClickListener() {                  

           @Override                              public void

onClick(DialogInterface dialog, int which) {                                  

requestPermissions(new String[] {Manifest.permission.WRITE_CONTACTS},          

                                REQUEST_CODE_ASK_PERMISSIONS);                  

           }                         });                  return;            }  

         requestPermissions(new String[] {Manifest.permission.WRITE_CONTACTS},

REQUEST_CODE_ASK_PERMISSIONS);            return;       }      

insertDummyContact();}private void showMessageOKCancel(String message,

DialogInterface.OnClickListener okListener) {      new

AlertDialog.Builder(MainActivity.this)           .setMessage(message)          

.setPositiveButton("OK", okListener)           .setNegativeButton("Cancel",

null)           .create()           .show();}

当一个权限首次被恳求和用户标记过不再提示的时分,咱们写的对话框被展现。

后一种状况,onRequestPermissionsResult

会收到PERMISSION_DENIED ,体系问询对话框不展现。

搞定!

一次恳求多个权限

当然了有时分需求好多权限,能够用上面办法一次恳求多个权限。不要忘了为每个权限查看“不再提示”的设置。

修正后的代码:

final private int

REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 124;private void

insertDummyContactWrapper() {      ListpermissionsNeeded = new

ArrayList();      final ListpermissionsList = new

ArrayList();      if (!addPermission(permissionsList,

Manifest.permission.ACCESS_FINE_LOCATION))          

permissionsNeeded.add("GPS");      if (!addPermission(permissionsList,

Manifest.permission.READ_CONTACTS))           permissionsNeeded.add("Read

Contacts");      if (!addPermission(permissionsList,

Manifest.permission.WRITE_CONTACTS))           permissionsNeeded.add("Write

Contacts");      if (permissionsList.size() > 0) {           if

(permissionsNeeded.size() > 0) {                 // Need Rationale          

      String message = "You need to grant access to " +

permissionsNeeded.get(0);                 for (int i = 1; i <

permissionsNeeded.size(); i++)                        message = message + ", " +

permissionsNeeded.get(i);                 showMessageOKCancel(message,          

           new DialogInterface.OnClickListener() {                          

@Override                           public void onClick(DialogInterface dialog,

int which) {                                

requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),

REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);                           }         });

             return;     }     requestPermissions(permissionsList.toArray(new

String[permissionsList.size()]),     REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);    

return; }     insertDummyContact();}private boolean

addPermission(ListpermissionsList, String permission) {     if

(checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {        

  permissionsList.add(permission);           // Check for Rationale Option      

    if (!shouldShowRequestPermissionRationale(permission))                

return false;     }     return

true;}

假如全部权限被授权,仍然回调onRequestPermissionsResult,我用hashmap让代码整齐便于阅读。

@Overridepublic void

onRequestPermissionsResult(int requestCode, String[] permissions, int[]

grantResults) {     switch (requestCode) {         case

REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS:        {              Mapperms = new HashMap();              // Initial  

           perms.put(Manifest.permission.ACCESS_FINE_LOCATION,

PackageManager.PERMISSION_GRANTED);            

 perms.put(Manifest.permission.READ_CONTACTS,

PackageManager.PERMISSION_GRANTED);            

 perms.put(Manifest.permission.WRITE_CONTACTS,

PackageManager.PERMISSION_GRANTED);              // Fill with results          

   for (int i = 0; i < permissions.length; i++)                  

 perms.put(permissions, grantResults);                    // Check for

ACCESS_FINE_LOCATION                    if

(perms.get(Manifest.permission.ACCESS_FINE_LOCATION) ==

PackageManager.PERMISSION_GRANTED &&

perms.get(Manifest.permission.READ_CONTACTS) ==

PackageManager.PERMISSION_GRANTED   &&

perms.get(Manifest.permission.WRITE_CONTACTS) ==

PackageManager.PERMISSION_GRANTED) {                          // All Permissions

Granted                          insertDummyContact();                    } else

{                           // Permission Denied                          

Toast.makeText(MainActivity.this, "Some Permission is Denied",

Toast.LENGTH_SHORT) .show();                     }              }            

 break;        default:            

 super.onRequestPermissionsResult(requestCode, permissions, grantResults);    

 }}

条件灵敏的,你自个设置。有的状况,一个权限没有授权,就不可用;可是也有状况,能作业,可是体现的是有所约束的。关于这个我不做评估,你自个规划吧。

用兼容库使代码兼容旧版

以上代码在android 6.0以上运转没疑问,可是23

api之前就不行了,由于没有那些办法。

粗暴的办法是查看版别

if (Build.VERSION.SDK_INT >= 23) {      //

Marshmallow+} else {      // Pre-Marshmallow}

可是太杂乱,我主张用v4兼容库,已对这个做过兼容,用这个办法替代:

ContextCompat.checkSelfPermission()

被授权函数回来PERMISSION_GRANTED,不然回来PERMISSION_DENIED

,在全部版别都是如此。

ActivityCompat.requestPermissions()

这个办法在M之前版别调用,OnRequestPermissionsResultCallback

直接被调用,带着正确的 PERMISSION_GRANTED或许 PERMISSION_DENIED 。

ActivityCompat.shouldShowRequestPermissionRationale()

在M之前版别调用,永远回来false。

用v4包的这三办法,完美兼容全部版别!这个办法需求额定的参数,Context or

Activity。别的就没啥特别的了。下面是代码:

private void insertDummyContactWrapper() {      

int hasWriteContactsPermission =

ContextCompat.checkSelfPermission(MainActivity.this,

Manifest.permission.WRITE_CONTACTS);       if (hasWriteContactsPermission !=

PackageManager.PERMISSION_GRANTED) {             if

(!ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,        

          Manifest.permission.WRITE_CONTACTS)) {                  

showMessageOKCancel("You need to allow access to Contacts",                  

new DialogInterface.OnClickListener() {                        @Override        

               public void onClick(DialogInterface dialog, int which) {        

                     ActivityCompat.requestPermissions(MainActivity.this,      

                             new String[] {Manifest.permission.WRITE_CONTACTS},

                                                REQUEST_CODE_ASK_PERMISSIONS);  

                     }                   });             return;        }      

 ActivityCompat.requestPermissions(MainActivity.this, new String[]

{Manifest.permission.WRITE_CONTACTS}, REQUEST_CODE_ASK_PERMISSIONS);      

 return;    }    insertDummyContact();}

后两个办法,咱们也能够在Fragment中运用,用v13兼容包:FragmentCompat.requestPermissions()

and FragmentCompat.shouldShowRequestPermissionRationale().和activity作用相同。

第三方库简化代码

以上代码真尼玛杂乱。为处理这事,有许多第三方库现已面世了,真屌真有速度。我试了许多最终找到了个满足的hotchemi’s

PermissionsDispatcher。

他和我上面做的相同,仅仅简化了代码。灵敏易扩展,试一下吧。假如不满足你能够找些别的的。

### 假如我的app还开着呢,权限被吊销了,会发作生么

权限随时能够被吊销。

当app开着的时分被撤消了会发作啥呢?我试过了发现这时app会俄然停止

terminated。app中的全部都被简略粗暴的停止了,由于terminated!对我来说这能够了解,由于体系假如答应它持续运转(没有某权限),这会呼唤弗雷迪到我的噩梦里。或许更糟…

定论主张

我信任你对新权限模型现已有了清晰的认识。我信任你也认识到了疑问的严重。

可是你没得挑选。新运转时权限现已在棉花糖中被运用了。咱们没有退路。咱们如今仅有能做的即是确保app适配新权限模型.

欣慰的是只要少数权限需求运转时权限模型。大多数常用的权限,例如,网络拜访,归于Normal

Permission 在装置时主动会授权,当然你要声明,今后无需查看。因而,只要少部分代码你需求修正。

两个主张:

1.严厉对待新权限模型

2.假如你代码没支撑新权限,不要设置targetSdkVersion 23

。尤其是当你在Studio新建工程时,不要忘了修正!

说一下代码修正。这是大事,假如代码构造被规划的不够好,你需求一些很蛋疼的重构。每个app都要被修正。如上所说,咱们没的挑选。。。

列出全部你需求恳求的权限全部景象,假如A被授权,B被回绝,会发作啥。blah,blah。

祝重构顺畅。把它列为你需求做的大事,从如今就开端着手做,以确保M正式发布的时分没有疑问。

期望本文对你有用,高兴编码!

优质IT资源分享社区为你提供此文。

站有大量优质android教程视频,资料等资源,包含android基础教程,高级进阶教程等等,教程视频资源涵盖传智播客,极客学院,达内,北大青鸟,猎豹网校等等IT职业培训机构的培训教学视频,价值巨大。欢迎点击下方链接查看。

android教程视频

优质IT资源分享社区(www.itziyuan.top)
一个免费,自由,开放,共享,平等,互助的优质IT资源分享网站。
专注免费分享各大IT培训机构最新培训教学视频,为你的IT学习助力!

!!!回帖受限制请看点击这里!!!
!!!资源失效请在此版块发帖说明!!!

[PS:按 CTRL+D收藏本站网址~]

——“优质IT资源分享社区”管理员专用签名~

本版相似帖子

游客