Permission trong Android (Part 2) - Yêu cầu cấp quyền khi ứng dụng đang chạy

Trong phần 2 này mình sẽ giới thiệu cho các bạn về cách yêu cầu được cấp các quyền cần thiết khi ứng dụng đang chạy. Các phần khác:

Bắt đầu từ Androdi 6.0 (API 23), người dùng cần cấp quyền cho ứng dụng khi ứng dụng đang chạy, không phải khi cài đặt. Với cách tiếp cận này, người dùng không cần phải cấp quyền khi mà họ cài đặt hay cập nhật ứng dụng. Điều này cũng giúp cho người dùng kiểm soát tốt hơn các chức năng của ứng dụng. Ví dụ, 1 người dùng có thể cho phép ứng dụng truy cập vào camera nhưng không thể lấy vị trí của thiết bị. Người dùng có thể thay đổ các quyền bắt cứ lúc nào, bằng các vào mục cài đặt của thiết bị.

Các quyền hệ thống được chia làm 2 loại: bình thường và nguy hiểm:

  • Các quyền bình thường là không ảnh hưởng đến thông tin cá nhân của người dùng. Hệ thống sẽ tự động cấp các quyền này mà không cần hỏi ý kiến người dùng
  • Các quyền nguy hiểm là cho phép truy cập vào các thông tin cá nhân của người dùng. Hệ thống sẽ yêu cầu sự đồng ý của người dùng sau đó mới cấp quyền cho ứng dụng

Dù ở phiên bản Android nào, ứng dụng của bạn đều phải khai báo các quyền bình thường và nguy hiểm trong file Manifest. Tuy nhiên, tùy từng phiên bản hệ thống sẽ xử lý khác nhau:

  • Thiết bị chạy Android 5.1 hay thấp hơn, hoặc ứng dụng của bạn nhắm đến SDK 22 hay thấp hơn thì người dùng sẽ cho cấp các quyền khi họ cái đặt ứng dụng; nếu họ không cấp quyền, thì hệ thống sẽ không cài đặt ứng dụng
  • Thiết bị chạy Android 6.0 hay cao hơn, và ứng dụng của bạn nhắm đến SDK 23 hay cao hơn thì nó sẽ yêu cầu người dùng cấp các quyên nguy hiểm khi ứng dụng đang chạy. Người dùng có thể đồng ý hoặc từ chối từng quyền, và ứng dụng có thể tiếp tục chạy với khả năng bị giới hạn thậm chí khi người dùng từ chối các yêu cầu cấp quyền

Kiểm tra các quyền

Nếu ứng dụng của bạn cần 1 quyền nguy hiểm, bạn phải kiểm tra liệu quyền đó đã được cấp chưa mỗi lần bạn thực hiện 1 thao tác mà yêu cầu quyền đó. Người dùng luôn luôn có thể gọi lại các quyền, thậm chí nếu ứng dụng đã sử dụng camera hôm qua, không thể đảm bảo rằng hôm nay nó vẫn có quyền đó.

Để kiểm tra liệu bạn đang có 1 quyền hay không, gọi phương thức ContextCompat.checkSelfPermission() . Ví dụ, đoạn code sau cho thấy làm thế nào để kiểm tra 1 activity có quyền viết vào lịch hay không:

// Assume thisActivity is the current activity**
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
        Manifest.permission.WRITE_CALENDAR);

Nếu ứng dụng có quyền này, phương thức sẽ trả về PackageManager.PERMISSION_GRANTED, và ứng dụng có thể thực hiện thao tác. Nếu ứng dụng không có quyền này, phương thức trả về PERMISSION_DENIED, và ứng dụng phải hỏi lại người dùng để được cấp quyền.

Yêu cầu để được cấp quyền

Nếu ứng dụng cảu bạn cần 1 quyền nguy hiểm đã được liệt kê trong file Manifest, nó phải yêu cầu người dùng cấp quyền đó. Android cung cấp 1 số phương thức bạn có thể sử dụng để yêu cầu được cấp quyền. Gọi các phương thức này sẽ hiển thị 1 hộp hội thoại trên màn hình.

alt

Giải thích tại sao ứng dụng cần được cấp quyền

Trong vài trường hợp, bạn có thể muốn giúp người dùng hiểu rõ hơn tại sao ứng dụng của bạn là cần 1 quyền nào đó. Ví dụ, nếu nguwoif dùng bật ứng dụng ảnh, người dùng có thể không bất ngờ khi ứng dụng yêu cầu cần quyền sử dụng camera, nhưng người dùng sẽ không hiểu tại sao ứng dụng lại cần truy cập vào danh bạ. Trước khi bạn yêu cầu 1 quyền, bạn nên cân nhắc việc giải thích lý do với người dùng. Nhưng luôn nhớ đừng làm người dùng khó chịu với quá nhiều giải thích.

