Thiết lập cấu hình được quản lý

Nếu đang phát triển ứng dụng cho thị trường doanh nghiệp, bạn có thể cần đáp ứng các yêu cầu cụ thể do chính sách của tổ chức đặt ra. Cấu hình được quản lý, trước đây gọi là các hạn chế đối với ứng dụng, cho phép quản trị viên CNTT của tổ chức chỉ định từ xa các chế độ cài đặt cho ứng dụng. Chức năng này đặc biệt hữu ích cho các ứng dụng được tổ chức phê duyệt được triển khai cho hồ sơ công việc.

Ví dụ: một tổ chức có thể yêu cầu các ứng dụng được phê duyệt phải cho phép quản trị viên CNTT:

  • Cho phép hoặc chặn URL đối với trình duyệt web
  • Định cấu hình việc ứng dụng được phép đồng bộ hoá nội dung qua mạng di động hay chỉ qua Wi-Fi
  • Thiết lập chế độ cài đặt email của ứng dụng

Hướng dẫn này trình bày cách triển khai các chế độ cài đặt cấu hình được quản lý trong ứng dụng của bạn. Để xem các ứng dụng mẫu có cấu hình được quản lý, hãy xem phần ManagedConfigurations. Nếu bạn là nhà phát triển giải pháp quản lý di động dành cho doanh nghiệp (EMM), hãy tham khảo Hướng dẫn về API quản lý Android.

Lưu ý: Vì lý do trước đây, các chế độ cài đặt cấu hình này được gọi là hạn chế, đồng thời được triển khai với các tệp và lớp sử dụng thuật ngữ này (chẳng hạn như RestrictionsManager). Tuy nhiên, trên thực tế, các hạn chế này có thể triển khai nhiều tuỳ chọn cấu hình, không chỉ các hạn chế về chức năng của ứng dụng.

Tổng quan về cấu hình từ xa

Ứng dụng xác định những chế độ cấu hình được quản lý mà quản trị viên CNTT có thể thiết lập từ xa. Đây là các chế độ cài đặt tuỳ ý do nhà cung cấp cấu hình được quản lý có thể thay đổi. Nếu ứng dụng của bạn đang chạy trong hồ sơ công việc, thì quản trị viên CNTT có thể thay đổi cấu hình được quản lý của ứng dụng.

Nhà cung cấp cấu hình được quản lý là một ứng dụng khác chạy trên cùng thiết bị. Ứng dụng này thường do quản trị viên CNTT kiểm soát. Quản trị viên CNTT sẽ thông báo về các thay đổi về cấu hình cho ứng dụng của nhà cung cấp cấu hình được quản lý. Theo đó, ứng dụng đó sẽ thay đổi cấu hình trên ứng dụng của bạn.

Cách cung cấp cấu hình được quản lý bên ngoài:

  • Khai báo cấu hình được quản lý trong tệp kê khai ứng dụng. Cách làm này cho phép quản trị viên CNTT đọc cấu hình của ứng dụng thông qua API Google Play.
  • Bất cứ khi nào ứng dụng tiếp tục, hãy sử dụng đối tượng RestrictionsManager để kiểm tra các cấu hình được quản lý hiện tại, đồng thời thay đổi giao diện người dùng và hành vi của ứng dụng để phù hợp với các cấu hình đó.
  • Theo dõi ý định ACTION_APPLICATION_RESTRICTIONS_CHANGED. Khi bạn nhận được thông báo này, hãy kiểm tra RestrictionsManager để xem cấu hình được quản lý hiện tại và thực hiện mọi thay đổi cần thiết đối với hành vi của ứng dụng.

Xác định cấu hình được quản lý

Ứng dụng của bạn có thể hỗ trợ bất kỳ cấu hình được quản lý nào mà bạn muốn xác định. Bạn sẽ khai báo các cấu hình được quản lý của ứng dụng trong tệp cấu hình được quản lý và khai báo tệp cấu hình trong tệp kê khai. Khi bạn tạo tệp cấu hình, các ứng dụng khác có thể kiểm tra cấu hình được quản lý mà ứng dụng của bạn cung cấp. Các đối tác EMM có thể đọc cấu hình của ứng dụng bằng cách sử dụng API Google Play.

Để xác định các lựa chọn cấu hình từ xa của ứng dụng, hãy đặt phần tử sau đây vào phần tử <application> của tệp kê khai:

<meta-data android:name="android.content.APP_RESTRICTIONS"
    android:resource="@xml/app_restrictions" />

Tạo một tệp có tên app_restrictions.xml trong thư mục res/xml của ứng dụng. Cấu trúc của tệp đó được mô tả trong tài liệu tham khảo cho RestrictionsManager. Tệp này có một phần tử <restrictions> cấp cao nhất, trong đó chứa một phần tử con <restriction> cho mọi tuỳ chọn cấu hình mà ứng dụng có.

Lưu ý: Đừng tạo phiên bản đã bản địa hoá của tệp cấu hình được quản lý. Ứng dụng của bạn chỉ được phép có một tệp cấu hình được quản lý, vì vậy, các cấu hình sẽ nhất quán cho ứng dụng ở mọi ngôn ngữ.

Trong môi trường doanh nghiệp, EMM thường sử dụng giản đồ cấu hình được quản lý để tạo bảng điều khiển từ xa cho quản trị viên CNTT, nhờ đó, quản trị viên có thể định cấu hình ứng dụng của bạn từ xa.

Nhà cung cấp cấu hình được quản lý có thể truy vấn ứng dụng để tìm thông tin chi tiết về các cấu hình có sẵn của ứng dụng, bao gồm cả văn bản mô tả. Nhà cung cấp cấu hình và quản trị viên CNTT có thể thay đổi các cấu hình được quản lý của ứng dụng bất cứ lúc nào, ngay cả khi ứng dụng không chạy.

Ví dụ: giả sử bạn có thể định cấu hình ứng dụng từ xa để cho phép hoặc cấm ứng dụng tải dữ liệu xuống qua kết nối di động. Ứng dụng của bạn có thể có phần tử <restriction> như sau:

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

  <restriction
    android:key="downloadOnCellular"
    android:title="@string/download_on_cell_title"
    android:restrictionType="bool"
    android:description="@string/download_on_cell_description"
    android:defaultValue="true" />

</restrictions>

Bạn sử dụng thuộc tính android:key của từng cấu hình để đọc giá trị của cấu hình đó từ một gói cấu hình được quản lý. Vì lý do này, mỗi cấu hình phải có một chuỗi khoá duy nhất và không thể bản địa hoá chuỗi này. Giá trị này phải được chỉ định bằng giá trị cố định kiểu chuỗi.

Lưu ý: Trong ứng dụng chính thức, android:titleandroid:description phải được vẽ từ một tệp tài nguyên đã bản địa hoá, như mô tả trong phần Bản địa hoá bằng tài nguyên.

Ứng dụng xác định các quy định hạn chế bằng cách sử dụng các gói trong một bundle_array. Ví dụ: một ứng dụng có nhiều tuỳ chọn kết nối VPN có thể xác định từng cấu hình máy chủ VPN trong một bundle, với nhiều gói được nhóm với nhau trong một mảng gói:

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

  <restriction
    android:key="vpn_configuration_list"
    android:restrictionType="bundle_array">
    <restriction
      android:key="vpn_configuration"
      android:restrictionType="bundle">
      <restriction
        android:key="vpn_server"
        android:restrictionType="string"/>
      <restriction
        android:key="vpn_username"
        android:restrictionType="string"/>
      <restriction
        android:key="vpn_password"
        android:restrictionType="string"/>
    </restriction>
  </restriction>

</restrictions>

Các loại được hỗ trợ cho phần tử android:restrictionType được liệt kê trong Bảng 1 và được ghi lại trong tài liệu tham khảo cho RestrictionsManagerRestrictionEntry.

Bảng 1. Loại mục nhập hạn chế và cách sử dụng.

Loại android:restrictionType Mức sử dụng thông thường
TYPE_BOOLEAN "bool" Giá trị boolean, true hoặc false.
TYPE_STRING "string" Giá trị chuỗi, chẳng hạn như tên.
TYPE_INTEGER "integer" Số nguyên có giá trị từ MIN_VALUE đến MAX_VALUE.
TYPE_CHOICE "choice" Một giá trị chuỗi được chọn từ android:entryValues, thường được trình bày dưới dạng danh sách chọn một giá trị.
TYPE_MULTI_SELECT "multi-select" Một mảng chuỗi chứa các giá trị được chọn từ android:entryValues. Sử dụng tính năng này để hiển thị danh sách nhiều mục có thể chọn nhiều mục, chẳng hạn như để chọn các bộ phim/chương trình cụ thể để đưa vào danh sách cho phép.
TYPE_NULL "hidden" Loại hạn chế ẩn. Hãy sử dụng loại này cho thông tin cần được chuyển qua nhưng không được hiển thị cho người dùng trong giao diện người dùng. Lưu trữ một giá trị chuỗi đơn.
TYPE_BUNDLE_ARRAY "bundle_array" Sử dụng thuộc tính này để lưu trữ các mảng hạn chế bundles. Có trong Android 6.0 (API cấp 23).

Lưu ý: android:entryValues là máy có thể đọc được và không bản địa hoá được. Sử dụng android:entries để trình bày các giá trị con người có thể đọc được và có thể bản địa hoá. Mỗi mục phải có một chỉ mục tương ứng trong android:entryValues.

Kiểm tra cấu hình được quản lý

Ứng dụng của bạn sẽ không nhận được thông báo tự động khi các ứng dụng khác thay đổi chế độ cài đặt cấu hình. Thay vào đó, bạn cần kiểm tra xem cấu hình được quản lý là gì khi ứng dụng khởi động hoặc tiếp tục, đồng thời lắng nghe ý định của hệ thống để tìm hiểu xem cấu hình có thay đổi khi ứng dụng đang chạy hay không.

Để tìm các chế độ cài đặt cấu hình hiện tại, ứng dụng của bạn sẽ sử dụng một đối tượng RestrictionsManager. Ứng dụng của bạn nên kiểm tra các cấu hình hiện được quản lý tại những thời điểm sau:

Để lấy đối tượng RestrictionsManager, hãy lấy hoạt động hiện tại bằng getActivity(), sau đó gọi phương thức Activity.getSystemService() của hoạt động đó:

Kotlin

var myRestrictionsMgr =
        activity?.getSystemService(Context.RESTRICTIONS_SERVICE) as RestrictionsManager

Java

RestrictionsManager myRestrictionsMgr =
    (RestrictionsManager) getActivity()
        .getSystemService(Context.RESTRICTIONS_SERVICE);

Sau khi có RestrictionsManager, bạn có thể lấy các chế độ cài đặt cấu hình hiện tại bằng cách gọi phương thức getApplicationRestrictions():

Kotlin

var appRestrictions: Bundle = myRestrictionsMgr.applicationRestrictions

Java

Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();

Lưu ý: Để thuận tiện, bạn cũng có thể tìm nạp các cấu hình hiện tại bằng UserManager bằng cách gọi UserManager.getApplicationRestrictions(). Phương thức này có hành vi giống hệt như RestrictionsManager.getApplicationRestrictions().

Phương thức getApplicationRestrictions() yêu cầu đọc từ bộ nhớ dữ liệu, vì vậy, bạn nên thực hiện phương thức này một cách thận trọng. Không gọi phương thức này mỗi khi bạn cần biết cấu hình hiện tại. Thay vào đó, bạn nên gọi lệnh này một lần khi ứng dụng khởi động hoặc tiếp tục và lưu gói cấu hình được quản lý đã tìm nạp vào bộ nhớ đệm. Sau đó, hãy lắng nghe ý định ACTION_APPLICATION_RESTRICTIONS_CHANGED để tìm hiểu xem cấu hình có thay đổi khi ứng dụng đang hoạt động hay không, như mô tả trong phần Theo dõi các thay đổi về cấu hình được quản lý.

Đọc và áp dụng cấu hình được quản lý

Phương thức getApplicationRestrictions() trả về một Bundle chứa một cặp khoá-giá trị cho mỗi cấu hình đã được đặt. Tất cả các giá trị đều thuộc loại Boolean, int, StringString[]. Sau khi có cấu hình được quản lý Bundle, bạn có thể kiểm tra chế độ cài đặt cấu hình hiện tại bằng các phương thức Bundle tiêu chuẩn cho các loại dữ liệu đó, chẳng hạn như getBoolean() hoặc getString().

Lưu ý: Cấu hình được quản lý Bundle chứa một mục cho mỗi cấu hình do nhà cung cấp cấu hình được quản lý đặt rõ ràng. Tuy nhiên, bạn không thể giả định rằng một cấu hình sẽ xuất hiện trong gói chỉ vì bạn đã xác định giá trị mặc định trong tệp XML cấu hình được quản lý.

Ứng dụng của bạn có thể chọn có biện pháp xử lý thích hợp dựa trên các chế độ cài đặt cấu hình được quản lý hiện tại. Ví dụ: nếu ứng dụng của bạn có cấu hình chỉ định liệu ứng dụng có thể tải dữ liệu xuống qua kết nối di động hay không và bạn thấy rằng cấu hình được đặt thành false, thì bạn sẽ phải tắt tính năng tải dữ liệu xuống trừ khi thiết bị có kết nối Wi-Fi, như trong mã ví dụ sau:

Kotlin

val appCanUseCellular: Boolean =
        if (appRestrictions.containsKey("downloadOnCellular")) {
            appRestrictions.getBoolean("downloadOnCellular")
        } else {
            // cellularDefault is a boolean using the restriction's default value
            cellularDefault
        }

if (!appCanUseCellular) {
    // ...turn off app's cellular-download functionality
    // ...show appropriate notices to user
}

Java

boolean appCanUseCellular;

if (appRestrictions.containsKey("downloadOnCellular")) {
    appCanUseCellular = appRestrictions.getBoolean("downloadOnCellular");
} else {
    // cellularDefault is a boolean using the restriction's default value
    appCanUseCellular = cellularDefault;
}

if (!appCanUseCellular) {
    // ...turn off app's cellular-download functionality
    // ...show appropriate notices to user
}

Để áp dụng nhiều hạn chế lồng nhau, hãy đọc mục hạn chế bundle_array dưới dạng một tập hợp các đối tượng Parcelable và truyền dưới dạng Bundle. Trong ví dụ này, dữ liệu cấu hình của mỗi VPN được phân tích cú pháp và dùng để tạo danh sách lựa chọn kết nối với máy chủ:

Kotlin

// VpnConfig is a sample class used store config data, not defined
val vpnConfigs = mutableListOf<VpnConfig>()

val parcelables: Array<out Parcelable>? =
        appRestrictions.getParcelableArray("vpn_configuration_list")

if (parcelables?.isNotEmpty() == true) {
    // iterate parcelables and cast as bundle
    parcelables.map { it as Bundle }.forEach { vpnConfigBundle ->
        // parse bundle data and store in VpnConfig array
        vpnConfigs.add(VpnConfig()
                .setServer(vpnConfigBundle.getString("vpn_server"))
                .setUsername(vpnConfigBundle.getString("vpn_username"))
                .setPassword(vpnConfigBundle.getString("vpn_password")))
    }
}

if (vpnConfigs.isNotEmpty()) {
    // ...choose a VPN configuration or prompt user to select from list
}

Java

// VpnConfig is a sample class used store config data, not defined
List<VpnConfig> vpnConfigs = new ArrayList<>();

Parcelable[] parcelables =
    appRestrictions.getParcelableArray("vpn_configuration_list");

if (parcelables != null && parcelables.length > 0) {
    // iterate parcelables and cast as bundle
    for (int i = 0; i < parcelables.length; i++) {
        Bundle vpnConfigBundle = (Bundle) parcelables[i];
        // parse bundle data and store in VpnConfig array
        vpnConfigs.add(new VpnConfig()
            .setServer(vpnConfigBundle.getString("vpn_server"))
            .setUsername(vpnConfigBundle.getString("vpn_username"))
            .setPassword(vpnConfigBundle.getString("vpn_password")));
    }
}

if (!vpnConfigs.isEmpty()) {
    // ...choose a VPN configuration or prompt user to select from list
}

Theo dõi các thay đổi về cấu hình được quản lý

Bất cứ khi nào cấu hình được quản lý của một ứng dụng thay đổi, hệ thống sẽ kích hoạt ý định ACTION_APPLICATION_RESTRICTIONS_CHANGED. Ứng dụng của bạn phải theo dõi ý định này để bạn có thể thay đổi hành vi của ứng dụng khi chế độ cài đặt cấu hình thay đổi.

Lưu ý: Ý định ACTION_APPLICATION_RESTRICTIONS_CHANGED chỉ được gửi đến những trình nghe được đăng ký động, chứ không đến những trình nghe được khai báo trong tệp kê khai ứng dụng.

Mã sau đây cho biết cách đăng ký động một broadcast receiver cho ý định này:

Kotlin

val restrictionsFilter = IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED)

val restrictionsReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {

        // Get the current configuration bundle
        val appRestrictions = myRestrictionsMgr.applicationRestrictions

        // Check current configuration settings, change your app's UI and
        // functionality as necessary.
    }
}

registerReceiver(restrictionsReceiver, restrictionsFilter)

Java

IntentFilter restrictionsFilter =
    new IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);

BroadcastReceiver restrictionsReceiver = new BroadcastReceiver() {
  @Override public void onReceive(Context context, Intent intent) {

    // Get the current configuration bundle
    Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();

    // Check current configuration settings, change your app's UI and
    // functionality as necessary.
  }
};

registerReceiver(restrictionsReceiver, restrictionsFilter);

Lưu ý: Thông thường, ứng dụng của bạn không cần được thông báo về các thay đổi về cấu hình khi bị tạm dừng. Thay vào đó, bạn nên huỷ đăng ký broadcast receiver khi ứng dụng bị tạm dừng. Khi ứng dụng tiếp tục, trước tiên, bạn sẽ kiểm tra các cấu hình được quản lý hiện tại (như đã thảo luận trong phần Kiểm tra cấu hình được quản lý), sau đó đăng ký broadcast receiver để đảm bảo bạn nhận được thông báo về các thay đổi về cấu hình xảy ra khi ứng dụng đang hoạt động.

Gửi ý kiến phản hồi về cấu hình được quản lý cho EMM

Sau khi áp dụng các thay đổi về cấu hình được quản lý cho ứng dụng của mình, bạn nên thông báo cho EMM về trạng thái của thay đổi đó. Android hỗ trợ một tính năng có tên là trạng thái ứng dụng theo khoá. Bạn có thể dùng tính năng này để gửi ý kiến phản hồi mỗi khi ứng dụng cố gắng áp dụng các thay đổi về cấu hình được quản lý. Phản hồi này có thể đóng vai trò xác nhận rằng ứng dụng của bạn đã thiết lập thành công các cấu hình được quản lý hoặc có thể đưa ra thông báo lỗi nếu ứng dụng không áp dụng được các thay đổi đã chỉ định.

Nhà cung cấp dịch vụ EMM có thể truy xuất phản hồi này và hiển thị phản hồi này trong bảng điều khiển của họ để quản trị viên CNTT xem. Hãy xem phần Gửi phản hồi về ứng dụng cho EMM để biết thêm thông tin về chủ đề này, bao gồm cả hướng dẫn chi tiết về cách thêm tính năng hỗ trợ phản hồi vào ứng dụng.

Mã mẫu khác

Mẫu ManagedConfigurations minh hoạ thêm về cách sử dụng các API được trình bày trên trang này.