Thread Network SDK برای اندروید

کیت توسعه نرم‌افزاری شبکه Thread عملکردی مشابه یک جاکلیدی دیجیتال ارائه می‌دهد و به برنامه‌های اندروید شما اجازه می‌دهد تا اعتبارنامه‌های شبکه Thread را با سرویس‌های Google Play به اشتراک بگذارند. این به برنامه‌های شما اجازه می‌دهد تا هر دستگاه Thread را از هر اکوسیستم خانه هوشمندی، بدون افشای مستقیم اعتبارنامه‌ها و داده‌های کاربر، راه‌اندازی کنند.

تنها با چند فراخوانی API، می‌توانید:

  1. درخواست اعتبارنامه‌های شبکه Thread مورد نظر از سرویس‌های Google Play.
  2. Thread Border Router (TBR) جدید را راه‌اندازی کنید و اعتبارنامه‌های شبکه ترد خود را به سرویس‌های گوگل پلی اضافه کنید.
  3. اگر از قبل TBR های درون فیلدی دارید، می‌توانید بررسی کنید که آیا TBR های شما در شبکه ترجیحی قرار دارند یا خیر و در صورت لزوم آنها را منتقل کنید.

چندین مسیر برای کاربر و توسعه‌دهنده وجود دارد که باید در نظر گرفته شوند. ما در این راهنما اکثر آنها را به همراه سایر ویژگی‌های کلیدی و نحوه‌ی استفاده‌ی پیشنهادی پوشش خواهیم داد.

اصطلاحات کلیدی و مفاهیم API

قبل از شروع، درک اصطلاحات زیر مفید است:

  • اعتبارنامه‌های شبکه‌ی ترد: مجموعه‌ای دودویی از TLVهای ترد که نام شبکه‌ی ترد، کلید شبکه و سایر ویژگی‌هایی را که یک دستگاه ترد برای پیوستن به یک شبکه‌ی ترد معین نیاز دارد، کدگذاری می‌کند.

  • اعتبارنامه‌های شبکه‌ی ترد ترجیحی: اعتبارنامه‌های شبکه‌ی ترد که به صورت خودکار انتخاب شده‌اند و می‌توانند با استفاده از رابط برنامه‌نویسی کاربردی getPreferredCredentials با برنامه‌های فروشندگان مختلف به اشتراک گذاشته شوند.

  • شناسه عامل مرزی: یک شناسه ۱۶ بایتی منحصر به فرد جهانی برای یک دستگاه TBR . این شناسه توسط فروشندگان border router ایجاد و مدیریت می‌شود.

  • برنامه راه‌اندازی TBR : این برنامه اندروید شماست که دستگاه‌های جدید TBR را راه‌اندازی می‌کند و اعتبارنامه‌های شبکه Thread را به سرویس‌های Google Play اضافه می‌کند. برنامه شما مالک معتبر اعتبارنامه‌های اضافه شده است و به آنها دسترسی دارد.

بسیاری از APIهای شبکه Thread، وظیفه‌ای را برمی‌گردانند که به صورت غیرهمزمان تکمیل می‌شود. می‌توانید از addOnSuccessListener و addOnFailureListener برای ثبت فراخوانی‌ها جهت دریافت نتیجه استفاده کنید. برای کسب اطلاعات بیشتر، به مستندات Task مراجعه کنید.

مالکیت و نگهداری اعتبارنامه‌ها

برنامه‌ای که اعتبارنامه‌های شبکه Thread را اضافه می‌کند، مالک اعتبارنامه‌ها می‌شود و مجوزهای کامل برای دسترسی به اعتبارنامه‌ها را دارد. اگر سعی کنید به اعتبارنامه‌های اضافه شده توسط برنامه‌های دیگر دسترسی پیدا کنید، خطای PERMISSION_DENIED دریافت خواهید کرد.

به عنوان مالک برنامه، توصیه می‌شود هنگام به‌روزرسانی شبکه TBR ، اعتبارنامه‌های ذخیره شده در سرویس‌های Google Play را به‌روز نگه دارید. این به معنای اضافه کردن اعتبارنامه‌ها در صورت نیاز، به‌روزرسانی اعتبارنامه‌ها هنگام تغییر اعتبارنامه‌های شبکه Thread border router و حذف اعتبارنامه‌ها هنگام حذف TBR یا تنظیم مجدد کارخانه است.

کشف مامور مرزی

اعتبارنامه‌ها باید با شناسه عامل مرزی ذخیره شوند. باید مطمئن شوید که برنامه راه‌اندازی TBR شما قادر به تعیین شناسه‌های عامل مرزی TBR های شما است.

