Xây dựng ứng dụng nhận biết nhiều người dùng

Khi một thiết bị hỗ trợ nhiều người dùng, các ứng dụng của thiết bị đó phải nhận biết được những người dùng riêng biệt này.

Một số ứng dụng nhất định cần có một số thành phần chạy dưới dạng singleton và có thể chấp nhận yêu cầu của bất kỳ người dùng nào. Hiện tại, chỉ các ứng dụng hệ thống mới có thể sử dụng tính năng này.

Cơ sở này:

  • Tiết kiệm tài nguyên
  • Điều phối một hoặc nhiều tài nguyên dùng chung giữa người dùng
  • Giảm hao tổn mạng bằng cách sử dụng một kết nối máy chủ

Hãy xem sơ đồ bên dưới để biết thông tin mô tả về luồng cấp quyền cho nhiều người dùng.

Luồng quyền của nhiều người dùng

Hình 1. Quyền của nhiều người dùng

Bật thành phần singleton

Để xác định một ứng dụng là singleton, hãy thêm android:singleUser="true" vào dịch vụ, trình thu nhận hoặc trình cung cấp trong tệp kê khai Android.

Hệ thống tạo bản sao thành phần đó trong quy trình chỉ chạy dưới dạng người dùng 0. Mọi yêu cầu kết nối với nhà cung cấp hoặc dịch vụ đó hoặc để truyền tin đến bộ thu đó, từ bất kỳ người dùng nào đều được chuyển đến quy trình trong người dùng 0. Nếu đây là thành phần duy nhất trong ứng dụng, thì chỉ một phiên bản ứng dụng sẽ chạy.

Các hoạt động trong gói của bạn vẫn được khởi chạy trong một quy trình riêng biệt cho mỗi người dùng, với UID nằm trong phạm vi UID cho người dùng đó (chẳng hạn như 1010034).

Tương tác với người dùng

Đặt quyền

Bạn cần có các quyền sau:

INTERACT_ACROSS_USERS (signature|system)
INTERACT_ACROSS_USERS_FULL (signature)

Sử dụng API

Sử dụng các API sau để ứng dụng nhận biết được nhiều người dùng.

  1. Trích xuất tên người dùng từ các lệnh gọi Binder đến:
    • int userHandle = UserHandle.getCallingUserId()
  2. Sử dụng các API mới, được bảo vệ để bắt đầu các dịch vụ, hoạt động, thông báo truyền tin trên một người dùng cụ thể:
    • Context.startActivityAsUser(Intent, UserHandle)
    • Context.bindServiceAsUser(Intent, …, UserHandle)
    • Context.sendBroadcastAsUser(Intent, … , UserHandle)
    • Context.startServiceAsUser(Intent, …, UserHandle)
    UserHandle có thể là một người dùng rõ ràng hoặc một trong các tên người dùng đặc biệt: UserHandle.CURRENT hoặc UserHandle.ALL. CURRENT cho biết người dùng hiện đang ở nền trước. Sử dụng ALL khi bạn muốn gửi thông báo truyền tin cho tất cả người dùng.
  3. Giao tiếp với các thành phần trong ứng dụng của riêng bạn: (INTERACT_ACROSS_USERS) Hoặc với các thành phần trong các ứng dụng khác: (INTERACT_ACROSS_USERS_FULL)
  4. Bạn có thể cần tạo các thành phần proxy chạy trong quy trình của người dùng, sau đó truy cập vào thành phần singleUser trong người dùng 0.
  5. Truy vấn người dùng và tên người dùng của họ bằng dịch vụ hệ thống UserManager mới:
    • UserManager.getUsers()
    • UserManager.getUserInfo()
    • UserManager.supportsMultipleUsers()
    • UserManager.getUserSerialNumber(int userHandle) – một số không tái chế tương ứng với tên người dùng.
    • UserManager.getUserHandle(int serialNumber)
    • UserManager.getUserProfiles() – trả về tập hợp hồ sơ tự quản lý và hồ sơ được quản lý, nếu có.
  6. Đăng ký để nghe một số hoặc tất cả người dùng và lệnh gọi lại bằng các API mới trên ContentObserver, PackageMonitor, BroadcastReceiver cung cấp thêm thông tin về người dùng đã gây ra lệnh gọi lại.

Các dịch vụ trong nhiều người dùng hoặc hồ sơ

Không phải dịch vụ nào cũng cần chạy một thực thể trong hồ sơ người dùng hoặc hồ sơ công việc khác. Nếu dịch vụ hệ thống của bạn chỉ cần chạy dưới dạng người dùng 0, hãy tắt các thành phần của dịch vụ khi chạy dưới người dùng khác để giúp bảo tồn tài nguyên. Ví dụ sau đây cho thấy cách bạn có thể thực hiện việc này tại các điểm truy cập của dịch vụ:

// Add on all entry points such as boot_completed or other manifest-listed receivers and providers
if (!UserManager.isSystemUser()) {
    // Disable the service
    ComponentName targetServiceName = new ComponentName(this, TargetService.class);
    context.getPackageManager().setComponentEnabledSetting(
        targetServiceName, COMPONENT_ENABLED_STATE_DISABLED, 0);
}

Ví dụ này cũng có thể sử dụng PackageManager.setApplicationEnabledSetting() để tắt toàn bộ ứng dụng.