用 RxPermissions 處理 Android 6.0 Permission

Android 6(API level 23) 之後,開發者會被要求者處理 APP 權限問題(針對 Run),程式碼要撰寫相關邏輯:檢查有沒有權限、處理取得權限後的行為...等。官方範例碼大概就是畫面跳轉類似用 Listener Pattern 的方式來處理,另外還要處理當使用者選取"不要再跳出權限對話框"的特殊狀況。總覺得應該就是一個 yes 或 no 就該解決的事情,但每次寫出來都不一樣,各別提不同人寫出來的流程都是天差地遠了。
這次改用 RxPermissions 來重寫,RxPermissions 封裝邏輯後寫出來的程式碼順序很直覺:

  • 路徑1:要求權限 > 都有權限 > 執行需要權限的程式碼。
  • 路徑2:要求權限 > 有權限被拒絕會自動跳出對話框 > 還是有權限被拒絕(對話框沒勾選不再詢問) > 再重新要求權限 或 執行當沒有權限還是可以執行的程式碼。
  • 路徑3:要求權限 > 有權限被拒絕而且曾在對話框勾選不再訊問 > 提示有用訊息並引導使用者到設定頁面打開權限 > onActivityResult 處理設定頁面跳轉回來的事件再重新要求權限。
廢話不多說,上扣!
public class FooActivity extends AppCompatActivity
{
private static final String TAG = FooActivity.class.getSimpleName();
private static final int REQUEST_PERMISSION_SETTING = 109;
@Override
protected void onCreate(Bundle savedInstanceState)
{
// 省略...
// 每次建立都會要求取得權限。
requestPermissions();
}
private void requestPermissions()
{
RxPermissions rxPermission = new RxPermissions(FooActivity.this);
rxPermission
.requestEachCombined(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO) // 加入你需要的 Runtime 權限。如果沒權限會自動跳出要求權限的對話框。
.subscribe(new Consumer < Permission > () // 只會發射一次結果。
{
@Override
public void accept(Permission permission) throws Exception
{
if (permission.granted)
{
Log.d(TAG, "Path 1: 取得所有權限");
// 確定有權限之後就可以執行需要權限的方法。
doSomeThing();
}
else if (permission.shouldShowRequestPermissionRationale)
{
Log.d(TAG, "Path 2: 其中一個權限被拒絕(沒有勾選不再詢問)");
// 重新要求取得權限。
requestPermissions();
}
else
{
Log.d(TAG, "Path 3: 其中一個權限被拒絕(曾經在對話框勾選不再詢問)");
// 被勾選不再詢問就不會跳出要求權限的對話框,這邊要引導至設定頁面請使用者手動打開權限。
// 如果流程不想哪麼粗糙,也可以自己做一個對話框顯示詳細資訊,並提供一個按鈕跳到設定頁面。
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
startActivityForResult(intent, REQUEST_PERMISSION_SETTING);
}
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
// Path 3.1: 處理設定頁面跳轉回來的流程,這就就是再檢查一次權限。
if (requestCode == REQUEST_PERMISSION_SETTING)
{
// 重新要求取得權限。
requestPermissions();
}
}
}