Permissions API trên Android

Trước khi sử dụng bất kỳ API Home nào cho Android, ứng dụng phải có quyền truy cập vào các thiết bị trong nhà của người dùng, được gọi trong API là cấu trúc. Với Permissions API, người dùng có thể sử dụng Tài khoản Google của mình để cấp cho các ứng dụng API Home quyền truy cập vào các thiết bị trong nhà.

Quy trình cấp quyền cho phép người dùng tạo một nhà và chỉ định địa chỉ đường phố của nhà đó nếu chưa được thiết lập, mà không cần sử dụng Google Home app (GHA).

Tích hợp Permissions API

Trước khi tiếp tục, hãy đảm bảo bạn đã làm theo hướng dẫn trong phần Khởi động Nhà trên Android. Thực thể homeManager từ bước đó được dùng trong tất cả ví dụ về Quyền tại đây.

Trước tiên, hãy đăng ký ActivityResultCaller với SDK. Ví dụ: đây là cách Ứng dụng mẫu xử lý:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    homeManager.registerActivityResultCallerForPermissions(this)
  }

Kiểm tra quyền

Trước khi yêu cầu cấp quyền, bạn nên kiểm tra xem người dùng ứng dụng đã đồng ý cấp quyền truy cập vào cấu trúc hay chưa. Để làm việc này, hãy gọi phương thức hasPermissions() của thực thể Home để lấy Flow của các giá trị PermissionsState:

val permissionsReadyState =
homeManager.hasPermissions().collect { state ->
    when (state) {
      PermissionsState.GRANTED -> println("Permissions granted, no need to request permissions")
      PermissionsState.PERMISSIONS_STATE_UNAVAILABLE ->
          println("Permissions state unavailable, request permissions")

      PermissionsState.NOT_GRANTED ->
          println("OAuth permission is enabled but not granted yet, request permissions")

      PermissionsState.PERMISSIONS_STATE_UNINITIALIZED -> println(
          "Permissions state is not initialized yet. Clients should wait for another status update"
      )
      else ->
          throw IllegalStateException("""
            HomeClient.hasPermissions state should be PermissionsState.GRANTED,
            PermissionState.PERMISSIONS_STATE_UNINITIALIZED, or
            PermissionsState.PERMISSIONS_STATE_UNAVAILABLE. Actual state: $state
          """.trimIndent())
    }
}

Nếu quy trình kiểm tra trả về PermissionsState là NOT_GRANTED hoặc PERMISSIONS_STATE_UNAVAILABLE, thì tức là người dùng hoặc ứng dụng không có quyền truy cập vào cấu trúc. Nếu kết quả kiểm tra trả về PermissionsState là GRANTED nhưng lệnh gọi tiếp theo đến structures() không trả về cấu trúc nào, thì có thể người dùng đã thu hồi quyền truy cập vào ứng dụng thông qua trang cài đặt GHA hoặc người dùng không có quyền truy cập cần thiết.

Yêu cầu cấp quyền

Ứng dụng của bạn phải được cấp quyền để truy cập vào nhà và thiết bị trong một nhà nhất định.

Nếu người dùng chưa cấp quyền, hãy sử dụng phương thức requestPermissions() của thực thể Home để chạy giao diện người dùng Quyền và xử lý kết quả:

fun requestPermissions(scope: CoroutineScope, onShowSnackbar: (String) -> Unit) {
  scope.launch {
    val result =
      try {
        homeManager.requestPermissions()
      } catch (e: HomeException) {
        PermissionsResult(
          PermissionsResultStatus.ERROR,
          "Got HomeException with error: ${e.message}",
        )
      }
    when (result.status) {
      PermissionsResultStatus.SUCCESS -> {
        Log.i(TAG, "Permissions successfully granted.")
      }
      PermissionsResultStatus.CANCELLED -> {
        Log.i(TAG, "User cancelled Permissions flow.")
        onShowSnackbar("User cancelled Permissions flow")
      }
      else -> {
        Log.e(
          TAG,
          "Failed to grant permissions with error: ${result.status}, ${result.errorMessage}",
        )
        onShowSnackbar("Failed to grant permissions with error: ${result.errorMessage}")
      }
    }
  }
}

