ویژگی‌ها و میاناهای برنامه‌سازی کاربردی

‫Android 17 ویژگی‌ها و میاناهای برنامه‌سازی کاربردی جدید و فوق‌العاده‌ای را برای توسعه‌دهندگان معرفی می‌کند. بخش‌های زیر این ویژگی‌ها را خلاصه می‌کند تا به شما کمک کند با میاناهای برنامه‌سازی کاربردی مرتبط شروع کنید.

برای مشاهده فهرست دقیق میاناهای برنامه‌سازی کاربردی جدید، اصلاح‌شده، و حذف‌شده، گزارش تفاوت میانای برنامه‌سازی کاربردی را بخوانید. برای جزئیات درباره میاناهای برنامه‌سازی کاربردی جدید، به مرجع میانای برنامه‌سازی کاربردی Android مراجعه کنید — میاناهای برنامه‌سازی کاربردی جدید برای دید بهتر برجسته شده‌اند.

همچنین باید بخش‌هایی را که تغییرات پلاتفرم ممکن است بر برنامه‌هایتان تأثیر بگذارد مرور کنید. برای اطلاعات بیشتر، صفحه‌های زیر را ببینید:

عملکرد اصلی

‫Android 17 ویژگی‌های جدید زیر را دررابطه‌با عملکرد اصلی Android اضافه می‌کند.

راه‌اندازهای جدید ProfilingManager

Android 17 چند راه‌انداز سیستم جدید به ProfilingManager اضافه می‌کند تا به شما کمک کند داده‌های عمیقی برای اشکال‌زدایی مشکلات عملکرد جمع‌آوری کنید.

راه‌اندازهای جدید عبارت‌اند از:

  • TRIGGER_TYPE_COLD_START: راه‌انداز درطول راه‌اندازی سرد برنامه رخ می‌دهد. این ابزار هم نمونه پشته فراخوانی و هم ردگیری سیستم را در پاسخ ارائه می‌دهد.
  • TRIGGER_TYPE_OOM: راه‌انداز زمانی رخ می‌دهد که برنامه‌ای OutOfMemoryError را ایجاد کند و در پاسخ، «رونوشت پشته جاوا» ارائه دهد.
  • TRIGGER_TYPE_KILL_EXCESSIVE_CPU_USAGE: راه‌انداز زمانی رخ می‌دهد که برنامه‌ای به‌دلیل استفاده غیرعادی و بیش‌ازحد از واحد پردازش مرکزی متوقف شود و در پاسخ، عکس آنی از ردگیری سیستم پس‌زمینه درحال اجرا ارائه می‌دهد.
  • TRIGGER_TYPE_ANOMALY: ناهنجاری‌های عملکرد سیستم را شناسایی می‌کند، مانند فراخوانی‌های بیش‌ازحد binder و استفاده بیش‌ازحد از حافظه.

برای درک نحوه راه‌اندازی راه‌انداز سیستم، به مستندات مربوط به نمایه‌سازی مبتنی بر راه‌انداز و نحوه بازیابی و بارگذاری نمایه‌ها و تحلیل داده‌های نمایه‌سازی مراجعه کنید.

راه‌انداز نمایه‌سازی برای ناهنجاری‌های برنامه

Android 17 سرویس تشخیص ناهنجاری درون‌دستگاهی را معرفی می‌کند که رفتارهای پرمصرف ازنظر منابع و پس‌رفت‌های احتمالی سازگاری را پایش می‌کند. این سرویس که با ProfilingManager ادغام شده است به برنامه شما اجازه می‌دهد تا مصنوعات نمایه‌سازی را که توسط رویدادهای خاص شناسایی‌شده توسط سیستم راه‌اندازی شده‌اند دریافت کند.

از راه‌انداز TRIGGER_TYPE_ANOMALY برای شناسایی مشکلات عملکرد سیستم مثل تماس‌های بیش‌ازحد با binder و استفاده بیش‌ازحد از حافظه استفاده کنید. وقتی برنامه‌ای از محدودیت‌های حافظه تعریف‌شده توسط سیستم‌عامل فراتر می‌رود، راه‌انداز ناهنجاری به توسعه‌دهندگان اجازه می‌دهد رونوشت‌های پشته مختص برنامه را دریافت کنند تا به شناسایی و رفع مشکلات حافظه کمک کند. علاوه‌براین، برای هرزنامه بیش‌ازحد binder، راه‌انداز ناهنجاری یک نمایه نمونه‌گیری پشته در تراکنش‌های binder ارائه می‌دهد.

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

fun registerAnomalyTrigger(context: Context) {
    val profilingManager =
        context.getSystemService(ProfilingManager::class.java) ?: return
    val triggers = listOf(
        ProfilingTrigger.Builder(ProfilingTrigger.TRIGGER_TYPE_ANOMALY).build()
    )
    val callbackExecutor: Executor = Executors.newSingleThreadExecutor()
    val resultCallback = Consumer<ProfilingResult> { profilingResult ->
        if (profilingResult.errorCode == ProfilingResult.ERROR_NONE) {
            // Upload profile result to server for further analysis
            profilingResult.resultFilePath?.let { setupProfileUploadWorker(it) }
        }
    }
    profilingManager.registerForAllProfilingResults(
        callbackExecutor,
        resultCallback
    )
    profilingManager.addProfilingTriggers(triggers)
}

JobDebugInfo APIs

Android 17 میاناهای برنامه‌سازی کاربردی جدیدی برای JobDebugInfo معرفی می‌کند تا به توسعه‌دهندگان کمک کند کارهای JobScheduler خود را اشکال‌زدایی کنند—چرا اجرا نمی‌شوند، چه مدت اجرا شده‌اند، و سایر اطلاعات تجمیع‌شده.

اولین روش JobDebugInfo API گسترش‌یافته getPendingJobReasonStats() است که نقشه‌ای از دلایل قرار گرفتن کار در وضعیت اجرای معلقه و مدت‌زمان معلقه تجمعی مربوطه را برمی‌گرداند. این روش به روش‌های getPendingJobReasonsHistory() و getPendingJobReasons() می‌پیوندد تا به شما بینشی درباره دلیل عدم اجرای کار زمان‌بندی‌شده طبق انتظار ارائه دهد، اما با دردسترس قرار دادن مدت‌زمان و دلیل کار در یک روش واحد، بازیابی اطلاعات را ساده‌تر می‌کند.

برای مثال، برای jobId مشخص‌شده، ممکن است روش PENDING_JOB_REASON_CONSTRAINT_CHARGING و مدت ۶۰۰۰۰ میلی‌ثانیه را برگرداند، که نشان می‌دهد کار به‌مدت ۶۰۰۰۰ میلی‌ثانیه به‌دلیل برآورده نشدن محدودیت شارژ درانتظار بوده است.

کاهش قفل‌های بیداری با پشتیبانی شنونده برای هشدارهای «مجاز درحالت بیکار»

‫Android 17 نوع جدیدی از AlarmManager.setExactAndAllowWhileIdle را معرفی می‌کند که به‌جای PendingIntent، OnAlarmListener را می‌پذیرد. این سازوکار جدید مبتنی بر فراخوانی برگشتی برای برنامه‌هایی که درحال‌حاضر برای انجام کارهای دوره‌ای به قفل‌های بیداری مداوم متکی هستند، مانند برنامه‌های پیام‌رسانی که اتصالات سوکت را حفظ می‌کنند، ایده‌آل است.

حریم خصوصی

‫Android 17 شامل ویژگی‌های جدید زیر برای بهبود حریم خصوصی کاربر است.

پشتیبانی پلاتفرم از Encrypted Client Hello (ECH)

اندروید ۱۷ پشتیبانی پلتفرم از Encrypted Client Hello (ECH) را معرفی می‌کند، که یک بهبود قابل توجه در حریم خصوصی ارتباطات شبکه است. ECH یک افزونه TLS 1.3 است که نشانگر نام سرور (SNI) را در طول اولین اتصال TLS رمزگذاری می‌کند. این رمزگذاری با دشوارتر کردن شناسایی دامنه خاصی که یک برنامه به آن متصل می‌شود، برای واسطه‌های شبکه، به محافظت از حریم خصوصی کاربر کمک می‌کند.

این پلتفرم اکنون شامل APIهای لازم برای کتابخانه‌های شبکه برای پیاده‌سازی ECH است. این شامل قابلیت‌های جدید در DnsResolver برای جستجوی رکوردهای HTTPS DNS حاوی پیکربندی‌های ECH و روش‌های جدید در SSLEngines و SSLSockets متعلق به Conscrypt برای فعال کردن ECH با ارسال این پیکربندی‌ها هنگام اتصال به یک دامنه است. توسعه‌دهندگان می‌توانند تنظیمات ECH، مانند فعال کردن آن به صورت فرصت‌طلبانه یا اجباری کردن استفاده از آن را از طریق عنصر جدید <domainEncryption> در فایل پیکربندی امنیت شبکه، که به صورت جهانی یا بر اساس هر دامنه قابل اجرا است، پیکربندی کنند.

انتظار می‌رود کتابخانه‌های شبکه محبوب مانند HttpEngine، WebView و OkHttp این APIهای پلتفرم را در به‌روزرسانی‌های آینده ادغام کنند و پذیرش ECH و افزایش حریم خصوصی کاربران را برای برنامه‌ها آسان‌تر کنند.

برای اطلاعات بیشتر، به مستندات Encrypted Client Hello مراجعه کنید.

انتخاب‌گر مخاطبین Android

«انتخابگر مخاطب Android» واسطی استانداردشده و قابل‌مرور است که کاربران می‌توانند ازطریق آن مخاطبین را با برنامه شما هم‌رسانی کنند. این انتخابگر که در دستگاه‌های دارای Android 17 (سطح میانای برنامه‌سازی کاربردی 37) یا بالاتر دردسترس است، جایگزینی حافظ حریم خصوصی برای اجازه گسترده READ_CONTACTS ارائه می‌دهد. به‌جای درخواست دسترسی به کل دفترچه تلفن کاربر، برنامه‌تان فیلدهای داده موردنیازش را مشخص می‌کند (مثلاً شماره تلفن یا نشانی ایمیل) و کاربر مخاطبین خاصی را برای هم‌رسانی انتخاب می‌کند. این کار به برنامه شما اجازه خواندن فقط داده‌های انتخاب‌شده را می‌دهد، کنترل جزئی را تضمین می‌کند و درعین‌حال تجربه کاربری ثابتی را با قابلیت‌های جستجوی داخلی، تعویض نمایه، و چندانتخابی بدون نیاز به ساختن یا نگهداری واسط کاربر ارائه می‌دهد.

برای اطلاعات بیشتر، اسناد انتخابگر مخاطب را ببینید.

امنیت

Android 17 ویژگی‌های جدید زیر را برای بهبود امنیت دستگاه و برنامه اضافه می‌کند.

حالت محافظت پیشرفته Android (AAPM)

حالت حفاظت پیشرفته اندروید (Android Advanced Protection Mode) مجموعه‌ای قدرتمند و جدید از ویژگی‌های امنیتی را در اختیار کاربران اندروید قرار می‌دهد که گامی مهم در جهت محافظت از کاربران - به‌ویژه کاربران در معرض خطر بیشتر - در برابر حملات پیچیده است. AAPM که به عنوان یک ویژگی اختیاری طراحی شده است، با یک تنظیم پیکربندی واحد فعال می‌شود که کاربران می‌توانند در هر زمان آن را فعال کنند تا مجموعه‌ای از حفاظت‌های امنیتی دلخواه را اعمال کنند.

این تنظیمات اصلی شامل مسدود کردن نصب برنامه‌ها از منابع ناشناخته (سایدلودینگ)، محدود کردن سیگنال‌دهی داده‌های USB و اجباری کردن اسکن Google Play Protect است که به طور قابل توجهی سطح حمله دستگاه را کاهش می‌دهد. توسعه‌دهندگان می‌توانند با استفاده از AdvancedProtectionManager API با این ویژگی ادغام شوند تا وضعیت حالت را تشخیص دهند و برنامه‌ها را قادر سازند تا به طور خودکار یک وضعیت امنیتی سخت‌گیرانه را اتخاذ کنند یا عملکردهای پرخطر را هنگامی که کاربر انتخاب کرده است، محدود کنند.

امضای APK با PQC

Android اکنون از طرح امضای APK ترکیبی پشتیبانی می‌کند تا هویت امضای برنامه‌تان را در آینده دربرابر تهدید احتمالی حملاتی که از محاسبات کوانتومی استفاده می‌کنند مقاوم کند. این ویژگی «طرح امضای APK» جدیدی را معرفی می‌کند که به شما امکان می‌دهد کلید امضای کلاسیک (مثل RSA یا EC) را با الگوریتم جدید رمزنگاری پساکوانتومی (PQC) (ML-DSA) جفت کنید.

