關於解決的方法在Android官方網站很早就有列出如何透過程式的方法重新取得使用者的授權,只是因為一直沒有遇到需求,所以才會到現在才處理Android 6.0的權限部份。
整個開發的設計流程為:
a.透過程式的方法要求所須的權限
b.取得權限成功與失敗的結果
c.如果使用者提供授權就執行該功能(本例為playMusic())
d.如果使用者取消授權就跳出對話框再次詢問(告知為何需要使用者的權限)
e.如果使用者依然拒絕提供授權就不執行該功能
以下是開發實作的過程:
1.製作取得權限的公用函式
/**
* 取得權限(for Android 6.0)
*
* @param activity
* @param permission
* @param permissionCode
*/
public static void getPermission(Activity activity, String permission, int permissionCode) {
if (ContextCompat.checkSelfPermission(activity.getApplicationContext(), permission)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(activity, new String[]{permission}, permissionCode);
}
}
直接將取得授權寫成一個公用函式的好處,在於可以在不同的頁面隨時都能夠傳入不同的權限參數,就可以觸發取得所屬權限的功能,而且也可以在呼叫程式碼的時候變得簡潔。而其中第一個參數: Activtiy,如果是在Fragment的時候也可以傳入getActivity(),一樣可以使用這個函式。2.設定權限的requestCode:
自訂的requestCode來做為判斷要求的各個不同的權限,在下一步驟將會使用到。
假設將取得寫入磁碟空間的requestCode設定為0
private final int PERMISSION_WRITE_STORAGE = 0;而設定的requestCode必須在0~255之間,不然就會得到下列的錯誤:
java.lang.IllegalArgumentException: Can only use lower 8 bits for requestCode
3.取得要求權限所回傳結果:
要求權限之後會有一個用來處理回傳結果的的callback: onRequestPermissionsResult,所以要把取得權限成功與失敗的結果寫下後續要處理的事情。而在這邊透過取得的grantResults array來做為判斷是否有取得權限的方法。
Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { switch (requestCode) { case PERMISSION_WRITE_STORAGE: // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { /*get permission success*/ playMusic(); //執行播放音樂的方法 } else { /*get permission fail*/ showDialog("請提供授權", "聽音樂需要存放檔案的權限才能順利播放", "重新提供", getPermissionListener, "不要提供", closeActivityListener); } break; default: break; } }
4.其他搭配使用的公用函式
/**
* 產生對話框(具有兩個選項按鈕)
*
* @param title 標題
* @param message 文字
* @param confirm1 確定文字1
* @param listener1 按鈕監聽1
* @param confirm2 確定文字2
* @param listener2 按鈕監聽2
*/
public static void showDialog(String title, String message,
String confirm1, DialogInterface.OnClickListener listener1,
String confirm2, DialogInterface.OnClickListener listener2) {
AlertDialog.Builder dialog = new AlertDialog.Builder(this);
dialog.setTitle(title).setMessage(message)
.setPositiveButton(confirm1, listener1)
.setNegativeButton(confirm2, listener2)
.show();
}
/** * 對話框按鈕監聽(重開權限) */ private DialogInterface.OnClickListener getPermissionListener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //取得檔案寫入的權限 ValueUtility.getPermission(MyActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE, PERMISSION_WRITE_STORAGE); } };
/**
* 對話框按鈕監聽(離開)
*/
private DialogInterface.OnClickListener closeActivityListener =
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText((MyActivity.this, "無法播放音樂", Toast.LENGTH_SHORT).show();
}
};
基本上在Activity就如同上述的方式就能夠執行成功了,但如果是在Fragment呼叫要求權限(requestPermissions)之後,或許會發現在Fragment裡的onRequestPermissionsResult沒有反應,於是就造成沒辦法實作取得授權之後的功能(雖然有看到網路上有人提到這是bug,似乎會在Android Support Library 23.3.0修復),而目前就先使用撰寫Interface在Activity實作的方式來解決。
1.新增一個用來接收取得權限之後的interface
public interface PermissionCallback {
void getPermission(); //通知取得權限後要執行的方法
}
2.在Fragment產生Interface的reference
public class MyFragment extends Fragment{ public PermissionCallback permissionCallback; @Override public void onAttach(Activity activity) { super.onAttach(activity); try { permissionCallback = (PermissionCallback) activity; //產生Callback的reference } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement onViewSelected"); } } }
3.在Fragment使用Interface裡的函式觸發
permissionCallback.getPermission();
4.在Activity實作功能
public class MyActivity extends FragmentActivity implements PermissionCallback{ private MyFragment myFragment; //想要取得權限的fragment @Override protected void onCreate(Bundle savedInstanceState) { myFragment = new MyFragment(); //產生myFragment實體 //將Fragment加入此Activity getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, myFragment).commit(); } @Override public void getPermission() { //在Callback function裡執行要求權限 ValueUtility.getPermission(MyActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE, PERMISSION_WRITE_STORAGE); } }
5.取得要求權限所回傳結果
在MyActivity裡執行Override Method: onRequestPermissionsResult()
@Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { switch (requestCode) { case PERMISSION_WRITE_STORAGE: // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { /*get permission success*/ myFragment.playMusic(); //執行在myFragment裡的playMusic方法 } else { /*get permission fail*/ showDialog("請提供授權", "聽音樂需要存放檔案的權限才能順利播放", "重新提供", getPermissionListener, "不要提供", closeActivityListener); } break; default: break; } }
Reference:
http://developer.android.com/intl/zh-tw/training/permissions/requesting.html
http://stackoverflow.com/questions/33331073/android-what-to-choose-for-requestcode-values
http://stackoverflow.com/questions/33169455/onrequestpermissionsresult-not-being-called-in-dialog-fragment
沒有留言:
張貼留言