ฟีเจอร์และ API

Android 17 มาพร้อมฟีเจอร์และ API ใหม่ๆ ที่ยอดเยี่ยมสำหรับนักพัฒนาแอป ส่วนต่อไปนี้ จะสรุปฟีเจอร์เหล่านี้เพื่อช่วยให้คุณเริ่มต้นใช้งาน API ที่เกี่ยวข้องได้

หากต้องการดูรายการ API ใหม่ที่มีการแก้ไขและถูกนำออกโดยละเอียด โปรดอ่านรายงานความแตกต่างของ API ดูรายละเอียดเกี่ยวกับ API ใหม่ได้ที่เอกสารอ้างอิง Android API โดยเราจะไฮไลต์ API ใหม่เพื่อให้มองเห็นได้ชัดเจน

นอกจากนี้ คุณควรตรวจสอบส่วนที่การเปลี่ยนแปลงของแพลตฟอร์มอาจส่งผลต่อแอปด้วย ดูข้อมูลเพิ่มเติมได้ที่หน้าต่อไปนี้

ฟังก์ชันหลัก

Android 17 เพิ่มฟีเจอร์ใหม่ต่อไปนี้ที่เกี่ยวข้องกับฟังก์ชันหลักของ Android

ทริกเกอร์ ProfilingManager ใหม่

Android 17 เพิ่มทริกเกอร์ระบบใหม่หลายรายการลงใน ProfilingManager เพื่อ ช่วยคุณรวบรวมข้อมูลเชิงลึกสำหรับแก้ไขข้อบกพร่องของปัญหาด้านประสิทธิภาพ

ทริกเกอร์ใหม่มีดังนี้

  • TRIGGER_TYPE_COLD_START: ทริกเกอร์จะเริ่มทำงานระหว่าง Cold Start ของแอป โดยจะแสดงตัวอย่างสแต็กการเรียกใช้และข้อมูลการติดตามระบบในการตอบกลับ
  • TRIGGER_TYPE_OOM: ทริกเกอร์จะเริ่มทำงานเมื่อแอปแสดง OutOfMemoryError และแสดง Java Heap Dump ในการตอบกลับ
  • TRIGGER_TYPE_KILL_EXCESSIVE_CPU_USAGE: ทริกเกอร์จะเริ่มทำงานเมื่อระบบปิดแอปเนื่องจากการใช้ CPU ผิดปกติและมากเกินไป และแสดงตัวอย่างสแต็กการเรียกใช้ในการตอบกลับ
  • TRIGGER_TYPE_ANOMALY: ตรวจหาความผิดปกติของประสิทธิภาพระบบ เช่น การเรียก Binder มากเกินไปและการใช้งานหน่วยความจำมากเกินไป

หากต้องการดูวิธีตั้งค่าทริกเกอร์ระบบ โปรดดูเอกสารประกอบเกี่ยวกับ การสร้างโปรไฟล์ตามทริกเกอร์และวิธีดึงและวิเคราะห์ข้อมูลการสร้างโปรไฟล์ เอกสารประกอบ

ทริกเกอร์การสร้างโปรไฟล์สำหรับความผิดปกติของแอป

Android 17 ขอแนะนำบริการตรวจหาความผิดปกติในอุปกรณ์ ซึ่งจะตรวจสอบลักษณะการทำงานที่ใช้ทรัพยากรมากและอาจเกิดการถดถอยด้านความเข้ากันได้ บริการนี้ผสานรวม กับ ProfilingManagerจึงช่วยให้แอปของคุณรับอาร์ติแฟกต์การสร้างโปรไฟล์ ที่ทริกเกอร์โดยเหตุการณ์ที่ระบบตรวจพบได้

ใช้ทริกเกอร์ TRIGGER_TYPE_ANOMALY เพื่อตรวจหาปัญหาด้านประสิทธิภาพของระบบ เช่น การเรียก Binder มากเกินไปและการใช้งานหน่วยความจำมากเกินไป เมื่อแอปละเมิดขีดจำกัดหน่วยความจำที่ระบบปฏิบัติการกำหนดไว้ ทริกเกอร์ความผิดปกติจะช่วยให้นักพัฒนาแอปได้รับ Heap Dump ที่เฉพาะเจาะจงกับแอปเพื่อช่วยระบุและแก้ไขปัญหาหน่วยความจำ นอกจากนี้ ทริกเกอร์ความผิดปกติยังแสดงโปรไฟล์แบบสุ่มตัวอย่างสแต็กในธุรกรรม Binder สำหรับการส่ง Binder Spam มากเกินไป