این رویکرد ترکیبی تضمین می‌کند که برنامه شما دربرابر حملات کوانتومی آینده ایمن بماند و درعین‌حال سازگاری کامل با نسخه‌های قدیمی‌تر Android و دستگاه‌هایی که به درستی‌سنجی امضای کلاسیک متکی هستند حفظ شود.

تأثیر بر توسعه‌دهندگان

  • برنامه‌هایی که از «امضای برنامه» Play استفاده می‌کنند: اگر از «امضای برنامه» Play استفاده می‌کنید، می‌توانید منتظر بمانید تا Google Play گزینه ارتقا به امضای ترکیبی بااستفاده از کلید «رمزنگاری پسا کوانتومی» تولیدشده توسط Google Play را به شما ارائه دهد. این کار تضمین می‌کند که برنامه‌تان بدون نیاز به مدیریت دستی کلید محافظت می‌شود.
  • برنامه‌هایی که از کلیدهای خودمدیریتی استفاده می‌کنند: توسعه‌دهندگانی که کلیدهای امضای خودشان را مدیریت می‌کنند می‌توانند از ابزارهای به‌روزشده ساخت Android (مانند apksigner) برای چرخش به هویت ترکیبی استفاده کنند که کلید «رمزنگاری پسا کوانتومی» را با کلید کلاسیک جدید ترکیب می‌کند. (باید کلید کلاسیک جدیدی ایجاد کنید، نمی‌توانید از کلید قدیمی‌تر دوباره استفاده کنید.)

اتصال‌پذیری

Android 17 ویژگی‌های زیر را برای بهبود اتصال‌پذیری دستگاه و برنامه اضافه می‌کند.

شبکه‌های ماهواره‌ای محدودشده

بهینه‌سازی‌هایی را پیاده‌سازی می‌کند تا برنامه‌ها بتوانند به طور مؤثر در شبکه‌های ماهواره‌ای با پهنای باند کم عمل کنند.

تجربه کاربری و واسط کاربر سیستم

Android 17 شامل تغییرات زیر برای بهبود تجربه کاربری است.

جاری‌سازی اختصاصی میزان صدای «دستیار»

Android 17 یک جریان اختصاصی میزان صدای «دستیار» برای برنامه‌های «دستیار» معرفی می‌کند، برای بازپخش با USAGE_ASSISTANT. این تغییر صدای «دستیار» را از جاری‌سازی رسانه استاندارد جدا می‌کند و به کاربران امکان می‌دهد هریک از این صداها را به‌طور جداگانه کنترل کنند. این کار سناریوهایی مانند بی‌صدا کردن بازپخش رسانه را درحین حفظ شنیداری برای پاسخ‌های «دستیار» و برعکس فعال می‌کند.

برنامه‌های «دستیار» که به حالت صوتی جدید MODE_ASSISTANT_CONVERSATION دسترسی دارند می‌توانند ثبات کنترل میزان صدا را بیشتر بهبود بخشند. برنامه‌های «دستیار» می‌توانند از این حالت برای ارائه راهنمایی به سیستم درباره جلسه فعال «دستیار» استفاده کنند، و مطمئن شوند که جریان «دستیار» می‌تواند خارج از بازپخش فعال USAGE_ASSISTANT یا با لوازم جانبی بلوتوث متصل کنترل شود.

Handoff

«انتقال» ویژگی و میانای برنامه‌سازی کاربردی جدیدی است که در Android 17 ارائه می‌شود و توسعه‌دهندگان نرم‌افزار می‌توانند آن را ادغام کنند تا تداوم بین‌دستگاهی را برای کاربرانشان فراهم کنند. این ویژگی به کاربر اجازه می‌دهد فعالیت برنامه را در یک دستگاه Android شروع کند و آن را به دستگاه Android دیگری منتقل کند. Handoff در پس‌زمینه دستگاه کاربر اجرا می‌شود و فعالیت‌های دردسترس را از دیگر دستگاه‌های اطراف کاربر ازطریق نقاط ورودی مختلف، مانند راه‌انداز و نوار وظیفه، در دستگاه گیرنده نمایش می‌دهد.