1 cách tiếp cận mà bạn có hể sử dụng là chỉ cung cấp giải thích khi người dùng đã từng từ chối cấp quyền trước đây. Nếu người dùng tiếp tục muốn sử dụng chức năng này, chứng tỏ người dùng có thể không hiểu tại sao lại cần phải cấp quyền đó. Trong trường hợp đó, ta nên cung cấp lời giải thích.

Để giúp tìm các trường hợp khi mà người dùng cần 1 lời giải thích, Android cung câp 1 phương thức shouldShowRequestPermissionRationale(). Phương thức này trả về true nếu ứng dụng đã từng yêu cầu cấp quyền trước đây nhưng bị từ chối.

Yêu cầu các quyền mà bạn cần

Nếu ứng dụng của bạn không có quyền mà nó cần, ứng dụng cần phải gọi 1 trong các phương thức requestPermissions() để yêu cầu các quyền phù hợp. Ứng dụng của bạn truyền các quyền mà nó muốn, cùng với 1 số request code để xác định yêu cầu này. Phương thức này không đồng bộ: nó trả về ngay lập tức, và sau đó người dùng thao tác với hộp hội thoại, hệ thống sẽ gọi các phương thức callback với kết quả, trả về cùng 1 request code mà ứng dụng đã truyền từ trước.

Đoạn code sau kiểm tra ứng dụng đã có quyền đọc danh bạ của người dùng chưa, và yêu cầu cấp quyền nếu cần thiết:

// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
                Manifest.permission.READ_CONTACTS)
        != PackageManager.PERMISSION_GRANTED) {

    // Should we show an explanation?
    if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
            Manifest.permission.READ_CONTACTS)) {

        // Show an expanation to the user *asynchronously* -- don't block
        // this thread waiting for the user's response! After the user
        // sees the explanation, try again to request the permission.

    } else {

        // No explanation needed, we can request the permission.

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

        // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
        // app-defined int constant. The callback method gets the
        // result of the request.
    }
}

Xử lý kết quả trả về của các yêu cầu cấp quyền

Khi ứng dụng của bạn yêu cầu cấp quyền, hệ thống hiển thị 1 hộp hội thoại cho người dùng. Khi người dùng thao tác xong với hộp hội thoại đó, hệ thông sẽ gọi phương thức onRequestPermissionsResult(), truyền cho nó kết quả mà nguời dùng đã chọn. Ứng dụng phải viết lại phương thức để tìm ra liệu quyền đó có được cấp hay không. Callback được truyền cùng 1 request code mà bạn đã truyền từ trước đó. Ví dọ 1 ứng dụng quyên cầu quyền đọc danh bạ, có thể làm theo đoạn code sau:

@Override
public void onRequestPermissionsResult(int requestCode,
        String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // permission was granted, yay! Do the
                // contacts-related task you need to do.

            } else {

                // permission denied, boo! Disable the
                // functionality that depends on this permission.
            }
            return;
        }

        // other 'case' lines to check for other
        // permissions this app might request
    }
}

Hộp hội thoại được hiển thị bởi hệ thống mô tả tập các quyền ứng dụng cần truy cập, nó không liệt kê từng quyền chi tiết. Người dùng chỉ cần cấp quyền 1 lần cho từng tập quyền. Nếu ứng dụng yêu cầu bât kỳ các quyền nào khác trong tập quyền đó, hệ thống sẽ từ cấp các quyền đó.

Nếu người dùng từ chối 1 yêu cầu cấp quyền, ứng dụng nên chọn hành động thích hợp. Ví dụ, ứng dụng có thể hiển thị 1 hộp hội thoại giải thích tại sao nó không thể thực hiện thao tác người dùng cần.

Khi hệ thống yêu cầu người dùng cấp quyền, người dùng có thể chọn không hiển thị yêu cầu này bao giờ nữa. Trong trường hợp đó, bất cứ khi nào ứng dụng sử dụng requestPermissions() để yêu cầu quyền đó lần nữa, hệ thống tự động từ chối. Hệ thống gọi phương thức callback onRequestPermissionsResult() và truyền PERMISSION_DENIED, tương tự như người dùng chọn không cấp quyền lần nữa.

Như vậy mình đã giới thiệu xong cách yêu cầu cấp quyền khi ứng dụng đang chạy, mong bài viết sẽ có ích cho việc phát triển ứng dụng của các bạn. Hẹn gặp lại các bạn trong phần 3, cũng là phần cuối của chuỗi bài viết này nhé 😄 !!!

Tài liệu tham khảo: https://developer.android.com/training/permissions/requesting.html

All Rights Reserved