SDK mạng Thread dành cho Android

SDK Mạng Thread cung cấp chức năng tương tự như một chuỗi khoá kỹ thuật số, cho phép các ứng dụng Android của bạn chia sẻ thông tin xác thực mạng Thread với Dịch vụ Google Play. Thao tác này cho phép ứng dụng của bạn thiết lập bất kỳ thiết bị Thread nào từ mọi hệ sinh thái nhà thông minh mà không trực tiếp làm lộ thông tin đăng nhập và dữ liệu người dùng.

Chỉ với một vài lệnh gọi API, bạn có thể:

  1. Yêu cầu thông tin xác thực mạng Thread ưu tiên từ Dịch vụ Google Play.
  2. Thiết lập bộ định tuyến biên mới và thêm thông tin đăng nhập mạng Thread của bạn vào Google Dịch vụ Google Play.
  3. Nếu đã có bộ định tuyến biên tại chỗ, bạn có thể kiểm tra xem đường viền của mình bộ định tuyến nằm trong mạng ưu tiên và di chuyển chúng nếu cần.

Có một số hành trình của người dùng và nhà phát triển cần xem xét. Chúng tôi sẽ đề cập đến hầu hết các tính năng này trong hướng dẫn này, cùng với các tính năng chính khác và cách sử dụng được đề xuất.

Các thuật ngữ chính và khái niệm API

Trước khi bắt đầu, bạn nên tìm hiểu các thuật ngữ sau:

  • Thông tin xác thực mạng Thread: Tệp nhị phân của các TLV Thread (Thread TLV) mã hoá Tên mạng Thread, Khoá mạng và các thuộc tính khác mà thiết bị Thread cần để tham gia một mạng Thread nhất định.

  • Thông tin đăng nhập mạng Thread ưu tiên: Mạng Thread được tự động chọn thông tin đăng nhập có thể được chia sẻ với ứng dụng của các nhà cung cấp khác nhau bằng API getPreferredCredentials.

  • Mã tác nhân đường viền: Mã nhận dạng duy nhất trên toàn cầu 16 byte cho Bộ định tuyến đường viền luồng thiết bị. Mã này do các nhà cung cấp bộ định tuyến biên tạo và quản lý.

  • Ứng dụng thiết lập bộ định tuyến đường viền luồng: Đây là ứng dụng Android giúp thiết lập các thiết bị Bộ định tuyến biên Thread mới và thêm thông tin đăng nhập mạng Thread vào Dịch vụ Google Play. Ứng dụng của bạn là chủ sở hữu có thẩm quyền của thông tin xác thực đã thêm và có quyền truy cập vào thông tin xác thực đó.

Nhiều API Mạng luồng trả về một Tác vụ hoàn tất không đồng bộ. Bạn có thể sử dụng addOnSuccessListeneraddOnFailureListener để đăng ký lệnh gọi lại nhằm nhận kết quả. Để tìm hiểu thêm, hãy tham khảo tài liệu về Tác vụ.

Quyền sở hữu và duy trì thông tin đăng nhập

Ứng dụng thêm thông tin đăng nhập mạng Thread sẽ trở thành chủ sở hữu của thông tin xác thực và có toàn quyền truy cập vào thông tin xác thực đó. Nếu bạn thử để truy cập vào thông tin xác thực do các ứng dụng khác thêm vào, bạn sẽ nhận được một PERMISSION_DENIED .

Là chủ sở hữu ứng dụng, bạn nên cập nhật thông tin xác thực được lưu trữ trong Dịch vụ Google Play khi mạng Bộ định tuyến biên Thread được cập nhật. Điều này có nghĩa là thêm thông tin xác thực khi cần, cập nhật thông tin xác thực khi thông tin xác thực mạng Thread của bộ định tuyến biên thay đổi và xoá thông tin xác thực khi Bộ định tuyến biên Thread bị xoá hoặc đặt lại về trạng thái ban đầu.

Khám phá Border Agent

Thông tin xác thực phải được lưu bằng Mã nhân viên hỗ trợ biên giới. Bạn cần đảm bảo rằng ứng dụng Thiết lập bộ định tuyến biên Thread có thể xác định mã nhận dạng của Tác nhân biên của bộ định tuyến biên Thread.

Bộ định tuyến đường viền luồng phải sử dụng mDNS để quảng cáo thông tin mạng Thread, bao gồm cả Tên mạng, Mã liên kết mở rộng và Mã nhận dạng tác nhân đường viền. Chiến lược phát hành đĩa đơn giá trị txt tương ứng cho các thuộc tính này là nn, xpid, .

Đối với các mạng có bộ định tuyến biên của Google, Dịch vụ Google Play sẽ tự động lấy thông tin đăng nhập mạng Google Thread để sử dụng.