TBR ها باید از mDNS برای انتشار اطلاعات شبکه Thread، از جمله نام شبکه، شناسه توسعه‌یافته Pan و شناسه عامل مرزی، استفاده کنند. مقادیر txt مربوط به این ویژگی‌ها به ترتیب nn ، xp و id هستند.

برای شبکه‌هایی که دارای Google Thread Border Router (gTBR) هستند، سرویس‌های گوگل پلی به‌طور خودکار اعتبارنامه‌های شبکه گوگل ترد را برای استفاده دریافت می‌کنند.

SDK را در برنامه اندروید خود ادغام کنید

برای شروع، مراحل زیر را انجام دهید:

  1. دستورالعمل‌های ارائه شده در بخش «راه‌اندازی سرویس‌های Google Play» را دنبال کنید.

  2. وابستگی سرویس‌های گوگل پلی را به فایل build.gradle خود اضافه کنید:

    implementation 'com.google.android.gms:play-services-threadnetwork:16.2.1'
    
  3. اختیاری: یک کلاس داده BorderAgent برای ذخیره اطلاعات TBR تعریف کنید. ما در سراسر این راهنما از این داده‌ها استفاده خواهیم کرد:

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

در ادامه، مراحل پیشنهادی برای افزودن و مدیریت اعتبارنامه‌های ترجیحی را بررسی خواهیم کرد.

تنظیمات جدید مسیریاب حاشیه نخ

قبل از ایجاد یک شبکه جدید برای روترهای مرزی جدید، مهم است که ابتدا از اعتبارنامه‌های شبکه ترجیحی استفاده کنید. این تضمین می‌کند که دستگاه‌های Thread در صورت امکان به یک شبکه Thread واحد متصل شوند.

فراخوانی getPreferredCredentials یک Activity را اجرا می‌کند و از کاربران می‌خواهد که درخواست شبکه را مجاز کنند. اگر اعتبارنامه‌های شبکه در زنجیره کلید دیجیتال Thread SDK ذخیره شده باشند، اعتبارنامه‌ها به برنامه شما بازگردانده می‌شوند.

درخواست اعتبارنامه

برای درخواست اطلاعات احراز هویت ترجیحی از کاربر:

  1. یک ActivityLauncher تعریف کنید:

    private lateinit var preferredCredentialsLauncher: ActivityResultLauncher<IntentSenderRequest>
    
  2. مدیریت نتیجه Activity که به صورت 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. اگر در حال راه‌اندازی یک TBR جدید هستید، توصیه می‌شود که preferredCredentials را فراخوانی کرده و Activity را اجرا کنید. این فراخوانی تضمین می‌کند که TBR جدید شما از همان اعتبارنامه‌هایی که قبلاً به عنوان preferred در تلفن ذخیره شده‌اند، استفاده خواهد کرد و همگرایی TBRهای مختلف را به یک شبکه یکسان ارتقا می‌دهد.

    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. اگر مورد استفاده شما مربوط به راه‌اندازی دستگاه‌های غیر TBR، مانند یک دستگاه جدید Matter-over-Thread است، توصیه می‌شود از API allActiveCredentials برای دریافت اعتبارنامه‌ها استفاده کنید. این فراخوانی TBRهای موجود در شبکه محلی را اسکن می‌کند و بنابراین اعتبارنامه‌هایی را که توسط یک TBR موجود به صورت محلی در دسترس نیستند، برنمی‌گرداند.

    // 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
    }
    

یک شبکه Thread جدید ایجاد کنید

اگر نه اعتبارنامه‌های شبکه Thread ترجیحی و نه اعتبارنامه‌های Thread فعال در شبکه Thread کاربر موجود نباشد، می‌توانید از API addCredentials برای افزودن اعتبارنامه‌ها به سرویس‌های Google Play استفاده کنید. برای انجام این کار، باید یک ThreadBorderAgent ایجاد کنید و همچنین یک شیء ThreadNetworkCredentials ارائه دهید.

برای ایجاد یک شبکه تصادفی، تابع newRandomizeBuilder را فراخوانی کنید:

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

برای مشخص کردن نام شبکه Thread:

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

اضافه کردن اعتبارنامه‌ها

برای اینکه اعتبارنامه‌های شبکه Thread شما برای سایر فروشندگان Thread در دسترس قرار گیرد، باید آنها را به سرویس‌های Google Play اضافه کنیم. قبل از اینکه بتوانیم اعتبارنامه‌های جدید خود را اضافه کنیم، باید بدانیم که این شبکه Thread به کدام دستگاه TBR تعلق دارد.

