SDK mạng Thread cho Android

SDK của Thread (mạng) chuỗi cung cấp chức năng tương tự như 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 đăng nhập của mạng Thread với Dịch vụ Google Play. Điều này cho phép các ứng dụng của bạn thiết lập bất kỳ thiết bị Luồng nào từ bất kỳ hệ sinh thái nhà thông minh nào mà không tiết lộ thông tin xác thực và dữ liệu người dùng trực tiếp.

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 ưu tiên của luồng 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 Dịch vụ Google Play.
  3. Nếu đã có bộ định tuyến biên tại hiện trường, bạn có thể kiểm tra xem bộ định tuyến biên có nằm trong mạng ưu tiên hay không và di chuyển 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ẽ trình bày hầu hết các nội dung đó 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 đề xuất.

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

Trước khi bắt đầu, bạn cần nắm rõ những thuật ngữ sau:

  • Thông tin đăng nhập mạng luồng: blob nhị phân của TLV luồng (thread TLV) để mã hoá Tên mạng luồng, Khoá mạng và các thuộc tính khác mà thiết bị Luồng yêu cầu để tham gia một mạng Luồng nhất định.

  • Ưu tiên thông tin đăng nhập vào mạng chuỗi ưu tiên: Thông tin xác thực mạng luồng tự động được chọn có thể chia sẻ với các ứng dụng của nhiều nhà cung cấp bằng cách sử dụng API getPreferredCredentials.

  • Border Agent ID: Mã nhận dạng duy nhất toàn cầu 16 byte cho thiết bị Bộ định tuyến biên của luồng. Mã này do nhà cung cấp bộ định tuyến biên giới 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 đường viền mới và thêm thông tin đăng nhập vào mạng Thread vào các dịch vụ của 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 được thêm và có quyền truy cập vào đó.

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

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

Ứng dụng thêm bằng chứng xác thực mạng luồng trở thành chủ sở hữu bằng chứng xác thực và có toàn quyền truy cập thông tin xác thực. Nếu cố gắng truy cập vào thông tin đăng nhập do các ứng dụng khác thêm, bạn sẽ gặp lỗi 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 lưu trữ trong Dịch vụ Google Play khi mạng Bộ định tuyến đường viền luồng đượ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 đăng nhập mạng Thread của bộ định tuyến thay đổi và xoá thông tin xác thực khi Thread Border Router bị xoá hoặc đặt lại về trạng thái ban đầu.

Phát hiện tác nhân biên giới

Thông tin xác thực phải được lưu bằng ID tác nhân 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 của luồng có thể xác định Mã tác nhân biên giới của các 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 Tên mạng, Mã Pan mở rộng và Mã tác nhân biên giới. Giá trị txt tương ứng cho các thuộc tính này lần lượt 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 của bạn

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

  1. Làm theo hướng dẫn trong 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.0.0'
    
  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 tôi 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 qua các bước được đề xuất để thêm và quản lý bằng chứng xác thực ưa thích.

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 nên dùng thông tin xác thực mạng ưu tiên trước. Điều này đảm bảo rằng các thiết bị luồng được kết nối với một mạng luồng duy nhất 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ố SDK Thread, thì thông tin xác thực sẽ được trả về ứng dụng.

Yêu cầu thông tin đăng nhập

Để nhắc người dùng về 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. Gọi preferredCredentials và chạy Hoạt độ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}]") }
    }
    

Tạo mạng Chuỗi mới

Nếu không có thông tin xác thực mạng ưu tiên trong Mạng luồng của người dùng, thì 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 ThreadBorderAgent, đồng thời cung cấp đối tượng ThreadNetworkCredentials.

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

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

Để chỉ định Tên mạng chuỗi:

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

Thêm thông tin đăng nhập

Để cung cấp thông tin đăng nhập mạng Thread cho các nhà cung cấp Thread khác, chúng tôi cần thêm thông tin đó 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 tôi cũng cần biết thiết bị bộ định tuyến biên nào có chứa Thread này.

Trong ví dụ này, chúng ta sẽ tạo một ThreadBorderAgent từ Mã đại lý đường viền và chuyển thông tin xác thực mới của mạng Thread 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 hiện trường

Nếu hiện có bộ định tuyến biên tại hiện trường, bạn có thể sử dụng isPreferredCredentials để xác định xem bộ định tuyến biên có thuộc về mạng ưa thích 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 so với thông tin được lưu trữ trong Dịch vụ Google Play.

isPreferredCredentails trả về 0 nếu không khớp và 1 dưới dạng kiểu dữ liệu Int. Bạn có thể sử 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, trước tiên, bạn cần tạo một đối tượng ThreadNetworkCredentials. Có một số cách để khởi tạo ThreadNetworkCredentials. Trong các bước tiếp theo, chúng ta sẽ xem xét các tùy chọn này.

Thông tin đăng nhập mạng luồng do Tập dữ liệu hoạt động

Có những trường hợp Bộ định tuyến đường viền (Thread Border Router) đã được thiết lập với một mạng Thread (mạng riêng) 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 phiên bản ThreadNetworkCredential từ danh sách TLV tập dữ liệu 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 có thể lấy Tên mạng, Kênh và thông tin khác về mạng. Để xem 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 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}]") }
    

Thông tin đăng nhập mạng theo chuỗi do Tác nhân biên giới tạo

Mã tác nhân biên giới giúp xác định duy nhất một thiết bị bộ định tuyến biên. Để sử dụng API getCredentialsByBorderAgent, trước tiên, bạn cần tạo một đối tượng ThreadBorderAgent và chuyển Mã đại lý đường viền.

Sau khi bạn tạo đối tượng ThreadBorderAgent, hãy gọi getCredentialsByBorderAgent. Nếu đã lưu thông tin đăng nhập, hãy kiểm tra xem thông tin đó có được ưu tiên hay khô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 chuỗi theo ID mở rộng

Tương tự như getPreferredCredentials, bạn cũng có thể nhắc người dùng xác thực từ Mã mở rộng của bộ định tuyến biên giới. getCredentialsByExtendedPanId trả về IntentSender và kết quả Hoạt động chứa đố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}]") }
}

Xóa bằng chứng xác thực

Khi xoá thiết bị Bộ định tuyến biên (Border Router) khỏi nhà riêng hoặc đặt lại về trạng thái ban đầu, bạn cần xoá mạng Chuỗi của thiết bị 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ề SDK mạng luồng, vui lòng tham khảo Tài liệu tham khảo API.