Tích hợp SDK vào ứng dụng Android

Để bắt đầu, hãy hoàn thành các bước sau:

  1. Làm theo hướng dẫn tại bài viết Thiết lập Dịch vụ Google Play.

  2. Thêm phần phụ thuộc Dịch vụ Google Play vào tệp build.gradle:

    implementation 'com.google.android.gms:play-services-threadnetwork:16.2.1'
    
  3. Không bắt buộc: Xác định một lớp dữ liệu BorderAgent để lưu trữ thông tin về bộ định tuyến biên. Chúng ta sẽ sử dụng dữ liệu này trong suốt hướng dẫn này:

    data class BorderAgentInfo(
      // Network Name max 16 len
      val networkName: String = "",
      val extPanId: ByteArray = ByteArray(16),
      val borderAgentId: ByteArray = ByteArray(16),
      ...
    )
    

Tiếp theo, chúng ta sẽ xem xét các bước đề xuất để thêm và quản lý lựa chọn ưu tiên thông tin xác thực.

Thiết lập bộ định tuyến biên mới

Trước khi tạo một mạng mới cho bộ định tuyến biên mới, bạn cần mà bạn thử sử dụng thông tin đăng nhập mạng ưu tiên trước tiên. Điều này đảm bảo rằng Các thiết bị Thread được kết nối với một mạng Thread khi có thể.

Lệnh gọi đến getPreferredCredentials sẽ khởi chạy một Hoạt động, nhắc người dùng cho phép yêu cầu mạng. Nếu thông tin xác thực mạng đã được lưu trữ trong chuỗi khoá kỹ thuật số của SDK Luồng, thì thông tin xác thực sẽ được trả về ứng dụng của bạn.

Yêu cầu thông tin xác thực

Cách nhắc người dùng cung cấp thông tin đăng nhập ưu tiên:

  1. Khai báo ActivityLauncher:

    private lateinit var preferredCredentialsLauncher: ActivityResultLauncher<IntentSenderRequest>
    
  2. Xử lý kết quả Hoạt động, được trả về dưới dạng ThreadNetworkCredentials:

    preferredCredentialsLauncher =
     registerForActivityResult(
       StartIntentSenderForResult()
     ) { result: ActivityResult ->
       if (result.resultCode == RESULT_OK) {
         val threadNetworkCredentials = ThreadNetworkCredentials.fromIntentSenderResultData(result.data!!)
         Log.d("debug", threadNetworkCredentials.networkName)
       } else {
         Log.d("debug", "User denied request.")
       }
     }
    
  3. Nếu đang thiết lập một Bộ định tuyến biên luồng mới, bạn nên gọi preferredCredentials và khởi chạy Hoạt động. Cuộc gọi này sẽ đảm bảo rằng Bộ định tuyến đường viền luồng mới của bạn sẽ sử dụng chính thông tin đăng nhập đã lưu trữ được ưu tiên trong điện thoại, thúc đẩy sự hội tụ của các TBR khác nhau thành cùng một mạng.

    private fun getPreferredThreadNetworkCredentials() {
      ThreadNetwork.getClient(this)
        .preferredCredentials
      .addOnSuccessListener { intentSenderResult ->
        intentSenderResult.intentSender?.let {
          preferredCredentialsLauncher.launch(IntentSenderRequest.Builder(it).build())
          } ?: Log.d("debug", "No preferred credentials found.")
        }
      .addOnFailureListener { e: Exception -> Log.d(TAG, "ERROR: [${e}]") }
    }
    
  4. Nếu trường hợp sử dụng của bạn liên quan đến việc thiết lập thiết bị không phải TBR, chẳng hạn như Thiết bị cuối theo chuẩn Matter-over-Thread, bạn nên sử dụng allActiveCredentials api để tìm nạp thông tin xác thực. Cuộc gọi này sẽ quét tìm TBR được tìm thấy trong máy chủ và do đó sẽ không trả về thông tin xác thực mà TBR hiện có cục bộ.

    // Creates the IntentSender result launcher for the getAllActiveCredentials API
    private val getAllActiveCredentialsLauncher =
      registerForActivityResult(
        StartIntentSenderForResult()
      ) { result: ActivityResult ->
        if (result.resultCode == RESULT_OK) {
          val activeCredentials: List<ThreadNetworkCredentials> =
            ThreadNetworkCredentials.parseListFromIntentSenderResultData(
              result.data!!
            )
          // Use the activeCredentials list
        } else {
          // The user denied to share!
        }
      }
    
    // Invokes the getAllActiveCredentials API and starts the dialog activity with the returned
    // IntentSender
    threadNetworkClient
    .getAllActiveCredentials()
    .addOnSuccessListener { intentSenderResult: IntentSenderResult ->
      val intentSender = intentSenderResult.intentSender
      if (intentSender != null) {
        getAllActiveCredentialsLauncher.launch(
          IntentSenderRequest.Builder(intentSender).build()
        )
      } else {
        // No active network credentials found!
      }
    }
    // Handles the failure
    .addOnFailureListener { e: Exception ->
      // Handle the exception
    }
    