Để giao diện người dùng về quyền chạy đúng cách, bạn phải thiết lập OAuth cho ứng dụng của mình.

Giao diện người dùng đồng ý cấp quyền sẽ hiển thị theo ngôn ngữ được định cấu hình bằng HomeClient.setLocale() hoặc mặc định theo ngôn ngữ của ứng dụng hoặc thiết bị nếu bạn không đặt ngôn ngữ. Để hiển thị màn hình xin phép bằng một ngôn ngữ cụ thể, hãy gọi setLocale() trên thực thể HomeClient trước khi gọi requestPermissions(). Để biết thêm thông tin, hãy xem bài viết Định cấu hình ngôn ngữ của ứng dụng.

Cấp quyền

Bây giờ, bạn có thể chạy ứng dụng và yêu cầu người dùng cấp quyền. Loại người dùng có thể cấp quyền và loại thiết bị có thể cấp quyền sẽ khác nhau tuỳ thuộc vào việc bạn đã đăng ký ứng dụng của mình trong Google Home Developer Console hay chưa.

Bạn cần đăng ký Developer Console để xuất bản ứng dụng bằng các API cho Home. Bạn không bắt buộc phải kiểm thử và sử dụng các API cho Home.

Nếu một ứng dụng không được đăng ký trong Developer Console, thì ứng dụng đó sẽ ở trạng thái chưa được xác minh. Bạn nên dùng cách này để thử nghiệm việc sử dụng Home API:

  • Chỉ những người dùng đã đăng ký làm người dùng thử nghiệm trong bảng điều khiển OAuth mới có thể cấp quyền cho ứng dụng. Có giới hạn 100 người dùng thử nghiệm cho một ứng dụng chưa được xác minh.

  • Một ứng dụng chưa được xác minh sẽ có quyền truy cập vào các thiết bị thuộc bất kỳ loại thiết bị nào được OAuth hỗ trợ cho Home API (danh sách các loại thiết bị trong Developer Console). Tất cả thiết bị trong một nhà đều sẽ được cấp quyền.

Nếu một ứng dụng được đăng ký trong Developer Console và đã được phê duyệt để truy cập vào một hoặc nhiều loại thiết bị, đồng thời quy trình xác minh thương hiệu đã hoàn tất cho OAuth, thì ứng dụng đó sẽ ở trạng thái đã xác minh. Bạn cần có trạng thái này để phát hành ứng dụng lên kênh phát hành công khai:

  • Hạn mức người dùng thử nghiệm không còn áp dụng nữa. Bất kỳ người dùng nào cũng có thể cấp quyền cho ứng dụng.
  • Người dùng chỉ có thể cấp quyền cho các loại thiết bị đã được phê duyệt trong Developer Console.

Sau khi thiết lập OAuth, lệnh gọi của ứng dụng đến requestPermissions() sẽ kích hoạt các hộp thoại sau:

  1. Người dùng sẽ được nhắc chọn Tài khoản Google mà họ muốn sử dụng.
  2. Người dùng được nhắc chọn cấu trúc mà họ muốn cấp quyền truy cập cho ứng dụng.
    1. Đối với ứng dụng chưa được xác minh, tất cả loại thiết bị mà các API cho Home hỗ trợ đều có thể dùng được cho ứng dụng đó.
    2. Đối với ứng dụng đã xác minh, người dùng chỉ có thể cấp quyền cho những loại thiết bị đã được phê duyệt trong Developer Console.
    3. Đối với các loại thiết bị nhạy cảm mà ứng dụng có quyền quản lý, người dùng có thể hạn chế quyền truy cập theo từng thiết bị. Ví dụ: nếu người dùng có ba khoá, thì họ chỉ có thể cấp quyền truy cập vào một trong ba khoá đó.
  • Đồng ý OAuth – chọn tài khoản
  • OAuth consent - link devices 01
  • OAuth consent - link device 02
Hình 1: Ví dụ về quy trình đồng ý OAuth

Sau khi được cấp quyền, ứng dụng có thể sử dụng các API cho Home để đọc trạng thái và điều khiển các thiết bị trong nhà. Nếu người dùng không cấp quyền cho ứng dụng đối với một loại thiết bị cụ thể hoặc thiết bị nhạy cảm, thì ứng dụng sẽ không thể sử dụng các API cho Home để truy cập, điều khiển hoặc tự động hoá thiết bị đó.

Thay đổi quyền

Để cấp quyền truy cập vào các thiết bị trong một cấu trúc khác, bạn có thể chạy bộ chọn tài khoản để cho phép người dùng chọn Tài khoản Google và cấu trúc cần chuyển sang. Trong quá trình này, người dùng sẽ thấy màn hình xin phép một lần nữa, ngay cả khi họ đã đồng ý trước đó.

Bạn có thể thực hiện việc này bằng cách gọi lại requestPermissions() với forcePermissionFlow được đặt thành ForcePermissionFlow.FORCE_LAUNCH:

homeManager.requestPermissions(forcePermissionFlow = ForcePermissionFlow.FORCE_LAUNCH)

Thay đổi quyền bằng tính năng gợi ý cấu trúc nhà

Tính năng gợi ý cấu trúc nhà cho phép ứng dụng chọn trước một cấu trúc cụ thể hoặc hạn chế danh sách các cấu trúc có sẵn khi yêu cầu thay đổi gia tăng đối với quyền của người dùng đối với các API cho Home. Bằng cách truyền các tham số cấu trúc vào yêu cầu uỷ quyền, hộp thoại quyền sẽ tự động tập trung vào cấu trúc đã chọn, giảm sự phiền hà cho người dùng và ngăn ngừa lỗi cấu hình.

Tính năng gợi ý cấu trúc nhà được quản lý bằng lớp dữ liệu ConsentScreenOptions. Lớp ConsentScreenOptions chấp nhận các tham số cấu hình sau:

  • structureId — Mã nhận dạng cấu trúc cụ thể để chọn trước trong hộp thoại cấp quyền. Bạn có thể lấy thông tin này bằng cách kiểm tra thuộc tính của nhà cho nhà đang được cập nhật.
  • allowedStructureIds — Danh sách mã cấu trúc. Nếu được cung cấp, hộp thoại cấp quyền sẽ lọc các cấu trúc có sẵn để chỉ hiển thị những cấu trúc trong danh sách này. Bạn có thể không chỉ định thông tin này trong hầu hết các trường hợp, trừ phi bạn muốn đảm bảo người dùng chỉ có thể truy cập vào danh sách cấu trúc đã được cấp quyền.
  • allowStructureChange — Xác định xem người dùng có được phép thay đổi cấu trúc đã chọn trước hay không. Đặt giá trị này thành true nếu bạn chỉ định ít nhất một trong hai thuộc tính allowedStructureIds và structureId trong hầu hết các trường hợp để hỗ trợ hành vi tự nhiên cho người dùng.

Truyền đối tượng này dưới dạng tham số không bắt buộc trong lệnh gọi requestPermissions(), với forcePermissionFlow được đặt thành ForcePermissionFlow.FORCE_LAUNCH:

import com.google.home.ConsentScreenOptions

// Create the ConsentScreenOptions class, allowing structure changes while
// ensuring the permissions dialog pre-selects the target structure on launch
val consentOptions = ConsentScreenOptions(
    structureId = target-structure-id,
    allowStructureChange = true
)

homeManager.requestPermissions(forcePermissionFlow = ForcePermissionFlow.FORCE_LAUNCH, consentScreenOptions = consentOptions)

Người dùng sẽ thấy màn hình xin phép đã được lọc theo cấu trúc được ghi chú trong đối tượng ConsentScreenOptions.

Cho phép người dùng chuyển đổi nhà bằng tính năng gợi ý nhà

Nếu người dùng có nhiều nhà trong một ứng dụng và bạn muốn chọn trước một nhà trong khi vẫn cho phép họ chuyển đổi giữa các nhà hiện có, hãy bật tính năng thay đổi nhà bằng cờ allowStructureChange và cung cấp danh sách nhà trong allowedStructureIds:

val consentOptions = ConsentScreenOptions(
    structureId = target-structure-id,
    allowedStructureIds = listOf(target-structure-id, another-structure-id),
    allowStructureChange = true
)

Thu hồi quyền