برنامه‌ها می‌توانند «انتقال» را برای راه‌اندازی همان برنامه Android بومی تعیین کنند، اگر در دستگاه گیرنده نصب شده و دردسترس باشد. در این جریان برنامه به برنامه، کاربر به فعالیت تعیین‌شده پیوند عمیق می‌شود. یا اینکه «انتقال برنامه به وب» می‌تواند به‌عنوان گزینه جایگزین ارائه شود یا مستقیماً با «انتقال نشانی وب» پیاده‌سازی شود.

پشتیبانی از «چنددستگاهی» براساس هر فعالیت پیاده‌سازی می‌شود. برای فعال کردن Handoff، روش setHandoffEnabled() را برای فعالیت فراخوانی کنید. ممکن است لازم باشد داده‌های اضافی همراه با انتقال ارسال شود تا فعالیت بازآفرینی‌شده در دستگاه گیرنده بتواند وضعیت مناسب را بازیابی کند. فراخوانی برگشتی onHandoffActivityDataRequested() را پیاده‌سازی کنید تا شیء HandoffActivityData برگردانده شود که حاوی جزئیاتی است که مشخص می‌کند «انتقال» چگونه باید فعالیت را در دستگاه گیرنده مدیریت و بازآفرینی کند.

Live Update - Semantic color API

با Android 17، به‌روزرسانی زنده میاناهای برنامه‌سازی کاربردی «رنگ‌آمیزی معنایی» را برای پشتیبانی از رنگ‌هایی با معنی جهانی راه‌اندازی می‌کند.

کلاس‌های زیر از رنگ‌آمیزی معنایی پشتیبانی می‌کنند:

رنگ کردن

  • سبز: مرتبط با ایمنی. این رنگ باید برای موردی استفاده شود که به افراد اطلاع می‌دهد شما در وضعیت امن هستید.
  • نارنجی: برای نشان دادن احتیاط و علامت‌گذاری خطرات فیزیکی. این رنگ باید در شرایطی استفاده شود که کاربران باید برای تنظیم کردن تنظیمات محافظت بهتر توجه کنند.
  • قرمز: معمولاً نشان‌دهنده خطر، توقف است. این نوع اعلان باید برای مواردی ارائه شود که نیاز به توجه فوری افراد دارد.
  • آبی: رنگ خنثی برای محتوایی که اطلاعاتی است و باید از محتوای دیگر متمایز باشد.

مثال زیر نشان می‌دهد که چگونه می‌توان سبک‌های معنایی را به نوشتار در اعلان اعمال کرد:

  val ssb = SpannableStringBuilder()
        .append("Colors: ")
        .append("NONE", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_UNSPECIFIED), 0)
        .append(", ")
        .append("INFO", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_INFO), 0)
        .append(", ")
        .append("SAFE", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_SAFE), 0)
        .append(", ")
        .append("CAUTION", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_CAUTION), 0)
        .append(", ")
        .append("DANGER", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_DANGER), 0)

    Notification.Builder(context, channelId)
          .setSmallIcon(R.drawable.ic_icon)
          .setContentTitle("Hello World!")
          .setContentText(ssb)
          .setOngoing(true)
              .setRequestPromotedOngoing(true)

UWB Downlink-TDoA API برای Android 17

محدوده «تفاوت زمان رسیدن اتصال پایین‌سو» (DL-TDoA) به دستگاه امکان می‌دهد موقعیت خود را نسبت به چندین لنگر با اندازه‌گیری زمان رسیدن نسبی سیگنال‌ها تعیین کند.

قطعه کد زیر نحوه مقداردهی اولیه مدیر فاصله‌یابی، درستی‌سنجی قابلیت‌های دستگاه، و شروع جلسه DL-TDoA را نشان می‌دهد:

کاتلین

class RangingApp {

    fun initDlTdoa(context: Context) {
        // Initialize the Ranging Manager
        val rangingManager = context.getSystemService(RangingManager::class.java)

        // Register for device capabilities
        val capabilitiesCallback = object : RangingManager.RangingCapabilitiesCallback {
            override fun onRangingCapabilities(capabilities: RangingCapabilities) {
                // Make sure Dl-TDoA is supported before starting the session
                if (capabilities.uwbCapabilities != null && capabilities.uwbCapabilities!!.isDlTdoaSupported) {
                    startDlTDoASession(context)
                }
            }
        }
        rangingManager.registerCapabilitiesCallback(Executors.newSingleThreadExecutor(), capabilitiesCallback)
    }

