自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Android M新的運(yùn)行時(shí)權(quán)限開(kāi)發(fā)者需要知道的一切

移動(dòng)開(kāi)發(fā)
android M 的名字官方剛發(fā)布不久,最終正式版即將來(lái)臨!android在不斷發(fā)展,最近的更新 M 非常不同,一些主要的變化例如運(yùn)行時(shí)權(quán)限將有顛覆性影響。驚訝的是android社區(qū)鮮有談?wù)撨@事兒,盡管這事很重要或許在不遠(yuǎn)的將來(lái)會(huì)引發(fā)很?chē)?yán)重的問(wèn)題。這是今天我寫(xiě)這篇博客的原因。這里有一切關(guān)于android運(yùn)行時(shí)權(quán)限你需要知道的,包括如何在代碼中實(shí)現(xiàn)?,F(xiàn)在亡羊補(bǔ)牢還不晚。

翻譯的國(guó)外一篇文章。

android M 的名字官方剛發(fā)布不久,最終正式版即將來(lái)臨!

android在不斷發(fā)展,最近的更新 M 非常不同,一些主要的變化例如運(yùn)行時(shí)權(quán)限將有顛覆性影響。驚訝的是android社區(qū)鮮有談?wù)撨@事兒,盡管這事很重要或許在不遠(yuǎn)的將來(lái)會(huì)引發(fā)很?chē)?yán)重的問(wèn)題。

這是今天我寫(xiě)這篇博客的原因。這里有一切關(guān)于android運(yùn)行時(shí)權(quán)限你需要知道的,包括如何在代碼中實(shí)現(xiàn)?,F(xiàn)在亡羊補(bǔ)牢還不晚。

新運(yùn)行時(shí)權(quán)限

android的權(quán)限系統(tǒng)一直是首要的安全概念,因?yàn)檫@些權(quán)限只在安裝的時(shí)候被詢(xún)問(wèn)一次。一旦安裝了,app可以在用戶毫不知曉的情況下訪問(wèn)權(quán)限內(nèi)的所有東西。

難怪一些壞蛋利用這個(gè)缺陷惡意收集用戶數(shù)據(jù)用來(lái)做壞事了!

android小組也知道這事兒。7年了!權(quán)限系統(tǒng)終于被重新設(shè)計(jì)了。在android6.0棉花糖,app將不會(huì)在安裝的時(shí)候授予權(quán)限。取而代之的是,app不得不在運(yùn)行時(shí)一個(gè)一個(gè)詢(xún)問(wèn)用戶授予權(quán)限。

Paste_Image.png

注意權(quán)限詢(xún)問(wèn)對(duì)話框不會(huì)自己彈出來(lái)。開(kāi)發(fā)者不得不自己調(diào)用。如果開(kāi)發(fā)者要調(diào)用的一些函數(shù)需要某權(quán)限而用戶又拒絕授權(quán)的話,函數(shù)將拋出異常直接導(dǎo)致程序崩潰。

Paste_Image.png

另外,用戶也可以隨時(shí)在設(shè)置里取消已經(jīng)授權(quán)的權(quán)限。

Paste_Image.png

你或許已經(jīng)感覺(jué)到背后生出一陣寒意。。。如果你是個(gè)android開(kāi)發(fā)者,意味著要完全改變你的程序邏輯。你不能像以前那樣直接調(diào)用方法了,你不得不為每個(gè)需要的地方檢察權(quán)限,否則app就崩潰了!

是的。我不能哄你說(shuō)這是簡(jiǎn)單的事兒。盡管這對(duì)用戶來(lái)說(shuō)是好事,但是對(duì)開(kāi)發(fā)者來(lái)說(shuō)就是噩夢(mèng)。我們不得不修改編碼不然不論短期還是長(zhǎng)遠(yuǎn)來(lái)看都是潛在的問(wèn)題。

這個(gè)新的運(yùn)行時(shí)權(quán)限僅當(dāng)我們?cè)O(shè)置targetSdkVersion to 23(這意味著你已經(jīng)在23上測(cè)試通過(guò)了)才起作用,當(dāng)然還要是M系統(tǒng)的手機(jī)。app在6.0之前的設(shè)備依然使用舊的權(quán)限系統(tǒng)。

已經(jīng)發(fā)布了的app會(huì)發(fā)生什么

新運(yùn)行時(shí)權(quán)限可能已經(jīng)讓你開(kāi)始恐慌了。“hey,伙計(jì)!我三年前發(fā)布的app可咋整呢。如果他被裝到android 6.0上,我的app會(huì)崩潰嗎??。?rdquo;

莫慌張,放輕松。android小隊(duì)又不傻,肯定考慮到了這情況。如果app的targetSdkVersion 低于 23,那將被認(rèn)為app沒(méi)有用23新權(quán)限測(cè)試過(guò),那將被繼續(xù)使用舊有規(guī)則:用戶在安裝的時(shí)候不得不接受所有權(quán)限,安裝后app就有了那些權(quán)限咯!

Paste_Image.png

然后app像以前一樣奔跑!注意,此時(shí)用戶依然可以取消已經(jīng)同意的授權(quán)!用戶取消授權(quán)時(shí),android 6.0系統(tǒng)會(huì)警告,但這不妨礙用戶取消授權(quán)。

Paste_Image.png

問(wèn)題又來(lái)了,這時(shí)候你的app崩潰嗎?

#p#

善意的主把這事也告訴了android小組,當(dāng)我們?cè)趖argetSdkVersion 低于23的app調(diào)用一個(gè)需要權(quán)限的函數(shù)時(shí),這個(gè)權(quán)限如果被用戶取消授權(quán)了的話,不拋出異常。但是他將啥都不干,結(jié)果導(dǎo)致函數(shù)返回值是null或者0.

Paste_Image.png

別高興的太早。盡管app不會(huì)調(diào)用這個(gè)函數(shù)時(shí)崩潰,返回值null或者0可能接下來(lái)依然導(dǎo)致崩潰。

好消息(至少目前看來(lái))是這類(lèi)取消權(quán)限的情況比較少,我相信很少用戶這么搞。如果他們這么辦了,后果自負(fù)咯。

但從長(zhǎng)遠(yuǎn)看來(lái),我相信還是會(huì)有大量用戶會(huì)關(guān)閉一些權(quán)限。我們app不能再新設(shè)備完美運(yùn)行這是不可接受的。

怎樣讓他完美運(yùn)行呢,你最好修改代碼支持最新的權(quán)限系統(tǒng),而且我建議你立刻著手搞起!

代碼沒(méi)有成功改為支持最新運(yùn)行時(shí)權(quán)限的app,不要設(shè)置targetSdkVersion 23 發(fā)布,否則你就有麻煩了。只有當(dāng)你測(cè)試過(guò)了,再改為targetSdkVersion 23 。

警告:現(xiàn)在你在android studio新建項(xiàng)目,targetSdkVersion 會(huì)自動(dòng)設(shè)置為 23。如果你還沒(méi)支持新運(yùn)行時(shí)權(quán)限,我建議你首先把targetSdkVersion 降級(jí)到22

PROTECTION_NORMAL類(lèi)權(quán)限

當(dāng)用戶安裝或更新應(yīng)用時(shí),系統(tǒng)將授予應(yīng)用所請(qǐng)求的屬于 PROTECTION_NORMAL 的所有權(quán)限(安裝時(shí)授權(quán)的一類(lèi)基本權(quán)限)。這類(lèi)權(quán)限包括:

  1. android.permission.ACCESS_LOCATION_EXTRA_COMMANDS 
  2. android.permission.ACCESS_NETWORK_STATE 
  3. android.permission.ACCESS_NOTIFICATION_POLICY 
  4. android.permission.ACCESS_WIFI_STATE 
  5. android.permission.ACCESS_WIMAX_STATE 
  6. android.permission.BLUETOOTH 
  7. android.permission.BLUETOOTH_ADMIN 
  8. android.permission.BROADCAST_STICKY 
  9. android.permission.CHANGE_NETWORK_STATE 
  10. android.permission.CHANGE_WIFI_MULTICAST_STATE 
  11. android.permission.CHANGE_WIFI_STATE 
  12. android.permission.CHANGE_WIMAX_STATE 
  13. android.permission.DISABLE_KEYGUARD 
  14. android.permission.EXPAND_STATUS_BAR 
  15. android.permission.FLASHLIGHT 
  16. android.permission.GET_ACCOUNTS 
  17. android.permission.GET_PACKAGE_SIZE 
  18. android.permission.INTERNET 
  19. android.permission.KILL_BACKGROUND_PROCESSES 
  20. android.permission.MODIFY_AUDIO_SETTINGS 
  21. android.permission.NFC 
  22. android.permission.READ_SYNC_SETTINGS 
  23. android.permission.READ_SYNC_STATS 
  24. android.permission.RECEIVE_BOOT_COMPLETED 
  25. android.permission.REORDER_TASKS 
  26. android.permission.REQUEST_INSTALL_PACKAGES 
  27. android.permission.SET_TIME_ZONE 
  28. android.permission.SET_WALLPAPER 
  29. android.permission.SET_WALLPAPER_HINTS 
  30. android.permission.SUBSCRIBED_FEEDS_READ 
  31. android.permission.TRANSMIT_IR 
  32. android.permission.USE_FINGERPRINT 
  33. android.permission.VIBRATE 
  34. android.permission.WAKE_LOCK 
  35. android.permission.WRITE_SYNC_SETTINGS 
  36. com.android.alarm.permission.SET_ALARM 
  37. com.android.launcher.permission.INSTALL_SHORTCUT 
  38. com.android.launcher.permission.UNINSTALL_SHORTCUT 

只需要在AndroidManifest.xml中簡(jiǎn)單聲明這些權(quán)限就好,安裝時(shí)就授權(quán)。不需要每次使用時(shí)都檢查權(quán)限,而且用戶不能取消以上授權(quán)。

讓你的app支持新運(yùn)行時(shí)權(quán)限

是時(shí)候讓我們的app支持新權(quán)限模型了,從設(shè)置compileSdkVersion and targetSdkVersion為 23開(kāi)始吧.

  1. android { 
  2.     compileSdkVersion 23 
  3.     ... 
  4.  
  5.     defaultConfig { 
  6.         ... 
  7.         targetSdkVersion 23 
  8.         ... 
  9.     } 

例子,我想用一下方法添加聯(lián)系人。

  1. private static final String TAG = "Contacts"
  2. private void insertDummyContact() { 
  3.     // Two operations are needed to insert a new contact. 
  4.     ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(2); 
  5.  
  6.     // First, set up a new raw contact. 
  7.     ContentProviderOperation.Builder op = 
  8.             ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) 
  9.                     .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null
  10.                     .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null); 
  11.     operations.add(op.build()); 
  12.  
  13.     // Next, set the name for the contact. 
  14.     op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) 
  15.             .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0
  16.             .withValue(ContactsContract.Data.MIMETYPE, 
  17.                     ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) 
  18.             .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, 
  19.                     "__DUMMY CONTACT from runtime permissions sample"); 
  20.     operations.add(op.build()); 
  21.  
  22.     // Apply the operations. 
  23.     ContentResolver resolver = getContentResolver(); 
  24.     try { 
  25.         resolver.applyBatch(ContactsContract.AUTHORITY, operations); 
  26.     } catch (RemoteException e) { 
  27.         Log.d(TAG, "Could not add a new contact: " + e.getMessage()); 
  28.     } catch (OperationApplicationException e) { 
  29.         Log.d(TAG, "Could not add a new contact: " + e.getMessage()); 
  30.     } 

上面代碼需要WRITE_CONTACTS權(quán)限。如果不詢(xún)問(wèn)授權(quán),app就崩了。

下一步像以前一樣在AndroidManifest.xml添加聲明權(quán)限。

  1. <uses-permission android:name="android.permission.WRITE_CONTACTS"/> 

下一步,不得不再寫(xiě)個(gè)方法檢查有沒(méi)有權(quán)限。如果沒(méi)有彈個(gè)對(duì)話框詢(xún)問(wèn)用戶授權(quán)。然后你才可以下一步創(chuàng)建聯(lián)系人。

權(quán)限被分組了,如下表:

