Android 6(API level 23) 之後,開發者會被要求者處理 APP 權限問題(針對 Run),程式碼要撰寫相關邏輯:檢查有沒有權限、處理取得權限後的行為...等。官方範例碼大概就是畫面跳轉類似用 Listener Pattern 的方式來處理,另外還要處理當使用者選取"不要再跳出權限對話框"的特殊狀況。總覺得應該就是一個 yes 或 no 就該解決的事情,但每次寫出來都不一樣,各別提不同人寫出來的流程都是天差地遠了。
這次改用 RxPermissions 來重寫,RxPermissions 封裝邏輯後寫出來的程式碼順序很直覺:
- 路徑1:要求權限 > 都有權限 > 執行需要權限的程式碼。
- 路徑2:要求權限 > 有權限被拒絕會自動跳出對話框 > 還是有權限被拒絕(對話框沒勾選不再詢問) > 再重新要求權限 或 執行當沒有權限還是可以執行的程式碼。
- 路徑3:要求權限 > 有權限被拒絕而且曾在對話框勾選不再訊問 > 提示有用訊息並引導使用者到設定頁面打開權限 > onActivityResult 處理設定頁面跳轉回來的事件再重新要求權限。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} | |
} |