Xây dựng ứng dụng dành cho 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 trên thiết bị đó phải: biết về những người dùng riêng biệt này.

Một số ứng dụng cần phải có một số thành phần chạy dưới dạng singleton và có thể chấp nhận các 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
  • Phân xử một hoặc nhiều tài nguyên dùng chung giữa những người dùng
  • Giảm mức hao tổn mạng bằng cách sử dụng một kết nối máy chủ duy nhất

Hãy xem biểu đồ dưới đây để biết thông tin mô tả quy trình cấp quyền cho nhiều người dùng.

Quy trình cấp quyền cho 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ụ của bạn. trình nhận hoặc trình cung cấp nào trong tệp kê khai Android.

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

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

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

Đặt quyền

Đây là những quyền bắt buộc

INTERACT_ACROSS_USERS (signature|system)
INTERACT_ACROSS_USERS_FULL (signature)

Sử dụng API

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

  1. Trích xuất tên người dùng từ các lệnh gọi đến Binder:
    • 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 trên một người dùng:
    • 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 tục tĩu hoặc một trong những 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 đến 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 bạn: (INTERACT_ACROSS_USERS) Hoặc với các thành phần trong ứng dụng khác: (INTERACT_ACROSS_USERS_FULL)
  4. Bạn có thể cần phải 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 tuần hoàn tương ứng với tên người dùng.
    • UserManager.getUserHandle(int serialNumber)
    • UserManager.getUserProfiles() – trả về tập hợp các hồ sơ chính bạn và hồ sơ được quản lý, nếu có.
  6. Đăng ký để nghe cụ thể hoặc tất cả người dùng và các lệnh gọi lại với API mới trên ContentObserver, PackageMonitor, BroadcastReceiver cung cấp thêm thông tin về người dùng nào đã 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 phiên bản trong một hồ sơ công việc hoặc người dùng khác. Nếu dịch vụ hệ thống của bạn chỉ cần chạy với tư cách người dùng 0, vô hiệu hoá 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 toàn tài nguyên. Ví dụ sau cho thấy cách bạn có thể thực hiện việc này tại mục nhập của dịch vụ điểm:

// 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() để vô hiệu hoá toàn bộ ứng dụng.