Tạo mạng Thread mới

Nếu không có thông tin xác thực mạng Thread ưu tiên cũng như luồng đang hoạt động có sẵn trong thông tin đăng nhập của người dùng Mạng Thread, sau đó bạn có thể sử dụng API addCredentials để thêm thông tin đăng nhập vào Dịch vụ Google Play. Để thực hiện việc này, bạn cần tạo một ThreadBorderAgent và cung cấp một đối tượng ThreadNetworkCredentials.

Để tạo một mạng ngẫu nhiên, hãy gọi newRandomizeBuilder:

val threadCredentials = ThreadNetworkCredentials.newRandomizedBuilder().build()

Cách chỉ định Tên mạng Thread:

val threadCredentials = ThreadNetworkCredentials.newRandomizedBuilder()
  .setNetworkName("ThreadNetworkSDK")
  .build()

Thêm thông tin xác thực

Để cung cấp thông tin đăng nhập mạng Thread của bạn cho các nhà cung cấp Thread khác, chúng tôi cần thêm chúng vào Dịch vụ Google Play. Trước khi có thể thêm thông tin xác thực mới, chúng ta cũng cần biết mạng Thread này thuộc về thiết bị bộ định tuyến biên nào.

Trong ví dụ này, chúng ta sẽ tạo một ThreadBorderAgent từ một Border Agent ID (Mã nhân viên hỗ trợ biên giới) và truyền thông tin đăng nhập mạng Thread mới mà bạn vừa tạo:

private fun addCredentials(borderAgentInfo: BorderAgentInfo, credentialsToBeAdded: ThreadNetworkCredentials) {

  val threadBorderAgent = ThreadBorderAgent.newBuilder(borderAgentInfo.borderAgentId).build()
  Log.d("debug", "border router id:" + threadBorderAgent.id)

  ThreadNetwork.getClient(this)
    .addCredentials(threadBorderAgent, credentialsToBeAdded)
      .addOnSuccessListener {
        Log.d("debug", "Credentials added.")
      }
      .addOnFailureListener { e: Exception -> Log.d(TAG, "ERROR: [${e}]") }
}

Phát hiện và di chuyển bộ định tuyến biên tại trường

Nếu hiện có bộ định tuyến biên trong trường, bạn có thể sử dụng isPreferredCredentials để xác định xem bộ định tuyến biên có thuộc mạng ưu tiên hay không. API này không nhắc người dùng cấp quyền và kiểm tra thông tin xác thực của bộ định tuyến biên giới với thông tin được lưu trữ trong Dịch vụ Google Play.

isPreferredCredentails trả về 0 cho giá trị không khớp và 1 cho giá trị khớp, dưới dạng loại dữ liệu Int. Bạn có thể dùng IsPreferredCredentialsResult để kiểm tra kết quả.

public @interface IsPreferredCredentialsResult {
    int PREFERRED_CREDENTIALS_NOT_FOUND = -1;
    int PREFERRED_CREDENTIALS_NOT_MATCHED = 0;
    int PREFERRED_CREDENTIALS_MATCHED = 1;
}

Để sử dụng isPreferredCredentials, bạn cần tạo một đối tượng ThreadNetworkCredentials trước tiên. Có một số cách để tạo bản sao ThreadNetworkCredentials. Trong các bước tiếp theo, chúng ta sẽ tìm hiểu về các tuỳ chọn này.

Tạo chuỗi thông tin xác thực mạng theo Tập dữ liệu hoạt động

