Android Runtime Permissions 設計
Android 6.0 (API Level 23) 開始引入了 Runtime Permissions,過去用戶在安裝程式時需要一次接受所有權限請求,而 Runtime Permissions 可交由用戶自行判斷接受哪些權限。

前提
今次教學會以「自由香港楷書」Android 應用程式作例子,自由香港楷書在 0.1.6 版本新增截圖分享功能,由於需要寫入圖片到外部空間作傳送圖片之用,因此加入了「android.permission.WRITE_EXTERNAL_STORAGE」權限。
應用程式下載:
https://play.google.com/store/apps/details?id=hk.collaction.freehkkai
完整 0.1.6 版本的 GitHub 原始碼:
https://github.com/collaction/freehkkai-android/tree/0.1.6
快速教學
不論你的程式有否支援 API Level 22 或以下的 Android 版本,你還是要在 Android Manifest.xml 聲明權限使用:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>在 MainFragment.java import 以下 Class 及定義一個 final String:
import android.support.v4.content.ContextCompat;
import android.content.pm.PackageManager;public class MainFragment extends BaseFragment {protected final String PERMISSION_NAME = Manifest.permission.WRITE_EXTERNAL_STORAGE;}
接著當用戶按下「分享截圖」按鈕時,會執行onClickScreenCap(),檢查是否已被授權相關權限:
if (ContextCompat.checkSelfPermission(mContext, PERMISSION_NAME) == PackageManager.PERMISSION_GRANTED) {
// 已得到授權
} else {
// 沒有授權
// 或曾請求用戶授權,但被拒絕
// 或用戶在系統設定中禁用授權
}當沒有授權時,你需要調用:
requestPermissions(new String[] { PERMISSION_NAME }, REQUEST_PERMISSION);假使你需要同時取得多個權限授權,你可以在 new String[] 加入權限名稱:
requestPermissions(new String[] { PERMISSION_NAME_1, PERMISSION_NAME_2, PERMISSION_NAME_3 }, REQUEST_PERMISSION);系統會 Dialog 詢問用戶是否需要授權程式,不論按下是否皆會調用 onRequestPermissionsResult(),取得授權後可以再次執行onClickScreenCap()。
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == PERMISSION_REQUEST_CODE) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
onClickScreenCap()
} else {
// 彈出請求
}
}
}
() 的請求一旦用戶在 Dialog 選擇了拒絕,往後的 Dialog 也會出現「不再詢問」的選項,有趣的是當用戶選擇了允許,「不再詢問」會被隱藏。
但是要注意當用戶點選「不再詢問」並拒絕授權,不論任何情況都會假定用戶是拒絕授權,因此你可以彈出自定的 Dialog,提醒用戶需要授權才能使用相關功能。

如果剛才你同時提交多個授權檢查,只要檢查grantResults每個 value 是否PackageManager.PERMISSION_GRANTED便可以。
小結
不是所有 Permissions 需要用戶授權的,Android 把權限分為 Normal and Dangerous Permissions,只有 Dangerous Permissions 才需要調用 requestPermissions()。
你在 Android Studio 建立項目時,現在的 targetSdkVersion 會自動設置為 23+。如果你還未支援新的 Runtime Permissions 時,建議你先把targetSdkVersion 降級到 22。
有關哪些是 Dangerous Permissions,請到:
https://developer.android.com/guide/topics/permissions/requesting.html

