權(quán)限分為幾個保護級別芋齿。保護級別影響著是否需要運行時權(quán)限請求腥寇。
有三種保護級別會影響第三方應(yīng)用:普通、簽名和危險權(quán)限觅捆。如需查看特定權(quán)限所擁有的保護級別赦役,請訪問權(quán)限 API 參考頁面。
普通權(quán)限
普通權(quán)限涵蓋以下情況:應(yīng)用需要訪問其沙盒外部的數(shù)據(jù)或資源栅炒,但對用戶隱私或其他應(yīng)用的操作帶來的風(fēng)險很小掂摔。例如,設(shè)置時區(qū)的權(quán)限就是普通權(quán)限赢赊。
如果應(yīng)用在清單中聲明需要普通權(quán)限乙漓,系統(tǒng)會在安裝時自動向應(yīng)用授予該權(quán)限。系統(tǒng)不會提示用戶授予普通權(quán)限释移,用戶也無法撤消這些權(quán)限簇秒。
簽名權(quán)限
系統(tǒng)在安裝時授予這些應(yīng)用權(quán)限,但僅會在嘗試使用某權(quán)限的應(yīng)用簽名證書為定義該權(quán)限的同一證書時才會授予秀鞭。
注意:有些簽名權(quán)限不適合第三方應(yīng)用使用趋观。
危險權(quán)限
危險權(quán)限涵蓋以下情況:應(yīng)用需要的數(shù)據(jù)或資源涉及用戶隱私信息,或者可能對用戶存儲的數(shù)據(jù)或其他應(yīng)用的操作產(chǎn)生影響锋边。例如皱坛,能夠讀取用戶的聯(lián)系人屬于危險權(quán)限。如果應(yīng)用聲明其需要危險權(quán)限豆巨,必須由用戶向應(yīng)用明確授予該權(quán)限剩辟。在用戶批準該權(quán)限之前,應(yīng)用無法提供依賴于該權(quán)限的功能往扔。
為了使用危險權(quán)限贩猎,應(yīng)用必須在運行時提示用戶授予權(quán)限。如需詳細了解如何提示用戶萍膛,請參閱危險權(quán)限的請求提示吭服。
特殊權(quán)限
有幾項權(quán)限的行為與普通權(quán)限及危險權(quán)限都不同。[SYSTEM_ALERT_WINDOW](https://developer.android.google.cn/reference/android/Manifest.permission#SYSTEM_ALERT_WINDOW)
和 [WRITE_SETTINGS](https://developer.android.google.cn/reference/android/Manifest.permission#WRITE_SETTINGS)
特別敏感蝗罗,因此大多數(shù)應(yīng)用不應(yīng)該使用它們艇棕。
在大多數(shù)情況下蝌戒,應(yīng)用必須在清單中聲明 SYSTEM_ALERT_WINDOW
權(quán)限,并發(fā)送請求用戶授權(quán)的 intent沼琉。系統(tǒng)將向用戶顯示詳細管理屏幕北苟,以響應(yīng)該 intent。
從 Android 11(API 級別 30)開始打瘪,調(diào)用 ACTION_MANAGE_OVERLAY_PERMISSION
intent 操作的應(yīng)用不能指定軟件包友鼻。當(dāng)應(yīng)用調(diào)用包含此 intent 操作的 intent 時,必須由用戶先選擇想要授予或撤消哪些應(yīng)用的權(quán)限闺骚。此行為可以讓權(quán)限的授予更有目的性彩扔,從而達到保護用戶的目的。
如需詳細了解如何請求這些權(quán)限葛碧,請參閱 [SYSTEM_ALERT_WINDOW](https://developer.android.google.cn/reference/android/Manifest.permission#SYSTEM_ALERT_WINDOW)
和 [WRITE_SETTINGS](https://developer.android.google.cn/reference/android/Manifest.permission#WRITE_SETTINGS)
參考條目。
如需了解 Android 系統(tǒng)提供的所有權(quán)限过吻,請參閱 [Manifest.permission](https://developer.android.google.cn/reference/android/Manifest.permission)
。
權(quán)限檢測方式:
/**
* Determine whether <em>you</em> have been granted a particular permission.
*
* @param permission The name of the permission being checked.
*
* @return {@link android.content.pm.PackageManager#PERMISSION_GRANTED} if you have the
* permission, or {@link android.content.pm.PackageManager#PERMISSION_DENIED} if not.
*
* @see android.content.pm.PackageManager#checkPermission(String, String)
*/
public static int checkSelfPermission(@NonNull Context context, @NonNull String permission) {
if (permission == null) {
throw new IllegalArgumentException("permission is null");
}
return context.checkPermission(permission, android.os.Process.myPid(), Process.myUid());
}
權(quán)限獲取方式:
/**
* Requests permissions to be granted to this application. These permissions
* must be requested in your manifest, they should not be granted to your app,
* and they should have protection level {@link
* android.content.pm.PermissionInfo#PROTECTION_DANGEROUS dangerous}, regardless
* whether they are declared by the platform or a third-party app.
* <p>
* Normal permissions {@link android.content.pm.PermissionInfo#PROTECTION_NORMAL}
* are granted at install time if requested in the manifest. Signature permissions
* {@link android.content.pm.PermissionInfo#PROTECTION_SIGNATURE} are granted at
* install time if requested in the manifest and the signature of your app matches
* the signature of the app declaring the permissions.
* </p>
* <p>
* If your app does not have the requested permissions the user will be presented
* with UI for accepting them. After the user has accepted or rejected the
* requested permissions you will receive a callback reporting whether the
* permissions were granted or not. Your activity has to implement {@link
* androidx.core.app.ActivityCompat.OnRequestPermissionsResultCallback}
* and the results of permission requests will be delivered to its {@link
* androidx.core.app.ActivityCompat.OnRequestPermissionsResultCallback#onRequestPermissionsResult(
* int, String[], int[])} method.
* </p>
* <p>
* Note that requesting a permission does not guarantee it will be granted and
* your app should be able to run without having this permission.
* </p>
* <p>
* This method may start an activity allowing the user to choose which permissions
* to grant and which to reject. Hence, you should be prepared that your activity
* may be paused and resumed. Further, granting some permissions may require
* a restart of you application. In such a case, the system will recreate the
* activity stack before delivering the result to your
* {@link OnRequestPermissionsResultCallback#onRequestPermissionsResult(int, String[], int[])}.
* </p>
* <p>
* When checking whether you have a permission you should use {@link
* #checkSelfPermission(android.content.Context, String)}.
* </p>
* <p>
* Calling this API for permissions already granted to your app would show UI
* to the user to decided whether the app can still hold these permissions. This
* can be useful if the way your app uses the data guarded by the permissions
* changes significantly.
* </p>
* <p>
* You cannot request a permission if your activity sets {@link
* android.R.attr#noHistory noHistory} to <code>true</code> in the manifest
* because in this case the activity would not receive result callbacks including
* {@link OnRequestPermissionsResultCallback#onRequestPermissionsResult(int, String[], int[])}.
* </p>
* <p>
* The <a >
* RuntimePermissions</a> sample app demonstrates how to use this method to
* request permissions at run time.
* </p>
*
* @param activity The target activity.
* @param permissions The requested permissions. Must me non-null and not empty.
* @param requestCode Application specific request code to match with a result
* reported to {@link OnRequestPermissionsResultCallback#onRequestPermissionsResult(int, String[], int[])}.
* Should be >= 0.
*
* @see OnRequestPermissionsResultCallback#onRequestPermissionsResult(int, String[], int[])
* @see #checkSelfPermission(android.content.Context, String)
* @see #shouldShowRequestPermissionRationale(android.app.Activity, String)
*/
public static void requestPermissions(final @NonNull Activity activity,
final @NonNull String[] permissions, final @IntRange(from = 0) int requestCode) {
if (sDelegate != null
&& sDelegate.requestPermissions(activity, permissions, requestCode)) {
// Delegate has handled the permission request.
return;
}
if (Build.VERSION.SDK_INT >= 23) {
if (activity instanceof RequestPermissionsRequestCodeValidator) {
((RequestPermissionsRequestCodeValidator) activity)
.validateRequestPermissionsRequestCode(requestCode);
}
activity.requestPermissions(permissions, requestCode);
} else if (activity instanceof OnRequestPermissionsResultCallback) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
final int[] grantResults = new int[permissions.length];
PackageManager packageManager = activity.getPackageManager();
String packageName = activity.getPackageName();
final int permissionCount = permissions.length;
for (int i = 0; i < permissionCount; i++) {
grantResults[i] = packageManager.checkPermission(
permissions[i], packageName);
}
((OnRequestPermissionsResultCallback) activity).onRequestPermissionsResult(
requestCode, permissions, grantResults);
}
});
}
}
獲取權(quán)限時用戶拒絕如何處理:
彈出自定義提示信息框說明權(quán)限申請的用途,告知用戶拒絕權(quán)限申請的影響苗胀。
/**
* Gets whether you should show UI with rationale for requesting a permission.
* You should do this only if you do not have the permission and the context in
* which the permission is requested does not clearly communicate to the user
* what would be the benefit from granting this permission.
* <p>
* For example, if you write a camera app, requesting the camera permission
* would be expected by the user and no rationale for why it is requested is
* needed. If however, the app needs location for tagging photos then a non-tech
* savvy user may wonder how location is related to taking photos. In this case
* you may choose to show UI with rationale of requesting this permission.
* </p>
*
* @param activity The target activity.
* @param permission A permission your app wants to request.
* @return Whether you can show permission rationale UI.
*
* @see #checkSelfPermission(android.content.Context, String)
* @see #requestPermissions(android.app.Activity, String[], int)
*/
public static boolean shouldShowRequestPermissionRationale(@NonNull Activity activity,
@NonNull String permission) {
if (Build.VERSION.SDK_INT >= 23) {
return activity.shouldShowRequestPermissionRationale(permission);
}
return false;
}
權(quán)限的實際處理:
class TestPermissionActivity : AppCompatActivity() {
private val permissionList = arrayListOf(
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val requestPermissions = arrayListOf<String>()
permissionList.forEach {
if (ActivityCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED) {
requestPermissions.add(it)
}
}
if (!requestPermissions.isNullOrEmpty()) {
ActivityCompat.requestPermissions(this, requestPermissions.toTypedArray(), 1000)
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == 1000) {
for (i in permissions.indices) {
val hasPermission = grantResults[i] == PackageManager.PERMISSION_GRANTED
val toastString =
"${permissions[i]}權(quán)限獲取${if (hasPermission) "成功" else "失敗"}"
Toast.makeText(this, toastString, Toast.LENGTH_LONG).show()
if (!hasPermission) {
val canShow =
ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[i])
if (canShow) {
//自定義提示信息
AlertDialog.Builder(this).create().show()
}
}
}
}
}
}