Android 6.0 引入了運行時權限。就是權限是在程序運行的時候賦予的,而不是安裝的時候賦予的。6.0以前權限的賦予都是在安裝的時候列出一堆權限,而後用戶點擊肯定後賦予的。下面對比圖,有種你敢看。android
Android L.pngshell
Android M.png數據庫
今天來講下6.0權限賦予的一個過程吧,先不上代碼,先用天然語言說一下。
1.並非全部權限都要運行時才申請的。有些是安裝的時候天然就給你的,安裝時候自動給你的都是一些小權限啦,沒啥危險的。執行 adb shell pm dump com.example.rubbishdemo |find "permission" 能夠看到有哪些權限是這個com.example.rubbishdemo安裝的時候就被賦予的。這個能夠叫作「安裝時權限」,哈哈,名字是我亂起的。數據結構
Paste_Image.pngide
2.運行時權限的賦予是給整個權限組賦予權限,啥意思啊,是這樣的,Android裏面的權限都是分組的,便於管理,例如寫sd卡,和讀sd卡就是同一個權限組android.permission-group.STORAGE的。這些在frameworks/base/core/res/AndroidManifest.xml中定義this
權限組定義.pngspa
權限組下的兩個權限.pngcode
3.權限賦予後,會記錄到設置數據庫中。於是重啓也不會失效。xml
下面就進入代碼時間
首先是應用部分,在onCreate裏面申請發送信息的權限SEND_SMS。ci
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); this.requestPermissions( new String[]{Manifest.permission.SEND_SMS}, 2); }
AndroidManifest定義要獲取的權限
<uses-permission android:name="android.permission.SEND_SMS" />
上節咱們說到運行時權限那個彈框是有應用安裝器彈出的,所在的Activity是GrantPermissionsActivity。因此,過一下這個Activity的代碼。
public void onCreate(Bundle icicle) { super.onCreate(icicle); //mRequestedPermissions是要獲取的權限,這裏要獲取的是android.permission.SEND_SMS mRequestedPermissions = getIntent().getStringArrayExtra( PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES); if (mRequestedPermissions == null) { mRequestedPermissions = new String[0]; } final int requestedPermCount = mRequestedPermissions.length; mGrantResults = new int[requestedPermCount]; //用來保存權限獲取結果 //要獲取權限的應用的包名 PackageInfo callingPackageInfo = getCallingPackageInfo(); //設備管理器 DevicePolicyManager devicePolicyManager = getSystemService(DevicePolicyManager.class); //權限策略 final int permissionPolicy = devicePolicyManager.getPermissionPolicy(null); //獲取應用中全部的權限,這個返回值是AndroidManifest裏面定義的全部權限,本例子就是下面一個,only one /* <uses-permission android:name="android.permission.SEND_SMS" /> */ //把這些權限保存到一個數據結構AppPermissions中去 mAppPermissions = new AppPermissions(this, callingPackageInfo, null, false, new Runnable() { @Override public void run() { setResultAndFinish(); } }); for (AppPermissionGroup group : mAppPermissions.getPermissionGroups()) { //遍歷應用的權限組groud boolean groupHasRequestedPermission = false; for (String requestedPermission : mRequestedPermissions) { if (group.hasPermission(requestedPermission)) { //權限組已經有權限了,就不用再次賦予權限了 groupHasRequestedPermission = true; break; } } if (!groupHasRequestedPermission) { continue; } // We allow the user to choose only non-fixed permissions. A permission // is fixed either by device policy or the user denying with prejudice. //根據權限策略賦予權限,正常這兩個策略不知足 if (!group.isUserFixed() && !group.isPolicyFixed()) { switch (permissionPolicy) { case DevicePolicyManager.PERMISSION_POLICY_AUTO_GRANT: { if (!group.areRuntimePermissionsGranted()) { group.grantRuntimePermissions(false); } group.setPolicyFixed(); } break; case DevicePolicyManager.PERMISSION_POLICY_AUTO_DENY: { if (group.areRuntimePermissionsGranted()) { group.revokeRuntimePermissions(false); } group.setPolicyFixed(); } break; default: { if (!group.areRuntimePermissionsGranted()) { //把要申請權限的權限組groud放在數據結構mRequestGrantPermissionGroups mRequestGrantPermissionGroups.put(group.getName(), new GroupState(group)); } else { group.grantRuntimePermissions(false); updateGrantResults(group); } } break; } } else { // if the permission is fixed, ensure that we return the right request result updateGrantResults(group); } } //彈出彈框 mViewHandler = new GrantPermissionsDefaultViewHandler(this).setResultListener(this); setContentView(mViewHandler.createView()); }
先看一下上面的註釋,大概步驟是
1.獲取APK AndroidManifest中定義的全部權限,並保存在結構AppPermissions。
本例子只定義了一個權限android.permission.SEND_SMS,因此AppPermissions結構中只包含一個Permission,若是定義了多個Permission,則AppPermissions結構中包含多個Permission。
2.獲取APK的權限組AppPermissionGroup ,本例子只定義了一個權限,因此權限組也只有一個。android.permission.SEND_SMS所在的權限組是android.permission-group.SMS。
3.查看要獲取的權限所在的權限組是否以前已經獲取到權限,若是已經獲取到,再也不獲取。直接結束,不然會彈個框,嚇嚇你。
4.彈框經過GrantPermissionsDefaultViewHandler建立。
彈框嚇嚇你.png
下面進入GrantPermissionsDefaultViewHandler看看
//建立了彈框,只關注贊成按鈕 public View createView() { mAllowButton = (Button) mRootView.findViewById(R.id.permission_allow_button); mDenyButton = (Button) mRootView.findViewById(R.id.permission_deny_button); return mRootView; } //看點擊容許是怎麼處理 public void onClick(View view) { switch (view.getId()) { case R.id.permission_allow_button: if (mResultListener != null) { view.clearAccessibilityFocus(); mResultListener.onPermissionGrantResult(mGroupName, true, false); //這裏的mResultListener就是GrantPermissionsActivity } break; } } //GrantPermissionsActivity中 public void onPermissionGrantResult(String name, boolean granted, boolean doNotAskAgain) { GroupState groupState = mRequestGrantPermissionGroups.get(name); if (groupState.mGroup != null) { if (granted) { groupState.mGroup.grantRuntimePermissions(doNotAskAgain); //這裏會往設置數據庫寫一個值,完成權限賦予 groupState.mState = GroupState.STATE_ALLOWED; } }
能夠看到,步驟也很簡單
1.彈框建立了容許與拒絕的按鈕,給按鈕設置監聽。
2.按下容許按鍵後,會給權限組賦予權限,最後調用PackageManagerService系統服務將結果寫入設置數據庫。groupState.mGroup就是權限組。
1.6.0的權限賦予是給整個權限組賦予權限。
2.權限賦予的入口是應用安裝器。
3.有些權限是安裝時賦予的,是沒啥危險的權限。危險的權限經過運行時賦予。至於危險的定義也在frameworks/base/core/res/AndroidManifest.xml中,截個圖你看
危險.png
不危險.png
做者:九九叔 連接:https://www.jianshu.com/p/d31ea81f75a3 來源:簡書 著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。