Android – Permission


Được đăng vào ngày 18/05/2016 | 0 bình luận
Đánh giá bài viết

Hệ điều hành Android bảo vệ chính nó và thông tin riêng của người dùng bằng cách chạy các ứng dụng Android trên một môi trường ảo riêng (thuật ngữ gọi là Sandbox), môi trường ảo này có tài nguyên riêng, không đụng chạm gì tới tài nguyên của hệ điều hành, nếu ứng dụng muốn sử dụng tài nguyên bên ngoài Sandbox thì ứng dụng phải xin permission – quyền sử dụng. Tùy thuộc vào loại tài nguyên mà ứng dụng muốn truy cập, hệ điều hành sẽ cấp quyền sử dụng tự động hoặc sẽ phải hỏi ý kiến của người dùng thì mới được sử dụng.

Khai báo Permission

Tùy vào loại tài nguyên cần sử dụng mà ứng dụng sẽ phải khai báo permission cho phù hợp. Các permission sẽ được khai báo trong file AndroidManifest.xml. Tùy vào loại dữ liệu có mức độ riêng tư đến mức nào mà hệ điều hành sẽ tự động cấp quyền hoặc phải xin ý kiến người dùng, chẳng hạn như quyền sử dụng đèn pin sẽ được cấp ngay, trong khi quyền truy cập danh sách số điện thoại liên lạc sẽ phải hỏi ý kiến người dùng… Cách người dùng cấp quyền cũng khác nhau theo từng phiên bản Android, chẳng hạn như đối với phiên bản Android 5.1 trở về trước thì người dùng sẽ cấp quyền trong quá trình cài đặt ứng dụng, còn ở phiên bản Android 6.0 trở lên thì người dùng sẽ cấp quyền khi ứng dụng đang chạy.

Xác định loại quyền cần dùng

Thông thường thì ứng dụng sẽ cần dùng đến các loại dữ liệu mà bản thân nó không thể tự tạo ra được, hay các hành động có thể làm ảnh hưởng đến hành vi của smartphone hoặc các ứng dụng khác. Chẳng hạn như quyền truy cập Internet, quyền sử dụng Camera, quyền tắt/bật Wifi…

Các quyền lại được chia làm nhiều cấp độ, trong đó 2 cấp độ cao nhất là bình thường (normal) và nguy hiểm (dangerous). Quyền bình thường là các quyền sử dụng tài nguyên mà ít có rủi ro đối với sự riêng tư của người dùng, loại quyền này sẽ được hệ điều hành tự động cấp. Dưới đây là danh sách các quyền bình thường có trong phiên bản API 23:

  • ACCESS_LOCATION_EXTRA_COMMANDS
  • ACCESS_NETWORK_STATE
  • ACCESS_NOTIFICATION_POLICY
  • ACCESS_WIFI_STATE
  • BLUETOOTH
  • BLUETOOTH_ADMIN
  • BROADCAST_STICKY
  • CHANGE_NETWORK_STATE
  • CHANGE_WIFI_MULTICAST_STATE
  • CHANGE_WIFI_STATE
  • DISABLE_KEYGUARD
  • EXPAND_STATUS_BAR
  • GET_PACKAGE_SIZE
  • INSTALL_SHORTCUT
  • INTERNET
  • KILL_BACKGROUND_PROCESSES
  • MODIFY_AUDIO_SETTINGS
  • NFC
  • READ_SYNC_SETTINGS
  • READ_SYNC_STATS
  • RECEIVE_BOOT_COMPLETED
  • REORDER_TASKS
  • REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
  • REQUEST_INSTALL_PACKAGES
  • SET_ALARM
  • SET_TIME_ZONE
  • SET_WALLPAPER
  • SET_WALLPAPER_HINTS
  • TRANSMIT_IR
  • UNINSTALL_SHORTCUT
  • USE_FINGERPRINT
  • VIBRATE
  • WAKE_LOCK
  • WRITE_SYNC_SETTINGS

