Android 6.0 權限管理


Android 6.0 權限管理

運行時權限(Runtime permission)

android的權限系統一直是首要的安全概念,因為這些權限只在安裝的時候被詢問一次。一旦安裝了,app可以在用戶毫不知曉的情況下訪問權限內的所有東西。
這是極其危險的事情
所以,在Android M 權限請求設計改版了,有點類似iOS的權限請求

權限請求對比

1461651981945.jpg

在android6.0棉花糖,app將不會在安裝的時候授予權限。取而代之的是,app不得不在運行時一個一個詢問用戶授予權限。

注意權限詢問對話框不會自己彈出來。開發者不得不自己調用。如果開發者要調用的一些函數需要某權限而用戶又拒絕授權的話,函數將拋出異常甚至導致程序崩潰.

舊版兼容

為了與舊版本兼容,比如你的 build.gradle 中的 targetSdkVersion 設置為 23 之前,比如22.
也能在Android6.0 的手機上面跑,並且權限請求機制使用6.0之前的 安裝時請求 的模式.
吐槽一下: Excuse Me? 這到底是兼容還是漏洞... targetSdkVersion 設置為23以前,不讓跑6.0不是更合理?
可能處於市場應用的API版本考慮,不兼容估計大部分應用都不能跑6.0
所以,如果你覺得運行時彈出權限框讓用戶勾選很不友好,那么就取巧使用targetSdkVersion <23 吧,但這絕對不是長久之計...(丑陋...)

  1. android { 
  2. compileSdkVersion 23 
  3. buildToolsVersion "23.0.2" 
  4.  
  5. defaultConfig { 
  6. minSdkVersion 8 
  7. targetSdkVersion 22 
  8. versionCode 1 
  9. versionName "1.0" 

  10. buildTypes { 
  11. release { 
  12. minifyEnabled false 
  13. proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 



enter description here

1461662965441.jpg

6.0權限彈框的兩種模式

1.初次請求,彈出對話框叫你勾選

enter description here

1461654947945.jpg

2,第二次請求之后,彈出對話框,出現不再提醒字樣

enter description here

1461655014689.jpg

當用戶點擊了不再提醒,你再次請求權限的時候,就不會彈出對話框,所以這時,你需要根據需求另做處理
下面會如何處理

6.0之后的權限分類

分為兩類 Normal permissionsDangerous permissions

Normal permissions(普通權限)

只需要在xml中申請就可以了,與6.0之前沒什么區別
包括的權限有

  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 

其實不需要記,記住哪些是危險權限就是了

Dangerous permissions(危險權限)

危險權限,需要在運行時請求.
注意: 危險權限是按組來分的,所以,當你申請了多個同組的危險權限時,運行時只需要申請一個就行
例如:

  1. <!-- 電話 --> 
  2. <uses-permission android:name="android.permission.READ_CALL_LOG" /> 
  3. <uses-permission android:name="android.permission.READ_PHONE_STATE" /> 
  4. <uses-permission android:name="android.permission.CALL_PHONE" /> 
  5. <uses-permission android:name="android.permission.WRITE_CALL_LOG" /> 
  6. <uses-permission android:name="android.permission.USE_SIP" /> 
  7. <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" /> 
  8. <uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" /> 

你申請了關於電話的那么多權限,在動態申請的時候,它只會彈出

enter description here

1461654947945.jpg

這一個權限框
所以,這是一個權限組的概念,運行時選擇你申請的同組權限的一個就行

目前所有的危險權限組集合

  1. <!-- Dangerous Permissions. --> 
  2. <!-- 聯系人 --> 
  3. <uses-permission android:name="android.permission.WRITE_CONTACTS" /> 
  4. <uses-permission android:name="android.permission.GET_ACCOUNTS" /> 
  5. <uses-permission android:name="android.permission.READ_CONTACTS" /> 
  6.  
  7. <!-- 錄音 --> 
  8. <uses-permission android:name="android.permission.RECORD_AUDIO" /> 
  9.  
  10. <!-- 電話 --> 
  11. <uses-permission android:name="android.permission.READ_CALL_LOG" /> 
  12. <uses-permission android:name="android.permission.READ_PHONE_STATE" /> 
  13. <uses-permission android:name="android.permission.CALL_PHONE" /> 
  14. <uses-permission android:name="android.permission.WRITE_CALL_LOG" /> 
  15. <uses-permission android:name="android.permission.USE_SIP" /> 
  16. <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" /> 
  17. <uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" /> 
  18.  
  19. <!-- 日歷 --> 
  20. <uses-permission android:name="android.permission.READ_CALENDAR" /> 
  21. <uses-permission android:name="android.permission.WRITE_CALENDAR" /> 
  22.  
  23. <!-- 相機 --> 
  24. <uses-permission android:name="android.permission.CAMERA" /> 
  25.  
  26. <!-- 傳感器 --> 
  27. <uses-permission android:name="android.permission.BODY_SENSORS" /> 
  28.  
  29. <!-- 定位 --> 
  30. <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> 
  31. <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> 
  32.  
  33. <!-- 存儲 --> 
  34. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 
  35. <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> 
  36.  
  37. <!-- 短信 --> 
  38. <uses-permission android:name="android.permission.READ_SMS" /> 
  39. <uses-permission android:name="android.permission.RECEIVE_WAP_PUSH" /> 
  40. <uses-permission android:name="android.permission.RECEIVE_MMS" /> 
  41. <uses-permission android:name="android.permission.RECEIVE_SMS" /> 
  42. <uses-permission android:name="android.permission.SEND_SMS" /> 

對應的java code

  1. // 聯系人 
  2. Manifest.permission.WRITE_CONTACTS, 
  3. Manifest.permission.GET_ACCOUNTS, 
  4. Manifest.permission.READ_CONTACTS, 
  5.  
  6. // 電話 
  7. Manifest.permission.READ_CALL_LOG, 
  8. Manifest.permission.READ_PHONE_STATE, 
  9. Manifest.permission.CALL_PHONE, 
  10. Manifest.permission.WRITE_CALL_LOG, 
  11. Manifest.permission.USE_SIP, 
  12. Manifest.permission.PROCESS_OUTGOING_CALLS, 
  13. Manifest.permission.ADD_VOICEMAIL, 
  14.  
  15. // 日歷 
  16. Manifest.permission.READ_CALENDAR, 
  17. Manifest.permission.WRITE_CALENDAR, 
  18.  
  19. // 相機 
  20. Manifest.permission.CAMERA, 
  21.  
  22. // 傳感器 
  23. Manifest.permission.BODY_SENSORS, 
  24.  
  25. // 定位 
  26. Manifest.permission.ACCESS_FINE_LOCATION, 
  27. Manifest.permission.ACCESS_COARSE_LOCATION, 
  28.  
  29. // 存儲 
  30. Manifest.permission.READ_EXTERNAL_STORAGE, 
  31. Manifest.permission.WRITE_EXTERNAL_STORAGE, 
  32.  
  33. // 錄音 
  34. Manifest.permission.RECORD_AUDIO, 
  35.  
  36. // 短信 
  37. Manifest.permission.READ_SMS, 
  38. Manifest.permission.RECEIVE_WAP_PUSH, 
  39. Manifest.permission.RECEIVE_MMS, 
  40. Manifest.permission.RECEIVE_SMS, 
  41. Manifest.permission.SEND_SMS, 

運行時權限請求的基本步驟

1.在xml中注冊
2. 運行時請求權限

以下是權限檢查的幫助類

  1. /** 
  2. * 檢查權限是否已請求到 (6.0) 
  3. */ 
  4. public void checkPermissions(String... permissions)
  5. // 版本兼容 
  6. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M 
  7. // 判斷缺失哪些必要權限 
  8. && lacksPermissions(permissions)) { 
  9. // 如果缺失,則申請 
  10. requestPermissions(permissions); 


  11.  
  12. /** 
  13. * 判斷是否缺失權限集合中的權限 
  14. */ 
  15. private boolean lacksPermissions(String... permissions)
  16. for (String permission : permissions) { 
  17. if (lacksPermission(permission)) { 
  18. return true


  19. return false

  20.  
  21. /** 
  22. * 判斷是否缺少某個權限 
  23. */ 
  24. private boolean lacksPermission(String permission)
  25. return ContextCompat.checkSelfPermission(context, permission) == 
  26. PackageManager.PERMISSION_DENIED; 

  27.  
  28. /** 
  29. * 請求權限 
  30. */ 
  31. private void requestPermissions(String... permissions)
  32. ActivityCompat.requestPermissions(context, permissions, PERMISSION_REQUEST_CODE); 

  33.  
  34. /** 
  35. * 啟動應用的設置,進入手動配置權限頁面 
  36. */ 
  37. private void startAppSettings()
  38. Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); 
  39. Uri uri = Uri.fromParts("package", context.getPackageName(), null); 
  40. intent.setData(uri); 
  41. context.startActivity(intent); 

注意: 其中的 requestPermissions 方法,它會彈出權限提示框( 沒有點擊不再提醒的話 ),然后調用 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) 方法,該方法在Activity或者Fragment中回調

3.在onRequestPermissionsResult回調中處理

public void onRequestPermissionsResult() 方法中,你可以捕獲到用於是點擊了 不再提醒 還是 拒絕 ,然后做出不同的操作..

  1. @Override 
  2. public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
  3. // 版本兼容 
  4. if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M || 
  5. requestCode != PermissionsChecker.PERMISSION_REQUEST_CODE) 
  6. return
  7.  
  8. for (int i = 0, len = permissions.length; i < len; i++) { 
  9. String permission = permissions[i]; 
  10. // 缺失的權限 
  11. if (grantResults[i] == PackageManager.PERMISSION_DENIED) { 
  12. boolean showRationale = shouldShowRequestPermissionRationale(permission); 
  13. if (!showRationale) { 
  14. // 用戶點擊不再提醒 
  15. // TODO 
  16. break
  17. } else {  
  18. // 用戶點擊了取消... 
  19. // possibly check more permissions...  




權限請求策略

下面提供一種我認為還不錯的策略
在需要某權限的Activity的 onStrart() 中去請求權限
onRequestPermissionsResult 回調中,如果用戶點擊了拒絕,則繼續請求權限
如果用戶點擊了不再提醒,則彈出自定義對話框,引導用戶手動去開啟權限,如果用戶不授權,則退出當前頁面
注意:適用於沒有權限就無法使用該功能的情況

enter description here

1461661615410.jpg

Activity代碼

  1. public class BaseActivity extends AppCompatActivity
  2. private static final String TAG = "BaseActivity"
  3. private PermissionsChecker checker; 
  4.  
  5. @Override 
  6. protected void onCreate(@Nullable Bundle savedInstanceState)
  7. super.onCreate(savedInstanceState); 
  8. checker = new PermissionsChecker(this); 

  9.  
  10. public PermissionsChecker getChecker()
  11. return checker; 

  12.  
  13. /** 
  14. * 在該聲明周期,檢查權限申請情況 
  15. */ 
  16. @Override 
  17. protected void onStart()
  18. super.onStart(); 
  19. checker.checkPermissions(PermissionsChecker.PERMISSIONS); 

  20.  
  21. /** 
  22. * 請求權限檢查完后回調的結果 
  23. * 
  24. * @param requestCode . 
  25. * @param permissions 所請求的權限 
  26. * @param grantResults . 
  27. */ 
  28. @TargetApi(Build.VERSION_CODES.M) 
  29. @Override 
  30. public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
  31. if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || 
  32. requestCode != PermissionsChecker.PERMISSION_REQUEST_CODE) 
  33. return
  34.  
  35.  
  36. for (int i = 0, len = permissions.length; i < len; i++) { 
  37. String permission = permissions[i]; 
  38. if (grantResults[i] == PackageManager.PERMISSION_DENIED) { 
  39. boolean showRationale = shouldShowRequestPermissionRationale(permission); 
  40. if (!showRationale) { 
  41. // 用戶點擊不再提醒,彈出權限框,引導其手動開啟權限 
  42. checker.showMissingPermissionDialog(); 
  43. break
  44. } else
  45. // 用戶點擊取消,繼續提示 
  46. checker.checkPermissions(PermissionsChecker.PERMISSIONS); 
  47. break





  48.  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM