Những điều cần biết về Permission của Android
Với Marshmallow, một mô hình permission đã được bổ sung vào Android mà yêu cầu các Developer phải có cách tiếp cận khác để thực hiện xin cấp quyền permission trên Android. Trong bài viết này, chúng ta sẽ xem xét các cách thức để xử lý yêu cầu cấp quyền permission từ cả góc độ kỹ thuật và góc độ làm ...
Với Marshmallow, một mô hình permission đã được bổ sung vào Android mà yêu cầu các Developer phải có cách tiếp cận khác để thực hiện xin cấp quyền permission trên Android. Trong bài viết này, chúng ta sẽ xem xét các cách thức để xử lý yêu cầu cấp quyền permission từ cả góc độ kỹ thuật và góc độ làm thế nào để cung cấp một trải nghiệm người dùng mượt mà.
Mô hình Runtime Permission
Hệ thống cấp quyền permission của Android là một trong những mối quan tâm an ninh lớn nhất kể từ khi tất cả các permission được yêu cầu khi cài đặt. Sau khi cài đặt, ứng dụng sẽ có thể truy cập tất cả mọi thứ đã được cấp quyền mà không cần thêm bất kỳ sự nhìn nhận nào từ phía người dùng cho biết chính xác những gì ứng dụng được phép truy cập.
Trong Android 6.0 Marshmallow, ứng dụng sẽ không được cấp bất kỳ permission nào vào lúc cài đặt. Thay vào đó, ứng dụng sẽ yêu cầu người dùng cho phép permission vào thời điểm chạy.
Lưu ý rằng, dialog yêu cầu permission hiển thị ở trên là không chạy tự động. Developer phải tự gọi nó ra. Trong trường hợp này, developer đang cố gắng thực hiện một chức năng mà đòi hỏi phải được cung cấp một permission mà người dùng chưa cho phép, khi đó, chức năng này sẽ ném ra một Exception dẫn đến crash ứng dụng.
Ngoài ra, người dùng còn có thể thu hồi các permission bất cứ lúc nào thông qua phần Setting ứng dụng.
Các permission được cấp tự động
Có một số permission sẽ được cấp tự động vào thời điểm cài đặt và không thể thu hồi, đó là các Normal Permission (PROTECT_PERMISSION):
android.permission.ACCESS_LOCATION_EXTRA_COMMANDS android.permission.ACCESS_NETWORK_STATE android.permission.ACCESS_NOTIFICATION_POLICY android.permission.ACCESS_WIFI_STATE android.permission.ACCESS_WIMAX_STATE android.permission.BLUETOOTH android.permission.BLUETOOTH_ADMIN android.permission.BROADCAST_STICKY android.permission.CHANGE_NETWORK_STATE android.permission.CHANGE_WIFI_MULTICAST_STATE android.permission.CHANGE_WIFI_STATE android.permission.CHANGE_WIMAX_STATE android.permission.DISABLE_KEYGUARD android.permission.EXPAND_STATUS_BAR android.permission.FLASHLIGHT android.permission.GET_ACCOUNTS android.permission.GET_PACKAGE_SIZE android.permission.INTERNET android.permission.KILL_BACKGROUND_PROCESSES android.permission.MODIFY_AUDIO_SETTINGS android.permission.NFC android.permission.READ_SYNC_SETTINGS android.permission.READ_SYNC_STATS android.permission.RECEIVE_BOOT_COMPLETED android.permission.REORDER_TASKS android.permission.REQUEST_INSTALL_PACKAGES android.permission.SET_TIME_ZONE android.permission.SET_WALLPAPER android.permission.SET_WALLPAPER_HINTS android.permission.SUBSCRIBED_FEEDS_READ android.permission.TRANSMIT_IR android.permission.USE_FINGERPRINT android.permission.VIBRATE android.permission.WAKE_LOCK android.permission.WRITE_SYNC_SETTINGS com.android.alarm.permission.SET_ALARM com.android.launcher.permission.INSTALL_SHORTCUT com.android.launcher.permission.UNINSTALL_SHORTCUT
Chỉ đơn giản khai báo các quyền trên trong AndroidManifest.xml, các chức năng cần các quyền trên sẽ hoạt động tốt mà không cần thêm một sự cho phép nào từ người dùng.
Để ứng dụng hỗ trợ mô hình Runtime Permission
Để ứng dụng hỗ trợ mô hình Runtime Permission, đầu tiên, phải thiết lập compileSdkVersion và targetSdkVersion có giá trị 23.
android { compileSdkVersion 23 ... defaultConfig { ... targetSdkVersion 23 ... }
Ví dụ, ứng dụng đang được xây dựng có chức năng thao tác với danh bạ của người dùng, được thực hiện trong phương thức sau:
private void operateContact() { //insert a new contact }
Đoạn code trên cần được cung cấp permission WRITE_CONTACTS để thực hiện. Nếu phương thức trên được gọi mà không cung cấp permission thì ứng dụng sẽ bị crash.
Bước tiếp theo là thêm khai báo permission vào trong file AndroidManifest.xml tương tự như cách thức cũ.
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
Bước tiếp theo là phải tạo ra chức năng kiểm tra xem permission có được cung cấp hay không. Nếu chưa được cấp phép, một dialog sẽ được gọi ra để yêu cầu người dùng cung cấp permission này. Nếu permission đã được cấp phép, chức năng thao tác với danh bạ sẽ được thực hiện.
Các permission được phân vào các nhóm như sau:
Nếu bất kỳ một permission nào trong cùng một nhóm được cấp phép, thì các permission khác trong cùng nhóm đó cũng sẽ được cấp phép. Tức là việc cấp phép sẽ được cung cấp theo nhóm. Chẳng hạn trong ví dụ này, WRITE_CONTACTS được cấp phép, đồng nghĩa với việc READ_CONTACTS và GET_ACCOUNTS cũng được cấp phép.
Để kiểm tra và yêu cầu permission, sử dụng phương thức checkSelfPermission và requestPermissions của Activity. Các phương thức này được sử dụng từ API level 23.
final private int REQUEST_CODE_ASK_PERMISSIONS = 123; private void operateContactWrapper() { int hasWriteContactsPermission = checkSelfPermission(Manifest.permission.WRITE_CONTACTS); if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.WRITE_CONTACTS}, REQUEST_CODE_ASK_PERMISSIONS); return; } operateContact(); }
Nếu permission Contact đã được cung cấp, phương thức operateContact sẽ được gọi. Nếu không, phương thức requestPermissions sẽ được thực hiện để gọi dialog yêu cầu người dùng cung cấp permission như sau:
Khi người dùng chọn Allow hoặc Deny, phương thức onRequestPermissionsResult của Activity sẽ được gọi để trả về kết quả thông qua tham số grantResults:
@Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { switch (requestCode) { case REQUEST_CODE_ASK_PERMISSIONS: if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { // Permission Granted operateContact(); } else { // Permission Denied Toast.makeText(MainActivity.this, "WRITE_CONTACTS Denied", Toast.LENGTH_SHORT).show(); } break; default: super.onRequestPermissionsResult(requestCode, permissions, grantResults); } }
Xử lý "Never Ask Again"
Nếu người dùng từ chối cấp một permission và ngăn chặn ứng dụng xin quyền tiếp trong tương lai, thì sẽ lựa chọn "Never Ask Again".
Nếu tuỳ chọn "Never Ask Again" được người dùng lựa chọn trước khi từ chối cấp quyền, thì lần tiếp theo gọi phương thức requestPermissions, dialog yêu cầu cung cấp permission sẽ không được hiển thị ra nữa, và sẽ không có gì được thực hiện.
Việc người dùng thực hiện một hành động nhưng không có gì tương tác trở lại là một điều không tốt trong trải nghiệm người dùng. Vì vậy, trước khi gọi phương thức requestPermissions, cần phải giải thích tới người dùng lý do ứng dụng cần permission thông qua phương thức shouldShowRequestPermissionRationale của Activity.
final private int REQUEST_CODE_ASK_PERMISSIONS = 123; private void operateContactWrapper() { int hasWriteContactsPermission = checkSelfPermission(Manifest.permission.WRITE_CONTACTS); if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) { if (!shouldShowRequestPermissionRationale(Manifest.permission.WRITE_CONTACTS)) { showMessageOKCancel("You need to allow access to Contacts", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) {requestPermissions(new String[] {Manifest.permission.WRITE_CONTACTS}, REQUEST_CODE_ASK_PERMISSIONS); } }); return; } requestPermissions(new String[] {Manifest.permission.WRITE_CONTACTS}, REQUEST_CODE_ASK_PERMISSIONS); return; } insertDummyContact(); } private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) { new AlertDialog.Builder(MainActivity.this) .setMessage(message) .setPositiveButton("OK", okListener) .setNegativeButton("Cancel", null) .create() .show(); }
Kết quả là dialog sau được hiển thị:
Yêu cầu nhiều permission cùng lúc
Khi phát triển ứng dụng, sẽ có tính năng yêu cầu nhiều permission để thực hiện. Vì vậy, có thể yêu cầu nhiều permission cùng một lúc với cùng phương pháp như trên. Và đừng quên kiểm tra trường hợp người dùng lựa chọn "Never Ask Again".
Kết luận
- Sử dụng mô hình Runtime Permission để hỗ trợ các vấn đề cấp thiết.
- Đừng đặt targetSdkVersion là 23 khi ứng dụng của bạn chưa hỗ trợ Runtime Permission.