การเรียกกลับของ API นี้จะเกิดขึ้นก่อนการบังคับใช้ใดๆ ที่ระบบกำหนด เช่น ช่วยให้นักพัฒนาแอปเก็บรวบรวมข้อมูลการแก้ไขข้อบกพร่องได้ก่อนที่ระบบจะยุติแอปเนื่องจากใช้หน่วยความจำเกินขีดจำกัด

val profilingManager =
    applicationContext.getSystemService(ProfilingManager::class.java)
val triggers = ArrayList<ProfilingTrigger>()
triggers.add(ProfilingTrigger.Builder(ProfilingTrigger.TRIGGER_TYPE_ANOMALY))
val mainExecutor: Executor = Executors.newSingleThreadExecutor()
val resultCallback = Consumer<ProfilingResult> { profilingResult ->
    if (profilingResult.errorCode != ProfilingResult.ERROR_NONE) {
        // upload profile result to server for further analysis
        setupProfileUploadWorker(profilingResult.resultFilePath)
    }
    profilingManager.registerForAllProfilingResults(mainExecutor,
                                                    resultCallback)
    profilingManager.addProfilingTriggers(triggers)
}

API ของ JobDebugInfo

Android 17 ขอแนะนำ API JobDebugInfo ใหม่ที่จะช่วยนักพัฒนาแอปในการแก้ไขข้อบกพร่องของงาน JobScheduler เช่น เหตุผลที่งานไม่ทำงาน ระยะเวลาที่งานทำงาน และข้อมูลรวมอื่นๆ

เมธอดแรกของ API JobDebugInfo ที่ขยายแล้วคือ getPendingJobReasonStats() ซึ่งจะแสดงผลแผนผังของเหตุผลที่งานอยู่ใน สถานะรอการดำเนินการและระยะเวลารอสะสมของแต่ละเหตุผล เมธอดนี้จะเข้าร่วมกับเมธอด getPendingJobReasonsHistory() และ getPendingJobReasons() เพื่อให้ข้อมูลเชิงลึกเกี่ยวกับเหตุผลที่งานที่กำหนดเวลาไว้ไม่ทำงานตามที่คาดไว้ แต่จะลดความซับซ้อนในการดึงข้อมูลโดยทำให้ทั้งระยะเวลาและเหตุผลของงานพร้อมใช้งานในเมธอดเดียว

ตัวอย่างเช่น สำหรับ jobId ที่ระบุ เมธอดอาจแสดงผล PENDING_JOB_REASON_CONSTRAINT_CHARGING และระยะเวลา 60000 มิลลิวินาที ซึ่งบ่งชี้ว่างานรอเป็นเวลา 60000 มิลลิวินาทีเนื่องจากข้อจำกัดในการชาร์จไม่เป็นไปตามเงื่อนไข

ลด Wake Lock ด้วยการรองรับ Listener สำหรับการปลุกที่อนุญาตขณะไม่ได้ใช้งาน

Android 17 引入了 AlarmManager.setExactAndAllowWhileIdle 的新变体,该变体 接受 OnAlarmListener 而不是 PendingIntent。这种基于回调的新机制非常适合目前依赖于连续唤醒锁来执行定期任务的应用,例如维护套接字连接的消息传递应用。

ความเป็นส่วนตัว

Android 17 มีฟีเจอร์ใหม่ต่อไปนี้เพื่อปรับปรุงความเป็นส่วนตัวของผู้ใช้

การรองรับแพลตฟอร์มสำหรับ ClientHello ที่เข้ารหัส (ECH)

Android 17 เปิดตัวการรองรับแพลตฟอร์มสำหรับ Encrypted Client Hello (ECH) ซึ่งเป็นการปรับปรุงความเป็นส่วนตัวที่สำคัญสำหรับการสื่อสารผ่านเครือข่าย ECH เป็นส่วนขยายของ TLS 1.3 ที่เข้ารหัสการระบุชื่อเซิร์ฟเวอร์ (SNI) ระหว่างแฮนด์เชค TLS เริ่มต้น การเข้ารหัสนี้ช่วยปกป้องความเป็นส่วนตัวของผู้ใช้ด้วยการทำให้ตัวกลางในเครือข่ายระบุโดเมนที่เฉพาะเจาะจงซึ่งแอปเชื่อมต่อได้ยากขึ้น