Người dùng có thể thu hồi quyền truy cập đã cấp trước đó:

  1. Thông qua phần Cài đặt Tài khoản Google > Dữ liệu và quyền riêng tư > Ứng dụng và dịch vụ bên thứ ba. Thao tác này sẽ thu hồi mã thông báo OAuth được cấp khi người dùng đồng ý lần đầu, đồng thời sẽ thu hồi quyền truy cập vào mọi phiên bản của ứng dụng mà người dùng đang sử dụng trên tất cả các nền tảng (điện thoại) và cấu trúc.

    Người dùng có thể được chuyển hướng bằng một đường liên kết sâu đến trang con Ứng dụng và dịch vụ bên thứ ba bằng lược đồ URL sau:

    https://myaccount.google.com/connections/link?project_number=Cloud project_number
    
  2. Thông qua trang GHA > Cài đặt > Ứng dụng đã liên kết. Khi nhấp vào trong GHA, bạn sẽ được chuyển đến trang Cài đặt. Tại đây, hãy nhấp vào ô Ứng dụng đã liên kết để chuyển đến một trang có giao diện tương tự như màn hình xin phép. Trên trang này, người dùng có thể xoá quyền truy cập vào ứng dụng. Người dùng có thể sử dụng chính trang này để thay đổi loại thiết bị hoặc thiết bị nhạy cảm cụ thể mà ứng dụng có thể truy cập.

Xoá và xuất dữ liệu người dùng

Nền tảng này tự động quản lý việc xoá dữ liệu phụ trợ khi người dùng xoá Tài khoản Google của họ hoặc rời khỏi một cấu trúc:

  • Nếu người dùng bị xoá là chủ sở hữu duy nhất của một công trình, thì nền tảng sẽ xoá công trình đó và các mối liên kết thiết bị của công trình.
  • Nếu các chủ sở hữu khác vẫn ở trong một nhà dùng chung, thì nhà đó và các thiết bị dùng chung trong nhà đó vẫn được giữ lại cho những thành viên còn lại. Nền tảng này sẽ xoá tư cách thành viên của người dùng đã rời đi và huỷ liên kết mọi thiết bị Cloud-to-cloud của bên thứ ba chỉ được kết nối thông qua thông tin đăng nhập của người dùng đó.
  • Việc xoá tài khoản sẽ ngay lập tức và vĩnh viễn xoá dữ liệu cấu trúc và quyền truy cập ứng dụng của người dùng. Ngay cả khi người dùng khôi phục Tài khoản Google của họ sau đó, thì cấu trúc và quyền của họ cũng không được khôi phục.

Các API cho Home không cung cấp điểm cuối để xuất hoặc xoá dữ liệu trong Tài khoản Google của người dùng. Hướng dẫn người dùng có Tài khoản Google truy cập vào Google Takeout để xuất dữ liệu của họ trên Google Home và truy cập vào phần cài đặt Tài khoản Google để quản lý việc xoá tài khoản.

Trong hệ sinh thái Google Home, đối với hầu hết các loại thiết bị, người dùng có thể cấp quyền cho tất cả thiết bị thuộc loại đó cùng một lúc. Đối với các loại thiết bị nhạy cảm hoặc bị hạn chế, chẳng hạn như khoá, camera hoặc chuông cửa, người dùng phải cấp quyền riêng cho từng thiết bị.

Để xác định xem người dùng đã cấp quyền truy cập vào một loại thiết bị nhạy cảm hoặc bị hạn chế hay chưa, hãy sử dụng hàm consentedDeviceTypes() ở cấp Cấu trúc:

import com.google.home.Structure
import com.google.home.DeviceType
import com.google.home.DeviceTypeFactory
import com.google.home.consentedDeviceTypes // Extension function from the SDK
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch

/**
 * Example of how an app may monitor which device types have been granted access by a user.
 */
fun monitorDeviceConsent(structure: Structure, myScope: CoroutineScope) {
    // Obtain the flow of consented device type factories
    val consentedTypesFlow: Flow<Set<DeviceTypeFactory<out DeviceType>>> =
        structure.consentedDeviceTypes()

    myScope.launch {
        consentedTypesFlow.collect { consentedSet ->
            // Check if the user has consented to share a specific restricted
            // type, such as a Doorbell or Camera.
            val hasCameraAccess = consentedSet.any {
                it.toString() == "matter.google.type.GoogleDoorbellDevice"
            }

            if (hasCameraAccess) {
                // Enable features that require camera access
            } else {
                // Inform the user or disable camera-specific features
            }
        }
    }
}

Quyền truy cập của OkGoogle

Lệnh okGoogle là lệnh ở cấp thiết bị và có thể dùng để tự động hoá mọi thiết bị trong cấu trúc. Tuy nhiên, một ứng dụng Home API có thể không có quyền truy cập vào mọi thiết bị. Bảng sau đây mô tả cách thực thi quyền trong những trường hợp như vậy.

Tự động hóa Đặc điểm Thực thi quyền
Lúc 10 giờ tối, hãy phát đi thông báo "Giờ đi ngủ" trên loa phòng ngủ. AssistantBroadcastTrait trên thiết bị. Tạo quy trình tự động hoá:
  • Thiết bị phát phải là thiết bị có Trợ lý.
  • Ứng dụng và người dùng phải có quyền truy cập vào thiết bị mà chương trình phát sóng diễn ra.
Thực thi quy trình tự động hoá:
  • Ứng dụng và người dùng phải có quyền truy cập vào thiết bị mà chương trình phát sóng diễn ra.
Lúc 10:00 tối, hãy phát đi thông báo "Đến giờ đi ngủ" trên tất cả các thiết bị AssistantBroadcastTrait về cấu trúc. Tạo quy trình tự động hoá:
  • Phải có ít nhất một thiết bị có Trợ lý trong cấu trúc mà ứng dụng và người dùng có quyền truy cập.
  • Ứng dụng và người dùng phải có quyền truy cập vào nhà.
Thực thi quy trình tự động hoá:
  • Ứng dụng và người dùng phải có quyền truy cập vào nhà.
"Phát nhạc" lúc 10 giờ tối AssistantFulfillmentTrait.OkGoogleCommand Tạo quy trình tự động hoá:
  • Ứng dụng và người dùng phải có quyền truy cập vào các thiết bị mà quy trình tự động hoá đưa ra lệnh.
Thực thi quy trình tự động hoá:
  • Ứng dụng và người dùng phải có quyền truy cập vào các thiết bị mà quy trình tự động hoá đưa ra lệnh.
Bất cứ khi nào có người nói "phát nhạc" VoiceStarterTrait.OkGoogleEvent Tạo quy trình tự động hoá:
  • Ứng dụng và người dùng phải có quyền truy cập vào cấu trúc. Một quy trình tự động hoá không yêu cầu thiết bị có Trợ lý phải vượt qua quy trình xác thực hoặc chạy, vì bất kỳ người dùng nào có quyền truy cập vào cấu trúc đều có thể sử dụng điện thoại của họ (bằng cùng một Tài khoản Google) để tương tác với Trợ lý và kích hoạt VoiceStarter.
Thực thi quy trình tự động hoá:
  • Ứng dụng không cần quyền truy cập vào thiết bị bắt đầu quy trình tự động hoá.
  • Ứng dụng và người dùng phải có quyền truy cập vào thiết bị nơi hành động xảy ra.

Hướng dẫn trong trường hợp người dùng thu hồi toàn quyền

Nếu người dùng thu hồi toàn quyền, thì tất cả quy trình tự động hoá hiện có sẽ ngừng hoạt động. Ngoài ra, nếu người dùng thu hồi quyền truy cập vào các thiết bị cụ thể, thì các điều kiện khởi động, điều kiện và hành động liên quan đến các thiết bị đó sẽ ngừng hoạt động.

Mỗi lần ứng dụng khởi động, hãy nhớ kiểm tra để đảm bảo các quyền vẫn còn hiệu lực. Nếu các quyền này đã bị thu hồi, hãy đảm bảo rằng tất cả dữ liệu trước đó đều bị xoá, bao gồm cả mọi dữ liệu được lưu vào bộ nhớ đệm trong ứng dụng.

Khi quyền truy cập vào nhà bị thu hồi, một StructureAccessRevokedEvent sẽ được gửi đến phần phụ trợ trên đám mây của bạn. Tham khảo bài viết Cấp quyền truy cập vào cấu trúc để biết quy trình thu hồi quyền truy cập vào ứng dụng di động và đám mây của đối tác từ đầu đến cuối.