Paste_Image.png

同一組的任何一個(gè)權(quán)限被授權(quán)了,其他權(quán)限也自動(dòng)被授權(quán)。例如,一旦WRITE_CONTACTS被授權(quán)了,app也有READ_CONTACTS和GET_ACCOUNTS了。
源碼中被用來(lái)檢查和請(qǐng)求權(quán)限的方法分別是Activity的checkSelfPermission和requestPermissions。這些方法api23引入。

  1. final private int REQUEST_CODE_ASK_PERMISSIONS = 123
  2.  
  3. private void insertDummyContactWrapper() { 
  4.     int hasWriteContactsPermission = checkSelfPermission(Manifest.permission.WRITE_CONTACTS); 
  5.     if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) { 
  6.         requestPermissions(new String[] {Manifest.permission.WRITE_CONTACTS}, 
  7.                 REQUEST_CODE_ASK_PERMISSIONS); 
  8.         return
  9.     } 
  10.     insertDummyContact(); 

如果已有權(quán)限,insertDummyContact()會(huì)執(zhí)行。否則,requestPermissions被執(zhí)行來(lái)彈出請(qǐng)求授權(quán)對(duì)話框,如下:

Paste_Image.png

#p#

不論用戶同意還是拒絕,activity的onRequestPermissionsResult會(huì)被回調(diào)來(lái)通知結(jié)果(通過(guò)第三個(gè)參數(shù)),grantResults,如下:

  1. @Override 
  2. public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { 
  3.     switch (requestCode) { 
  4.         case REQUEST_CODE_ASK_PERMISSIONS: 
  5.             if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { 
  6.                 // Permission Granted 
  7.                 insertDummyContact(); 
  8.             } else { 
  9.                 // Permission Denied 
  10.                 Toast.makeText(MainActivity.this"WRITE_CONTACTS Denied", Toast.LENGTH_SHORT) 
  11.                         .show(); 
  12.             } 
  13.             break
  14.         default
  15.             super.onRequestPermissionsResult(requestCode, permissions, grantResults); 
  16.     } 

這就是新權(quán)限模型工作過(guò)程。代碼真復(fù)雜但是只能去習(xí)慣它。。。為了讓app很好兼容新權(quán)限模型,你不得不用以上類(lèi)似方法處理所有需要的情況。
如果你想捶墻,現(xiàn)在是時(shí)候了。。。

處理 “不再提醒”

如果用戶拒絕某授權(quán)。下一次彈框,用戶會(huì)有一個(gè)“不再提醒”的選項(xiàng)的來(lái)防止app以后繼續(xù)請(qǐng)求授權(quán)。

Paste_Image.png

如果這個(gè)選項(xiàng)在拒絕授權(quán)前被用戶勾選了。下次為這個(gè)權(quán)限請(qǐng)求requestPermissions時(shí),對(duì)話框就不彈出來(lái)了,結(jié)果就是,app啥都不干。

這將是很差的用戶體驗(yàn),用戶做了操作卻得不到響應(yīng)。這種情況需要好好處理一下。在請(qǐng)求requestPermissions前,我們需要檢查是否需要展示請(qǐng)求權(quán)限的提示通過(guò)activity的shouldShowRequestPermissionRationale,代碼如下:

  1. final private int REQUEST_CODE_ASK_PERMISSIONS = 123
  2.  
  3. private void insertDummyContactWrapper() { 
  4.     int hasWriteContactsPermission = checkSelfPermission(Manifest.permission.WRITE_CONTACTS); 
  5.     if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) { 
  6.             if (!shouldShowRequestPermissionRationale(Manifest.permission.WRITE_CONTACTS)) { 
  7.                 showMessageOKCancel("You need to allow access to Contacts"
  8.                         new DialogInterface.OnClickListener() { 
  9.                             @Override 
  10.                             public void onClick(DialogInterface dialog, int which) { 
  11.                                 requestPermissions(new String[] {Manifest.permission.WRITE_CONTACTS}, 
  12.                                         REQUEST_CODE_ASK_PERMISSIONS); 
  13.                             } 
  14.                         }); 
  15.                 return
  16.             } 
  17.         requestPermissions(new String[] {Manifest.permission.WRITE_CONTACTS}, 
  18.                 REQUEST_CODE_ASK_PERMISSIONS); 
  19.         return
  20.     } 
  21.     insertDummyContact(); 
  22.  
  23. private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) { 
  24.     new AlertDialog.Builder(MainActivity.this
  25.             .setMessage(message) 
  26.             .setPositiveButton("OK", okListener) 
  27.             .setNegativeButton("Cancel"null
  28.             .create() 
  29.             .show(); 

當(dāng)一個(gè)權(quán)限第一次被請(qǐng)求和用戶標(biāo)記過(guò)不再提醒的時(shí)候,我們寫(xiě)的對(duì)話框被展示。

后一種情況,onRequestPermissionsResult 會(huì)收到PERMISSION_DENIED ,系統(tǒng)詢(xún)問(wèn)對(duì)話框不展示。

Paste_Image.png

搞定!

一次請(qǐng)求多個(gè)權(quán)限

當(dāng)然了有時(shí)候需要好多權(quán)限,可以用上面方法一次請(qǐng)求多個(gè)權(quán)限。不要忘了為每個(gè)權(quán)限檢查“不再提醒”的設(shè)置。
修改后的代碼:

  1. final private int REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 124
  2.  
  3. private void insertDummyContactWrapper() { 
  4.     List<String> permissionsNeeded = new ArrayList<String>(); 
  5.  
  6.     final List<String> permissionsList = new ArrayList<String>(); 
  7.     if (!addPermission(permissionsList, Manifest.permission.ACCESS_FINE_LOCATION)) 
  8.         permissionsNeeded.add("GPS"); 
  9.     if (!addPermission(permissionsList, Manifest.permission.READ_CONTACTS)) 
  10.         permissionsNeeded.add("Read Contacts"); 
  11.     if (!addPermission(permissionsList, Manifest.permission.WRITE_CONTACTS)) 
  12.         permissionsNeeded.add("Write Contacts"); 
  13.  
  14.     if (permissionsList.size() > 0) { 
  15.         if (permissionsNeeded.size() > 0) { 
  16.             // Need Rationale 
  17.             String message = "You need to grant access to " + permissionsNeeded.get(0); 
  18.             for (int i = 1; i < permissionsNeeded.size(); i++) 
  19.                 message = message + ", " + permissionsNeeded.get(i); 
  20.             showMessageOKCancel(message, 
  21.                     new DialogInterface.OnClickListener() { 
  22.                         @Override 
  23.                         public void onClick(DialogInterface dialog, int which) { 
  24.                             requestPermissions(permissionsList.toArray(new String[permissionsList.size()]), 
  25.                                     REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS); 
  26.                         } 
  27.                     }); 
  28.             return
  29.         } 
  30.         requestPermissions(permissionsList.toArray(new String[permissionsList.size()]), 
  31.                 REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS); 
  32.         return
  33.     } 
  34.  
  35.     insertDummyContact(); 
  36.  
  37. private boolean addPermission(List<String> permissionsList, String permission) { 
  38.     if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) { 
  39.         permissionsList.add(permission); 
  40.         // Check for Rationale Option 
  41.         if (!shouldShowRequestPermissionRationale(permission)) 
  42.             return false
  43.     } 
  44.     return true

如果所有權(quán)限被授權(quán),依然回調(diào)onRequestPermissionsResult,我用hashmap讓代碼整潔便于閱讀。

  1. @Override 
  2. public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { 
  3.     switch (requestCode) { 
  4.         case REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS: 
  5.             { 
  6.             Map<String, Integer> perms = new HashMap<String, Integer>(); 
  7.             // Initial 
  8.             perms.put(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.PERMISSION_GRANTED); 
  9.             perms.put(Manifest.permission.READ_CONTACTS, PackageManager.PERMISSION_GRANTED); 
  10.             perms.put(Manifest.permission.WRITE_CONTACTS, PackageManager.PERMISSION_GRANTED); 
  11.             // Fill with results 
  12.             for (int i = 0; i < permissions.length; i++) 
  13.                 perms.put(permissions[i], grantResults[i]); 
  14.             // Check for ACCESS_FINE_LOCATION 
  15.             if (perms.get(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED 
  16.                     && perms.get(Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED 
  17.                     && perms.get(Manifest.permission.WRITE_CONTACTS) == PackageManager.PERMISSION_GRANTED) { 
  18.                 // All Permissions Granted 
  19.                 insertDummyContact(); 
  20.             } else { 
  21.                 // Permission Denied 
  22.                 Toast.makeText(MainActivity.this"Some Permission is Denied", Toast.LENGTH_SHORT) 
  23.                         .show(); 
  24.             } 
  25.             } 
  26.             break
  27.         default
  28.             super.onRequestPermissionsResult(requestCode, permissions, grantResults); 
  29.     } 

條件靈活的,你自己設(shè)置。有的情況,一個(gè)權(quán)限沒(méi)有授權(quán),就不可用;但是也有情況,能工作,但是表現(xiàn)的是有所限制的。對(duì)于這個(gè)我不做評(píng)價(jià),你自己設(shè)計(jì)吧。

#p#

用兼容庫(kù)使代碼兼容舊版

以上代碼在android 6.0以上運(yùn)行沒(méi)問(wèn)題,但是23 api之前就不行了,因?yàn)闆](méi)有那些方法。

粗暴的方法是檢查版本

  1. if (Build.VERSION.SDK_INT >= 23) { 
  2.     // Marshmallow+ 
  3. else { 
  4.     // Pre-Marshmallow 

但是太復(fù)雜,我建議用v4兼容庫(kù),已對(duì)這個(gè)做過(guò)兼容,用這個(gè)方法代替:

  • ContextCompat.checkSelfPermission()
    被授權(quán)函數(shù)返回PERMISSION_GRANTED,否則返回PERMISSION_DENIED ,在所有版本都是如此。
  • ActivityCompat.requestPermissions()
    這個(gè)方法在M之前版本調(diào)用,OnRequestPermissionsResultCallback 直接被調(diào)用,帶著正確的 PERMISSION_GRANTED或者 PERMISSION_DENIED 。
  • ActivityCompat.shouldShowRequestPermissionRationale()
    在M之前版本調(diào)用,永遠(yuǎn)返回false。
    用v4包的這三方法,完美兼容所有版本!這個(gè)方法需要額外的參數(shù),Context or Activity。別的就沒(méi)啥特別的了。下面是代碼:
  1. private void insertDummyContactWrapper() { 
  2.     int hasWriteContactsPermission = ContextCompat.checkSelfPermission(MainActivity.this
  3.             Manifest.permission.WRITE_CONTACTS); 
  4.     if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) { 
  5.         if (!ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this
  6.                 Manifest.permission.WRITE_CONTACTS)) { 
  7.             showMessageOKCancel("You need to allow access to Contacts"
  8.                     new DialogInterface.OnClickListener() { 
  9.                         @Override 
  10.                         public void onClick(DialogInterface dialog, int which) { 
  11.                             ActivityCompat.requestPermissions(MainActivity.this
  12.                                     new String[] {Manifest.permission.WRITE_CONTACTS}, 
  13.                                     REQUEST_CODE_ASK_PERMISSIONS); 
  14.                         } 
  15.                     }); 
  16.             return
  17.         } 
  18.         ActivityCompat.requestPermissions(MainActivity.this
  19.                 new String[] {Manifest.permission.WRITE_CONTACTS}, 
  20.                 REQUEST_CODE_ASK_PERMISSIONS); 
  21.         return
  22.     } 
  23.     insertDummyContact(); 

后兩個(gè)方法,我們也可以在Fragment中使用,用v13兼容包:FragmentCompat.requestPermissions() and FragmentCompat.shouldShowRequestPermissionRationale().和activity效果一樣。

第三方庫(kù)簡(jiǎn)化代碼

以上代碼真尼瑪復(fù)雜。為解決這事,有許多第三方庫(kù)已經(jīng)問(wèn)世了,真屌真有速度。我試了很多最終找到了個(gè)滿意的hotchemi's PermissionsDispatcher。
他和我上面做的一樣,只是簡(jiǎn)化了代碼。靈活易擴(kuò)展,試一下吧。如果不滿足你可以找些其他的。

如果我的app還開(kāi)著呢,權(quán)限被撤銷(xiāo)了,會(huì)發(fā)生生么

權(quán)限隨時(shí)可以被撤銷(xiāo)。

Paste_Image.png

當(dāng)app開(kāi)著的時(shí)候被撤消了會(huì)發(fā)生什么呢?我試過(guò)了發(fā)現(xiàn)這時(shí)app會(huì)突然終止 terminated。app中的一切都被簡(jiǎn)單粗暴的停止了,因?yàn)閠erminated!對(duì)我來(lái)說(shuō)這可以理解,因?yàn)橄到y(tǒng)如果允許它繼續(xù)運(yùn)行(沒(méi)有某權(quán)限),這會(huì)召喚弗雷迪到我的噩夢(mèng)里?;蛟S更糟...

結(jié)論建議

我相信你對(duì)新權(quán)限模型已經(jīng)有了清晰的認(rèn)識(shí)。我相信你也意識(shí)到了問(wèn)題的嚴(yán)峻。

但是你沒(méi)得選擇。新運(yùn)行時(shí)權(quán)限已經(jīng)在棉花糖中被使用了。我們沒(méi)有退路。我們現(xiàn)在唯一能做的就是保證app適配新權(quán)限模型.

欣慰的是只有少數(shù)權(quán)限需要運(yùn)行時(shí)權(quán)限模型。大多數(shù)常用的權(quán)限,例如,網(wǎng)絡(luò)訪問(wèn),屬于Normal Permission 在安裝時(shí)自動(dòng)會(huì)授權(quán),當(dāng)然你要聲明,以后無(wú)需檢查。因此,只有少部分代碼你需要修改。

兩個(gè)建議:

1.嚴(yán)肅對(duì)待新權(quán)限模型

2.如果你代碼沒(méi)支持新權(quán)限,不要設(shè)置targetSdkVersion 23 。尤其是當(dāng)你在Studio新建工程時(shí),不要忘了修改!

說(shuō)一下代碼修改。這是大事,如果代碼結(jié)構(gòu)被設(shè)計(jì)的不夠好,你需要一些很蛋疼的重構(gòu)。每個(gè)app都要被修正。如上所說(shuō),我們沒(méi)的選擇。。。

列出所有你需要請(qǐng)求的權(quán)限所有情形,如果A被授權(quán),B被拒絕,會(huì)發(fā)生什么。blah,blah。

祝重構(gòu)順利。把它列為你需要做的大事,從現(xiàn)在就開(kāi)始著手做,以保證M正式發(fā)布的時(shí)候沒(méi)有問(wèn)題。

希望本文對(duì)你有用,快樂(lè)編碼!艸

責(zé)任編輯:倪明 來(lái)源: 簡(jiǎn)書(shū)翻譯
相關(guān)推薦

2015-09-18 08:41:12

androidM權(quán)限

2023-02-10 08:44:05

KafkaLinkedIn模式

2018-06-15 23:00:56

2022-07-15 14:58:26

數(shù)據(jù)分析人工智能IT

2022-04-24 09:00:00

滲透測(cè)試安全數(shù)字時(shí)代

2021-12-29 14:24:12

物聯(lián)網(wǎng)IoT5G

2022-12-30 11:24:21

2019-05-24 08:54:13

2023-09-11 07:36:35

2022-07-06 10:07:21

物聯(lián)網(wǎng)IoT

2022-09-01 15:26:45

物聯(lián)網(wǎng)人工智能傳感器

2020-11-17 10:38:40

云計(jì)算工具技術(shù)

2023-02-27 15:47:31

2023-10-12 07:06:32

2023-10-12 09:42:44

2022-08-27 12:15:51

Linux Mint操作系統(tǒng)

2014-07-17 09:31:50

iOS8SDK

2020-12-22 11:04:05

人工智能AI機(jī)器學(xué)習(xí)

2023-04-03 14:24:46

2022-07-19 14:39:12

云安全云計(jì)算漏洞
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)