Có những trường hợp mà Bộ định tuyến đường viền luồng của bạn đã được thiết lập bằng Mạng Thread và bạn muốn thêm mạng Thread này vào Dịch vụ Google Play để chia sẻ với các nhà cung cấp khác. Bạn có thể tạo một thực thể ThreadNetworkCredential từ danh sách TLV Dữ liệu hoạt động đang hoạt động của luồng thô:

  1. Chuyển đổi Tập dữ liệu hoạt động thành ByteArray. Ví dụ:

    val activeDataset =
          "0e080000000000010000000300000f35060004001fffe0020833333333...".dsToByteArray()
    
    fun String.dsToByteArray(): ByteArray {
      return chunked(2).map { it.toInt(16).toByte() }.toByteArray()
    }
    
  2. Sử dụng fromActiveOperationalDataset để tạo ThreadNetworkCredentials. Khi thành công, bạn sẽ có thể nhận được Tên mạng Thread, Kênh và các thông tin khác về mạng. Để biết danh sách đầy đủ các thuộc tính, hãy tham khảo ThreadNetworkCredentials.

    val threadNetworkCredentials =
        ThreadNetworkCredentials.fromActiveOperationalDataset(activeDataset)
    Log.d(
        "threadNetworkCredentials",
        threadNetworkCredentials.channel.toString() + " - " + threadNetworkCredentials.networkName)
    
  3. Gọi API isPreferredCredentials và chuyển thông số ThreadNetworkCredentials.

    ThreadNetwork.getClient(this)
    .isPreferredCredentials(threadNetworkCredentials)
    .addOnSuccessListener { result ->
      when (result) {
        IsPreferredCredentialsResult.PREFERRED_CREDENTIALS_NOT_MATCHED ->
            Log.d("isPreferredCredentials", "Credentials not matched.")
        IsPreferredCredentialsResult.PREFERRED_CREDENTIALS_MATCHED ->
            Log.d("isPreferredCredentials", "Credentials matched.")
      }
    }
    .addOnFailureListener { e: Exception -> Log.d("isPreferredCredentials", "ERROR: [${e}]") }
    

Tạo chuỗi thông tin xác thực mạng do Border Agent thực hiện

Mã nhận dạng của tác nhân biên giới xác định riêng một thiết bị bộ định tuyến biên giới. Để sử dụng getCredentialsByBorderAgent API. Trước tiên, bạn cần tạo một ThreadBorderAgent rồi truyền mã nhận dạng tác nhân đường biên (Border Agent ID).

Sau khi bạn tạo đối tượng ThreadBorderAgent, hãy gọi getCredentialsByBorderAgent. Nếu thông tin xác thực đã được lưu, hãy kiểm tra để xem nếu họ được ưu tiên sử dụng.

private fun isPreferredThreadNetworkByBorderAgent(borderAgentInfo: BorderAgentInfo) {

  val threadBorderAgent = ThreadBorderAgent.newBuilder(borderAgentInfo.borderAgentId).build()
  Log.d("debug", "border router id:" + threadBorderAgent.id)

  var isPreferred = IsPreferredCredentialsResult.PREFERRED_CREDENTIALS_NOT_FOUND
  var borderAgentCredentials: ThreadNetworkCredentials?
  val taskByBorderAgent = ThreadNetwork.getClient(this)
  taskByBorderAgent
      .getCredentialsByBorderAgent(threadBorderAgent)
      .addOnSuccessListener { result: ThreadNetworkCredentialsResult ->
        borderAgentCredentials = result.credentials
        result.credentials?.let {
          taskByBorderAgent.isPreferredCredentials(it).addOnSuccessListener { result ->
            isPreferred = result
          }
        }
      }
      .addOnFailureListener { e: Exception -> Log.d(TAG, "ERROR: [${e}]") }
}

Thông tin đăng nhập mạng Thread theo Mã nhận dạng thẻ và phương tiện mở rộng

Tương tự như getPreferredCredentials, bạn cũng có thể nhắc người dùng nhập thông tin xác thực từ Mã nhận dạng mở rộng của bộ định tuyến biên. getCredentialsByExtendedPanId trả về một IntentSender và kết quả Hoạt động chứa một đối tượng ThreadNetworkCredentials khi người dùng phê duyệt.

private fun getCredentialsByExtPanId(borderAgentInfo: BorderAgentInfo) {
  ThreadNetwork.getClient(this)
    .getCredentialsByExtendedPanId(borderAgentInfo.extPanId)
    .addOnSuccessListener { intentSenderResult ->
      intentSenderResult.intentSender?.let {
        preferredCredentialsLauncher.launch(IntentSenderRequest.Builder(it).build())
      }
        ?: Log.d("debug", "No credentials found.")
    }
    .addOnFailureListener { e: Exception -> Log.d(TAG, "ERROR: [${e}]") }
}

Xoá thông tin đăng nhập

Khi thiết bị Border Router bị xoá khỏi nhà hoặc bị đặt lại về trạng thái ban đầu, bạn cần xoá mạng Thread khỏi Dịch vụ Google Play.

private fun removeCredentials(borderAgentInfo: BorderAgentInfo) {

  val threadBorderAgent = ThreadBorderAgent.newBuilder(borderAgentInfo.borderAgentId).build()
  Log.d("debug", "border router id:" + threadBorderAgent.id)

  ThreadNetwork.getClient(this)
      .removeCredentials(threadBorderAgent)
      .addOnSuccessListener { Log.d("debug", "Credentials removed.") }
      .addOnFailureListener { e: Exception -> Log.d(TAG, "ERROR: [${e}]") }
}

Tài nguyên

Để tìm hiểu thêm về Thread Network SDK, hãy tham khảo Tài liệu tham khảo API.