    fun startDlTDoASession(context: Context) {

        // Initialize the Ranging Manager
        val rangingManager = context.getSystemService(RangingManager::class.java)

        // Create session and configure parameters
        val executor = Executors.newSingleThreadExecutor()
        val rangingSession = rangingManager.createRangingSession(executor, RangingSessionCallback())
        val rangingRoundIndexes = byteArrayOf(0)
        val config: ByteArray = byteArrayOf() // OOB config data
        val params = DlTdoaRangingParams.createFromFiraConfigPacket(config, rangingRoundIndexes)

        val rangingDevice = RangingDevice.Builder().build()
        val rawTagDevice = RawRangingDevice.Builder()
            .setRangingDevice(rangingDevice)
            .setDlTdoaRangingParams(params)
            .build()

        val dtTagConfig = RawDtTagRangingConfig.Builder(rawTagDevice).build()

        val preference = RangingPreference.Builder(DEVICE_ROLE_DT_TAG, dtTagConfig)
            .setSessionConfig(SessionConfig.Builder().build())
            .build()

        // Start the ranging session
        rangingSession.start(preference)
    }
}

private class RangingSessionCallback : RangingSession.Callback {
    override fun onDlTdoaResults(peer: RangingDevice, measurement: DlTdoaMeasurement) {
        // Process measurement results here
    }
}

جاوا

public class RangingApp {

    public void initDlTdoa(Context context) {

        // Initialize the Ranging Manager
        RangingManager rangingManager = context.getSystemService(RangingManager.class);

        // Register for device capabilities
        RangingManager.CapabilitiesCallback capabilitiesCallback = new RangingManager.RangingCapabilitiesCallback() {
            @Override
            public void onRangingCapabilities(RangingCapabilities capabilities) {
                // Make sure Dl-TDoA is supported before starting the session
                if (capabilities.getUwbCapabilities() != null && capabilities.getUwbCapabilities().isDlTdoaSupported()) {
                    startDlTDoASession(context);
                }
            }
        };
        rangingManager.registerCapabilitiesCallback(Executors.newSingleThreadExecutor(), capabilitiesCallback);
    }

    public void startDlTDoASession(Context context) {
        RangingManager rangingManager = context.getSystemService(RangingManager.class);

        // Create session and configure parameters
        Executor executor = Executors.newSingleThreadExecutor();
        RangingSession rangingSession = rangingManager.createRangingSession(executor, new RangingSessionCallback());
        byte[] rangingRoundIndexes = new byte[] {0};
        byte[] config = new byte[0]; // OOB config data
        DlTdoaRangingParams params = DlTdoaRangingParams.createFromFiraConfigPacket(config, rangingRoundIndexes);

        RangingDevice rangingDevice = new RangingDevice.Builder().build();
        RawRangingDevice rawTagDevice = new RawRangingDevice.Builder()
                .setRangingDevice(rangingDevice)
                .setDlTdoaRangingParams(params)
                .build();

        RawDtTagRangingConfig dtTagConfig = new RawDtTagRangingConfig.Builder(rawTagDevice).build();

        RangingPreference preference = new RangingPreference.Builder(DEVICE_ROLE_DT_TAG, dtTagConfig)
                .setSessionConfig(new SessionConfig.Builder().build())
                .build();

        // Start the ranging session
        rangingSession.start(preference);
    }

    private static class RangingSessionCallback implements RangingSession.Callback {

        @Override
        public void onDlTdoaResults(RangingDevice peer, DlTdoaMeasurement measurement) {
            // Process measurement results here
        }
    }
}

پیکربندی‌های خارج‌از باند (OOB)

تکه‌کد زیر نمونه‌ای از داده‌های پیکربندی DL-TDoA OOB برای Wi-Fi و BLE ارائه می‌دهد:

جاوا