Quyền nguy hiểm là quyền sử dụng các loại tài nguyên có liên quan đến sự riêng tư của người dùng hoặc có thể ảnh hưởng đến hệ điều hành và các ứng dụng khác. Loại quyền này cần được sự cho phép của người dùng. Dưới đây là danh sách các quyền nguy hiểm có trong phiên bản API 23:

  • READ_CALENDAR
  • WRITE_CALENDAR
  • CAMERA
  • READ_CONTACTS
  • WRITE_CONTACTS
  • GET_ACCOUNTS
  • ACCESS_FINE_LOCATION
  • ACCESS_COARSE_LOCATION
  • RECORD_AUDIO
  • READ_PHONE_STATE
  • CALL_PHONE
  • READ_CALL_LOG
  • WRITE_CALL_LOG
  • ADD_VOICEMAIL
  • USE_SIP
  • PROCESS_OUTGOING_CALLS
  • BODY_SENSORS
  • SEND_SMS
  • RECEIVE_SMS
  • READ_SMS
  • RECEIVE_WAP_PUSH
  • RECEIVE_MMS
  • READ_EXTERNAL_STORAGE
  • WRITE_EXTERNAL_STORAGE

Ứng dụng chỉ cần xin quyền để nó có thể sử dụng trực tiếp tài nguyên, nếu trong quá trình chạy mà ứng dụng có sử dụng dữ liệu lấy từ một ứng dụng khác thì chỉ có ứng dụng khác mới cần xin quyền.

Khai báo trong file AndroidManifest.xml

Để khai báo quyền thì chúng ta sử dụng thẻ <user-permissions> trong thẻ <manifest>. Ví dụ:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.phocode">
    <uses-permission android:name="android.permission.SEND_SMS"/>
    <application ...>
        ...
    </application>
</manifest>

Ở đây chúng ta xin quyền được gửi tin SMS. Đây là loại quyền nguy hiểm.

Xin quyền trong quá trình chạy

Đối với loại quyền nguy hiểm thì quá trình xin quyền sẽ khác ở từng phiên bản hệ điều hành và từng phiên bản SDK. Ví dụ:

  • Nếu thiết bị chạy Android phiên bản 5.1 trở xuống và ứng dụng sử dụng API 22 trở xuống thì người dùng sẽ phải tự tay cấp quyền trong quá trình cài đặt ứng dụng, nếu không cấp thì ứng dụng sẽ không được cài đặt.
  • Nếu thiết bị chạy Android 6.0 trở lên và ứng dụng sử dụng API 23 trở lên thì ứng dụng sẽ được cài nhưng khi chạy thì ứng dụng sẽ lần lượt xin từng quyền từ người dùng, người dùng có thể cấp quyền này, bỏ quyền kia và ứng dụng sẽ vẫn chạy nhưng giới hạn với những quyền không được cấp.

Kể từ phiên bản Android 6.0 (API 23), người dùng có thể lấy lại quyền của ứng dụng, ví dụ như chúng ta có một ứng dụng cần sử dụng camera, và hôm nay người dùng đã cho phép quyền sử dụng camera thì không có nghĩa là ngày hôm sau ứng dụng vẫn còn có quyền đó, do đó trước khi chạy chúng ta nên kiểm tra xem ứng dụng của chúng ta có quyền hay không đã.

Ví dụ

Chúng ta viết một ứng dụng cần có quyền đọc danh sách số điện thoại liên lạc.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
    package="com.phocode.sharedpreferences">

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

Trong file AndroidManifest.xml chúng ta khai báo quyền trong thẻ <uses-permission>. 

package com.phocode;

import android.Manifest;
import android.content.pm.PackageManager;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.widget.Toast;

public class MainActivity extends Activity {

    private static final int MY_PERMISSIONS_REQUEST_READ_CONTACTS = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) 
                                != PackageManager.PERMISSION_GRANTED) 
        {
            ActivityCompat.requestPermissions(this, 
                                new String[]{Manifest.permission.READ_CONTACTS}, 
                                READ_CONTACTS_CODE);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
            case READ_CONTACTS_CODE: 
            {
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(getApplicationContext(), "Contacts permission granted", Toast.LENGTH_SHORT).show();
                } 
                else 
                {                   
                    Toast.makeText(getApplicationContext(), "Contacts permission denied", Toast.LENGTH_SHORT).show();
                }
                return;
            }
        }
    }
}

Trong file MainActivity.java chúng ta thực hiện các công việc xin quyền đọc danh sách liên lạc.

private static final int READ_CONTACTS_CODE = 1;

Hằng số READ_CONTACTS_CODE là một hằng số do chúng ta tự định nghĩa, hằng số này có tác dụng giống như ID để phân biệt các lần xin quyền.

if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) 
                                != PackageManager.PERMISSION_GRANTED) 

Phương thức checkSelfPermission() của lớp android.support.v4.ContextCompat sẽ kiểm tra xem ứng dụng đã được cấp quyền đó rồi hay chưa, lớp này được định nghĩa trong thư viện support v4. Chúng ta sẽ tìm hiểu về các thư viện support này sau.

ActivityCompat.requestPermissions(this, 
                                  new String[]{Manifest.permission.READ_CONTACTS}, 
                                  READ_CONTACTS_CODE);

Nếu quyền chưa được cấp thì chúng ta xin quyền bằng cách gọi phương thức ActivityCompat.requestPermission(), phương thức này nhận vào đối tượng Activity hiện tại, danh sách các quyền trong một mảng String và ID mà chúng ta đã định nghĩa ở trên, kết quả trả về là PackageManager.PERMISSION_GRANTED nếu được chấp nhận, ngược lại là PackageManager.PERMISSION_DENIED.

@Override
public void onRequestPermissionsResult(int requestCode, 
                                       String permissions[], 
                                       int[] grantResults) 
{
...
}

Phương thức requestPermission() sẽ hiển thị một hộp thoại xin cấp quyền cho người dùng, kết quả trả về sẽ được truyền vào lời gọi phương thức onRequestPermission(), phương thức này nhận ID của quyền được xin, danh sách các quyền trong mảng permissions và danh sách kết quả của từng quyền trong mảng grantResults.

switch (requestCode) {
    case READ_CONTACTS_CODE: 
    {
    ...
    }

Câu lệnh switch() sẽ thực thi từng câu lệnh tương ứng với từng ID.

if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) 
{
    Toast.makeText(getApplicationContext(), "Contacts permission granted", Toast.LENGTH_SHORT).show();
} 
else 
{   
    Toast.makeText(getApplicationContext(), "Contacts permission denied", Toast.LENGTH_SHORT).show();
}

Ở đây chúng ta chỉ xin cấp 1 quyền là READ_CONTACTS, do đó các mảng trả về chỉ có 1 phần tử, chúng ta kiểm tra xem kết quả xin quyền READ_CONTACTS có thành công hay không bằng cách so sánh với hằng số PERMISSION_GRANTED. Nếu có thì hiện một câu thông báo thành công, ngược lại thì báo thất bại.

Nếu ứng dụng đã từng bị từ chối cấp quyền bởi người dùng thì các lần xin quyền tiếp theo hộp thoại sẽ hiện một checkbox đề “Never ask again”, nếu người dùng check vào thì ứng dụng sẽ không bao giờ có thể xin quyền được nữa.

Capture







Trả lời


Lưu ý: bọc code trong cặp thẻ [code language="x"][/code] để highlight code.


Ví dụ:


[code language="cpp"]


    std::cout << "Hello world";


[/code]



Các ngôn ngữ được hỗ trợ gồm: actionscript3, bash, clojure, coldfusion, cpp, csharp, css, delphi, diff, erlang, fsharp, go, groovy, html, java, javafx, javascript, latex, matlab, objc, perl, php, powershell, python, r, ruby, scala, sql, text, vb, xml.

Thư điện tử của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *