07/09/2018, 17:54

Tìm hiểu Runtime Permission trong Android M

1. Permission workflow trước và sau android M (API 23) Mô hình permission trước android M: Trước API 23, mô hình permission đã được đơn giản cho các nhà phát triển nhưng cung cấp ít kiểm soát và bảo mật cho người dùng - yêu cầu permission được đưa ra khi người dùng cài đặt ứng dụng. Người ...


1. Permission workflow trước và sau android M (API 23)

  • Mô hình permission trước android M: Trước API 23, mô hình permission đã được đơn giản cho các nhà phát triển nhưng cung cấp ít kiểm soát và bảo mật cho người dùng - yêu cầu permission được đưa ra khi người dùng cài đặt ứng dụng. Người sử dụng cần quyết định liệu có cung cấp permission cho ứng dụng và cài đặt ứng dụng hoặc từ chối và không cài đặt. Permission không thể bị từ chối hoặc cấp lại sau khi đã cài đặt. Vì vậy các nhà phát triển chỉ cần khai báo tất cả các permission cần thiết trong manifest, nếu ứng dựng đang chạy thì nó có tất cả các quyền đã được yêu cầu.

  • Mô hình permission từ android M (API 23): Cùng với Android 6.0 Marshmallow (API 23), một mô hình runtime permission đã được đưa ra. Theo mô hình này, người dùng không cần cung cấp permission tại thời điểm cài đặt ứng dụng, nhà phát triển cần kiểm tra và yêu cầu permission trong thời gian ứng dụng chạy (tức là trước khi thực hiện bất kỳ hành động nào yêu cầu permission), người dùng có thể cho phép hoặc từ chối permission, người dùng cũng có thể cấp hoặc lấy lại bất cứ lúc nào permission từ settings. Điều này khiến người dùng cảm thấy an toàn trên thiết bị Android, nhưng ngược lại tính năng này yêu cầu nhà phát triển phải xử lý tất cả các trường hợp.

2. Các mức độ permission trong android M
Hệ thống permission có các mức độ bảo vệ khác nhau. Hai cấp độ bảo vệ quan trọng nhất là permission thường và permission nguy hiểm.

  • Permission thường là những permission đơn giản, không can thiệp sâu vào trong hệ thống. Hệ thống sẽ cấp quyền tự động với permission thường mà không cần nhắc cho người dùng. Ví dụ ACCESS_WIFI_STATE, WAKE_LOCK....
  • Permission nguy hiểm là những permission thường can thiệp sâu vào hệ thống thiết bị Android như: đọc danh bạ, đọc tập tin, tải file... Ví dụ khả năng đọc địa chỉ liên hệ của người dùng READ_CONTACTS. Nếu một ứng dụng yêu cầu một permission nguy hiểm, người dùng có quyền gán permission cho ứng dụng một cách rõ ràng.

3. Tạo ứng dụng yêu cầu permission trong android M

Tạo mới một project sử dụng Android Studio với minSdkVesion 17 và targetSdkVersion 23.

// build.gradle 
apply plugin: 'com.android.application'
 
android {
    defaultConfig {
        ..
        minSdkVersion 17
        targetSdkVersion 23
        ..
    }
}

Mặc dù permission sẽ được yêu cầu trong thời gian chạy, tuy nhiên chúng ta nên thêm permission vào Manifest, do đó người dụng sẽ được nhắc nhở lần đầu tiên yêu cầu permission, và sau đó hệ thống sẽ ghi nhớ quyết định của người dùng cho đến khi người dùng cập nhật permission trong settings. Chúng ta sẽ bắt đầu với các permission WRITE_EXTERNAL_STORAGE_PERMISSION tới AndroidManifest.xml file

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="info.androidhive.mpermissions">
 
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name="com.example.mpermissions.MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Mở layout file activity_main.xml add floating button để kiểm tra và yêu cầu permission WRITE_EXTERNAL_STORAGE.

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_awidth="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context="info.androidhive.mpermissions.MainActivity">
 
    ...
 
    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_awidth="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        app:srcCompat="@drawable/ic_file_download_black_24dp" />
 
   ...
</android.support.design.widget.CoordinatorLayout>

Layout trên sẽ sinh ra màn hình như sau:

Bước tiếp theo chúng ta sẽ thực hiện xử lý logic yêu cầu permission trong MainActivity.java file

public class MainActivity extends AppCompatActivity {
 
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       ...
       fab.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View view) {
              if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                  if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                      AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                      builder.setTitle("Need Storage Permission");
                      builder.setMessage("This app needs storage permission.");
                      builder.setPositiveButton("Grant", new DialogInterface.OnClickListener() {
                          @Override
                          public void onClick(DialogInterface dialog, int which) {
                              dialog.cancel();
                              ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, EXTERNAL_STORAGE_PERMISSION_CONSTANT);
                          }
                      });
                      builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                          @Override
                          public void onClick(DialogInterface dialog, int which) {
                              dialog.cancel();
                          }
                      });
                      builder.show();
                  } else if (permissionStatus.getBoolean(Manifest.permission.WRITE_EXTERNAL_STORAGE,false)) {
                      AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                      builder.setTitle("Need Storage Permission");
                      builder.setMessage("This app needs storage permission.");
                      builder.setPositiveButton("Grant", new DialogInterface.OnClickListener() {
                          @Override
                          public void onClick(DialogInterface dialog, int which) {
                              dialog.cancel();
                              sentToSettings = true;
                              Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                              Uri uri = Uri.fromParts("package", getPackageName(), null);
                              intent.setData(uri);
                              startActivityForResult(intent, REQUEST_PERMISSION_SETTING);
                              Toast.makeText(getBaseContext(), "Go to Permissions to Grant Storage", Toast.LENGTH_LONG).show();
                          }
                      });
                      builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                          @Override
                          public void onClick(DialogInterface dialog, int which) {
                              dialog.cancel();
                          }
                      });
                      builder.show();
                  } else {
                      ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, EXTERNAL_STORAGE_PERMISSION_CONSTANT);
                  }
       
                  SharedPreferences.Editor editor = permissionStatus.edit();
                  editor.putBoolean(Manifest.permission.WRITE_EXTERNAL_STORAGE,true);
                  editor.commit();
              } else {
                  proceedAfterPermission();
              }
           }
       });
     }
}

Khi khởi chạy ứng dụng, dialog sẽ hiển thị yêu cầu permisson

0