در این مثال، ما یک ThreadBorderAgent از یک Border Agent ID ایجاد می‌کنیم و اعتبارنامه‌های شبکه Thread جدیدی را که ایجاد کرده‌اید، ارسال می‌کنیم:

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}]") }
}

شناسایی و انتقال border router درون میدانی

اگر border router درون‌فیلد دارید، می‌توانید isPreferredCredentials برای تعیین اینکه آیا border router شما به شبکه ترجیحی تعلق دارند یا خیر، استفاده کنید. این API از کاربر اجازه نمی‌گیرد و اعتبارنامه‌های border router را با آنچه در سرویس‌های Google Play ذخیره شده است، بررسی می‌کند.

تابع isPreferredCredentials برای موارد منطبق نشده 0 و برای موارد منطبق 1 را به عنوان یک نوع داده Int برمی‌گرداند. می‌توانید IsPreferredCredentialsResult برای بررسی نتایج خود استفاده کنید.

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

برای استفاده از isPreferredCredentials ، ابتدا باید یک شیء ThreadNetworkCredentials ایجاد کنید. روش‌های مختلفی برای نمونه‌سازی ThreadNetworkCredentials وجود دارد. در مراحل بعدی، این گزینه‌ها را بررسی خواهیم کرد.

اعتبارنامه‌های شبکه Thread توسط مجموعه داده‌های عملیاتی

مواردی وجود دارد که TBR شما از قبل با یک شبکه Thread تنظیم شده است و شما می‌خواهید این شبکه Thread را به سرویس‌های Google Play اضافه کنید تا آن را با سایر فروشندگان به اشتراک بگذارید. می‌توانید یک نمونه ThreadNetworkCredential از یک لیست خام Thread Active Operational Dataset TLV ایجاد کنید:

  1. تبدیل مجموعه داده‌های عملیاتی به ByteArray . برای مثال:

    val activeDataset =
          "0e080000000000010000000300000f35060004001fffe0020833333333...".dsToByteArray()
    
    fun String.dsToByteArray(): ByteArray {
      return chunked(2).map { it.toInt(16).toByte() }.toByteArray()
    }
    
  2. fromActiveOperationalDataset برای ایجاد ThreadNetworkCredentials استفاده کنید. در صورت موفقیت، می‌توانید نام شبکه Thread، کانال و سایر اطلاعات شبکه را دریافت کنید. برای مشاهده لیست کامل ویژگی‌ها، به ThreadNetworkCredentials مراجعه کنید.

    val threadNetworkCredentials =
        ThreadNetworkCredentials.fromActiveOperationalDataset(activeDataset)
    Log.d(
        "threadNetworkCredentials",
        threadNetworkCredentials.channel.toString() + " - " + threadNetworkCredentials.networkName)
    
  3. API مربوط به isPreferredCredentials فراخوانی کرده و 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}]") }
    

اعتبارنامه‌های شبکه Thread توسط Border Agent

شناسه عامل مرزی (Border Agent ID) به طور منحصر به فرد یک دستگاه TBR را شناسایی می‌کند. برای استفاده از API getCredentialsByBorderAgent ، ابتدا باید یک شیء ThreadBorderAgent ایجاد کنید و شناسه عامل مرزی (Border Agent ID) را به آن ارسال کنید.

پس از ایجاد شیء ThreadBorderAgent ، تابع getCredentialsByBorderAgent را فراخوانی کنید. اگر اعتبارنامه‌ها ذخیره شده‌اند، بررسی کنید که آیا ترجیح داده می‌شوند یا خیر.

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}]") }
}

اعتبارنامه‌های شبکه Thread توسط Extended Pan ID

مشابه getPreferredCredentials ، می‌توانید از کاربر بخواهید که از شناسه‌ی توسعه‌یافته‌ی Pan یک TBR ، اطلاعات احراز هویت را دریافت کند. getCredentialsByExtendedPanId یک IntentSender برمی‌گرداند و نتیجه‌ی Activity در صورت تأیید کاربر، شامل یک شیء ThreadNetworkCredentials می‌شود.

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}]") }
}

حذف اعتبارنامه‌ها

وقتی دستگاه border router شما از حالت خانگی خارج می‌شود یا به تنظیمات کارخانه برمی‌گردد، باید شبکه Thread آن را از سرویس‌های گوگل پلی حذف کنید.

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}]") }
}

منابع

برای کسب اطلاعات بیشتر در مورد SDK شبکه Thread، به مرجع API مراجعه کنید.