ตอนนี้แพลตฟอร์มมี API ที่จำเป็นสำหรับไลบรารีระบบเครือข่ายเพื่อใช้ ECH แล้ว ซึ่งรวมถึงความสามารถใหม่ใน DnsResolver ในการค้นหาระเบียน DNS ของ HTTPS ที่มีการกำหนดค่า ECH และเมธอดใหม่ใน SSLEngines และ SSLSockets ของ Conscrypt เพื่อเปิดใช้ ECH โดยการส่งการกำหนดค่าเหล่านี้เมื่อเชื่อมต่อกับโดเมน นักพัฒนาแอปสามารถกำหนดค่ากำหนด ECH เช่น การเปิดใช้แบบมีโอกาสหรือการกำหนดให้ใช้ ผ่านองค์ประกอบใหม่ <domainEncryption> ภายในไฟล์การกำหนดค่าความปลอดภัยของเครือข่าย ซึ่งใช้ได้ทั่วโลกหรือในระดับโดเมน

คาดว่าไลบรารีเครือข่ายยอดนิยม เช่น HttpEngine, WebView และ OkHttp จะผสานรวม API ของแพลตฟอร์มเหล่านี้ในการอัปเดตในอนาคต ซึ่งจะช่วยให้แอปนำ ECH ไปใช้และปรับปรุงความเป็นส่วนตัวของผู้ใช้ได้ง่ายขึ้น

ดูข้อมูลเพิ่มเติมได้ที่เอกสารประกอบการทักทายไคลเอ็นต์ที่เข้ารหัส

เครื่องมือเลือกรายชื่อติดต่อ Android

เครื่องมือเลือกรายชื่อติดต่อ Android เป็นอินเทอร์เฟซที่ได้มาตรฐานและเรียกดูได้สำหรับผู้ใช้ในการแชร์รายชื่อติดต่อกับแอปของคุณ เครื่องมือเลือกนี้พร้อมใช้งานในอุปกรณ์ที่ใช้ Android 17 (ระดับ API 37) ขึ้นไป และเป็นทางเลือกที่ช่วยรักษาความเป็นส่วนตัวแทนREAD_CONTACTSแบบกว้าง แทนที่จะขอสิทธิ์เข้าถึงสมุดที่อยู่ทั้งหมดของผู้ใช้ แอปจะระบุฟิลด์ข้อมูลที่ต้องการ เช่น หมายเลขโทรศัพท์หรืออีเมล และผู้ใช้จะเลือกรายชื่อติดต่อที่ต้องการแชร์ได้ ซึ่งจะให้สิทธิ์แอปของคุณในการเข้าถึงแบบอ่านเฉพาะข้อมูลที่เลือก เพื่อให้ควบคุมได้อย่างละเอียดในขณะที่มอบประสบการณ์ของผู้ใช้ที่สอดคล้องกันด้วยความสามารถในการค้นหาในตัว การสลับโปรไฟล์ และการเลือกหลายรายการโดยไม่ต้องสร้างหรือบำรุงรักษา UI

ดูข้อมูลเพิ่มเติมได้ที่เอกสารประกอบของเครื่องมือเลือกรายชื่อติดต่อ

ความปลอดภัย

Android 17 เพิ่มฟีเจอร์ใหม่ต่อไปนี้เพื่อปรับปรุงความปลอดภัยของอุปกรณ์และแอป

โหมดการปกป้องขั้นสูงของ Android (AAPM)

โหมดการปกป้องขั้นสูงของ Android มอบฟีเจอร์ด้านความปลอดภัยชุดใหม่ที่ทรงพลังให้แก่ผู้ใช้ Android ซึ่งถือเป็นก้าวสำคัญในการปกป้องผู้ใช้ โดยเฉพาะผู้ที่มีความเสี่ยงสูงจากการโจมตีที่ซับซ้อน AAPM ออกแบบมาให้เป็นฟีเจอร์ที่เลือกใช้ได้ โดยจะเปิดใช้งานด้วยการตั้งค่าเดียวที่ผู้ใช้เปิดได้ทุกเมื่อ เพื่อใช้ชุดการป้องกันความปลอดภัยที่กำหนดไว้

การกำหนดค่าหลักเหล่านี้รวมถึงการบล็อกการติดตั้งแอปจากแหล่งที่มาที่ไม่รู้จัก (การโหลดจากแหล่งที่ไม่รู้จัก) การจำกัดการส่งสัญญาณข้อมูลผ่าน USB และการกำหนดให้สแกนด้วย Google Play Protect ซึ่งจะช่วยลดพื้นที่ผิวการโจมตีของอุปกรณ์ได้อย่างมาก นักพัฒนาแอปสามารถผสานรวมกับฟีเจอร์นี้ได้โดยใช้ API AdvancedProtectionManager เพื่อตรวจหาสถานะของโหมด ซึ่งจะช่วยให้แอปพลิเคชันใช้ท่าทีด้านความปลอดภัยที่เข้มงวดขึ้นโดยอัตโนมัติ หรือจำกัดฟังก์ชันการทำงานที่มีความเสี่ยงสูงเมื่อผู้ใช้เลือกใช้

การทำ APK Signing ด้วย PQC

ตอนนี้ Android รองรับ APK Signature Scheme แบบไฮบริดแล้ว เพื่อให้ข้อมูลประจำตัวสำหรับการลงนามของแอปปลอดภัยจากภัยคุกคามที่อาจเกิดขึ้นจากการโจมตีที่ใช้การประมวลผลควอนตัม ฟีเจอร์นี้จะแนะนำ APK Signature Scheme ใหม่ ซึ่งช่วยให้คุณจับคู่คีย์การลงนามแบบคลาสสิก (เช่น RSA หรือ EC) กับอัลกอริทึมวิทยาการเข้ารหัสหลังควอนตัม (PQC) ใหม่ (ML-DSA)

แนวทางแบบไฮบริดนี้ช่วยให้แอปของคุณยังคงปลอดภัยจากการโจมตีด้วยควอนตัมในอนาคต ขณะเดียวกันก็ยังคงความเข้ากันได้แบบย้อนหลังกับ Android เวอร์ชันเก่าและอุปกรณ์ที่ใช้การยืนยันลายเซ็นแบบคลาสสิกได้อย่างเต็มที่

ผลกระทบต่อนักพัฒนาแอป

  • แอปที่ใช้ Play App Signing: หากคุณใช้ Play App Signing คุณสามารถรอให้ Google Play มีตัวเลือกให้อัปเกรดลายเซ็นแบบไฮบริดโดยใช้คีย์ PQC ที่สร้างโดย Google Play ซึ่งจะช่วยให้แอปได้รับการปกป้องโดยไม่จำเป็นต้องจัดการคีย์ด้วยตนเอง
  • แอปที่ใช้คีย์ที่จัดการเอง: นักพัฒนาแอปที่จัดการคีย์การลงนามของตนเองสามารถใช้เครื่องมือสร้าง Android ที่อัปเดตแล้ว (เช่น apksigner) เพื่อเปลี่ยนไปใช้ข้อมูลประจำตัวแบบไฮบริด โดยรวมคีย์ PQC กับคีย์แบบคลาสสิกใหม่ (คุณต้องสร้างคีย์แบบคลาสสิกใหม่ โดยจะนำคีย์เก่ามาใช้ซ้ำไม่ได้)

การเชื่อมต่อ

Android 17 เพิ่มฟีเจอร์ต่อไปนี้เพื่อปรับปรุงการเชื่อมต่ออุปกรณ์และแอป

เครือข่ายดาวเทียมที่มีข้อจำกัด

实现优化,使应用能够在低带宽卫星网络上有效运行。

ประสบการณ์ของผู้ใช้และ UI ของระบบ

Android 17 มีการเปลี่ยนแปลงต่อไปนี้เพื่อปรับปรุงประสบการณ์ของผู้ใช้

สตรีมระดับเสียงของ Assistant โดยเฉพาะ