// Wifi Configuration
byte[] wifiConfig = {
    (byte) 0xDD, (byte) 0x2D, (byte) 0x5A, (byte) 0x18, (byte) 0xFF, // Header
    (byte) 0x5F, (byte) 0x19, // FiRa Sub-Element
    (byte) 0x02, (byte) 0x00, // Profile ID
    (byte) 0x06, (byte) 0x02, (byte) 0x20, (byte) 0x08, // MAC Address
    (byte) 0x14, (byte) 0x01, (byte) 0x0C, // Preamble Index
    (byte) 0x27, (byte) 0x02, (byte) 0x08, (byte) 0x07, // Vendor ID
    (byte) 0x28, (byte) 0x06, (byte) 0xCA, (byte) 0xC8, (byte) 0xA6, (byte) 0xF7, (byte) 0x6F, (byte) 0x08, // Static STS IV
    (byte) 0x08, (byte) 0x02, (byte) 0x60, (byte) 0x09, // Slot Duration
    (byte) 0x1B, (byte) 0x01, (byte) 0x0A, // Slots per RR
    (byte) 0x09, (byte) 0x04, (byte) 0xE8, (byte) 0x03, (byte) 0x00, (byte) 0x00, // Duration
    (byte) 0x9F, (byte) 0x04, (byte) 0x67, (byte) 0x45, (byte) 0x23, (byte) 0x01  // Session ID
};

// BLE Configuration
byte[] bleConfig = {
    (byte) 0x2D, (byte) 0x16, (byte) 0xF4, (byte) 0xFF, // Header
    (byte) 0x5F, (byte) 0x19, // FiRa Sub-Element
    (byte) 0x02, (byte) 0x00, // Profile ID
    (byte) 0x06, (byte) 0x02, (byte) 0x20, (byte) 0x08, // MAC Address
    (byte) 0x14, (byte) 0x01, (byte) 0x0C, // Preamble Index
    (byte) 0x27, (byte) 0x02, (byte) 0x08, (byte) 0x07, // Vendor ID
    (byte) 0x28, (byte) 0x06, (byte) 0xCA, (byte) 0xC8, (byte) 0xA6, (byte) 0xF7, (byte) 0x6F, (byte) 0x08, // Static STS IV
    (byte) 0x08, (byte) 0x02, (byte) 0x60, (byte) 0x09, // Slot Duration
    (byte) 0x1B, (byte) 0x01, (byte) 0x0A, // Slots per RR
    (byte) 0x09, (byte) 0x04, (byte) 0xE8, (byte) 0x03, (byte) 0x00, (byte) 0x00, // Duration
    (byte) 0x9F, (byte) 0x04, (byte) 0x67, (byte) 0x45, (byte) 0x23, (byte) 0x01  // Session ID
};

اگر نمی‌توانید از پیکربندی OOB استفاده کنید چون وجود ندارد، یا اگر لازم است مقادیر پیش‌فرضی را که در پیکربندی OOB نیستند تغییر دهید، می‌توانید پارامترها را با DlTdoaRangingParams.Builder بسازید، همان‌طور که در قطعه کد زیر نشان داده شده است. می‌توانید از این پارامترها به‌جای DlTdoaRangingParams.createFromFiraConfigPacket() استفاده کنید:

کاتلین

val dlTdoaParams = DlTdoaRangingParams.Builder(1)
    .setComplexChannel(UwbComplexChannel.Builder()
            .setChannel(9).setPreambleIndex(10).build())
    .setDeviceAddress(deviceAddress)
    .setSessionKeyInfo(byteArrayOf(0x01, 0x02, 0x03, 0x04))
    .setRangingIntervalMillis(240)
    .setSlotDuration(UwbRangingParams.DURATION_2_MS)
    .setSlotsPerRangingRound(20)
    .setRangingRoundIndexes(byteArrayOf(0x01, 0x05))
    .build()

جاوا

DlTdoaRangingParams dlTdoaParams = new DlTdoaRangingParams.Builder(1)
    .setComplexChannel(new UwbComplexChannel.Builder()
            .setChannel(9).setPreambleIndex(10).build())
    .setDeviceAddress(deviceAddress)
    .setSessionKeyInfo(new byte[]{0x01, 0x02, 0x03, 0x04})
    .setRangingIntervalMillis(240)
    .setSlotDuration(UwbRangingParams.DURATION_2_MS)
    .setSlotsPerRangingRound(20)
    .setRangingRoundIndexes(new byte[]{0x01, 0x05})
    .build();