Android 17 เปิดตัวสตรีมระดับเสียงของผู้ช่วยโดยเฉพาะสำหรับแอป Assistant สำหรับการเล่นด้วย USAGE_ASSISTANT การเปลี่ยนแปลงนี้จะแยกเสียงของ Assistant ออกจากสตรีมสื่อมาตรฐาน เพื่อให้ผู้ใช้ควบคุมระดับเสียงทั้ง 2 อย่างแยกกันได้ ซึ่งจะช่วยให้ทำสิ่งต่างๆ ได้ เช่น ปิดเสียงการเล่นสื่อในขณะที่ยังคงได้ยินคำตอบของ Assistant และในทางกลับกัน

แอป Assistant ที่มีสิทธิ์เข้าถึงโหมดเสียง MODE_ASSISTANT_CONVERSATION ใหม่จะช่วยปรับปรุงความสอดคล้องในการควบคุมระดับเสียงได้ดียิ่งขึ้น แอป Assistant สามารถใช้ โหมดนี้เพื่อบอกใบ้ให้ระบบทราบเกี่ยวกับเซสชัน Assistant ที่ใช้งานอยู่ เพื่อให้มั่นใจว่าสามารถควบคุมสตรีมของ Assistant ได้นอกUSAGE_ASSISTANTการเล่นที่ใช้งานอยู่หรือด้วยอุปกรณ์ต่อพ่วงบลูทูธที่เชื่อมต่อ

Handoff

切换是 Android 17 中新增的一项功能和 API,应用开发者可以将其集成到应用中,以便为用户提供跨设备连续性。它允许用户在一个 Android 设备上启动应用 activity,然后将其转移到另一个 Android 设备。Handoff 在用户设备的后台运行,并通过各种入口点(例如接收设备上的启动器和任务栏)显示用户附近其他设备上的可用活动。

应用可以指定 Handoff 来启动相同的原生 Android 应用(如果该应用已安装在接收设备上且可供使用)。在此应用到应用流程中,用户通过深层链接跳转到指定 activity。或者,应用到网站切换功能可以作为后备选项提供,也可以通过网址切换功能直接实现。

切换支持是按 activity 实现的。如需启用 Handoff,请针对 activity 调用 setHandoffEnabled() 方法。可能需要随切换传递其他数据,以便接收设备上重新创建的 activity 可以恢复适当的状态。实现 onHandoffActivityDataRequested() 回调以返回 HandoffActivityData 对象,该对象包含用于指定 Handoff 应如何处理并在接收设备上重新创建 activity 的详细信息。

การอัปเดตแบบเรียลไทม์ - Semantic Color API

ใน Android 17 Live Update จะเปิดตัว Semantic Coloring API เพื่อ รองรับสีที่มีความหมายสากล

คลาสต่อไปนี้รองรับการระบายสีเชิงความหมาย

เกมระบายสี

  • สีเขียว: เกี่ยวข้องกับความปลอดภัย สีนี้ควรใช้ในกรณีที่ต้องการให้ผู้อื่นทราบว่าคุณอยู่ในสถานการณ์ที่ปลอดภัย
  • สีส้ม: สำหรับ ระบุข้อควรระวังและทำเครื่องหมายอันตรายทางกายภาพ ควรใช้สีนี้ในกรณีที่ผู้ใช้ต้องให้ความสนใจกับการตั้งค่าการปกป้องที่ดีขึ้น
  • สีแดง: โดยทั่วไปหมายถึงอันตราย หยุด ควรแสดงในกรณีที่ต้องการดึงดูดความสนใจของผู้คนอย่างเร่งด่วน
  • สีน้ำเงิน: สีที่เป็นกลางสำหรับเนื้อหาที่ให้ข้อมูลและควรโดดเด่นจากเนื้อหาอื่นๆ

ตัวอย่างต่อไปนี้แสดงวิธีใช้รูปแบบเชิงความหมายกับข้อความในการแจ้งเตือน

  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) 测距技术可让设备通过测量信号的相对到达时间来确定其相对于多个锚点的位置。

以下代码段演示了如何初始化 Ranging Manager、验证设备功能并启动 DL-TDoA 会话:

Kotlin

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

Java

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) 配置

以下代码段提供了 Wi-Fi 和 BLE 的 DL-TDoA OOB 配置数据示例:

Java

// 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()

Kotlin

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()

Java

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();