Apps foundation

การเปิดใช้การโต้ตอบข้ามอุปกรณ์ที่ราบรื่น

ลำโพง

เกี่ยวกับ

เกี่ยวกับการเสวนา

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

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

สรุป

  • Companion Device Manager จะแทนที่บริการที่ทำงานอยู่เบื้องหน้าสำหรับอุปกรณ์ต่อพ่วงบลูทูธโดยการปลุกแอปตามสถานะและจัดการการเชื่อมต่อโดยไม่ทำให้แบตเตอรี่หมด Android 17 เพิ่มโปรไฟล์ใหม่สำหรับอุปกรณ์ทางการแพทย์และเครื่องติดตามการเคลื่อนไหวโดยเฉพาะ
  • Jetpack Telecom ทำหน้าที่เป็นผู้ประสานงานการโทรของระบบสำหรับแอป VoIP ในอุปกรณ์ที่เชื่อมต่อ เช่น นาฬิกาและรถยนต์ โดยทำงานย้อนกลับไปถึง Android 8 นอกจากนี้ยังซิงค์การปิดเสียงและการวางสายผ่าน CallControlScope ด้วย
  • ฟีเจอร์ Jetpack Telecom 1.1.0 ที่กำลังจะเปิดตัว ได้แก่ ประวัติการโทรแบบรวมในแป้นโทรศัพท์ของระบบ (SDK 36.1 ขึ้นไป) และการแบ่งส่วนเครือข่าย 5G อัตโนมัติในเครือข่ายผู้ให้บริการที่รองรับ
  • SDK ของ Quick Share จะเปิดตัวในปีหน้าเพื่อให้นักพัฒนาแอปสามารถฝังการแชร์ไฟล์ที่เข้ารหัสจากต้นทางถึงปลายทางในเครื่องลงในแอป Android และ iOS ได้โดยตรง ฟีเจอร์แตะเพื่อแชร์ (เปิดตัวพร้อมกับ Pixel 11) ยังสามารถปลุกแอปที่รับข้อมูลซึ่งปิดอยู่ให้ทำงานโดยอัตโนมัติได้ด้วย

แหล่งข้อมูล

Gemini Notebook

หัวข้อ

  • หลายอุปกรณ์
  • companion-device-manager
  • jetpack-telecom
  • quick-share
  • บลูทูธ
  • voip
  • เพียร์ทูเพียร์

ข้อความถอดเสียง

ข้อมูลเบื้องต้นเกี่ยวกับการโต้ตอบข้ามอุปกรณ์

  • สวัสดีทุกคน

  • ยินดีต้อนรับสู่การเปิดใช้การโต้ตอบข้ามอุปกรณ์ที่ราบรื่น

  • ฉันชื่อ Hanrui และวันนี้ฉันมาพร้อมกับเพื่อนร่วมงานอย่าง Yacine และ Nataraj

  • เมื่อพูดถึงการเชื่อมต่อ สิ่งที่มักจะนึกถึงคือลิงก์เครือข่ายพื้นฐานหรือชุดหูฟังบลูทูธ

  • ใน Android การเชื่อมต่อจะครอบคลุมมากกว่านั้นมาก

  • ซึ่งเป็นเรื่องของการทำให้อุปกรณ์ทำงานร่วมกันได้ดียิ่งขึ้น

  • วันนี้เราจะอธิบายสถานการณ์การใช้งานข้ามอุปกรณ์ที่พบบ่อยและแสดงให้คุณเห็นว่า API ใดเหมาะกับแต่ละสถานการณ์

  • เป็นเวลานานพอสมควรที่เราเคยสร้างแอปสำหรับอุปกรณ์เดียว ซึ่งก็คือโทรศัพท์เท่านั้น

  • จากนั้นอุปกรณ์ที่สวมใส่ได้ก็เริ่มได้รับความนิยม

  • ในไม่ช้า การจับคู่สมาร์ทวอทช์กับโทรศัพท์ การซิงค์ข้อมูลในเบื้องหลัง หรือการรับสายโดยตรงก็กลายเป็นเรื่องปกติ

  • เพิ่มหูฟังไร้สาย

  • ตอนนี้ผู้ใช้สามารถเปลี่ยนอุปกรณ์เสียงระหว่างการโทรได้ ไม่ว่าจะเป็นจากนาฬิกาไปเป็นโทรศัพท์ หูฟังเอียร์บัด หรือรถยนต์

  • เมื่อไม่นานมานี้ ผู้ใช้จำนวนมากยังพกอุปกรณ์หน้าจอขนาดใหญ่เครื่องที่ 2 ด้วย เช่น อุปกรณ์แบบพับได้หรือแท็บเล็ต

  • ผู้ใช้คาดหวังว่าแอปจะทำงานได้อย่างราบรื่นในอุปกรณ์เหล่านี้

  • ซึ่งรวมถึงแล็ปท็อปและ Chromebook ที่ผู้ใช้สามารถเรียกใช้แอป Android และเชื่อมต่อได้จากโต๊ะทำงาน

  • แม้แต่ในปี 2023 ผู้ใช้ทั่วไปก็มีอุปกรณ์เฉลี่ย 3-4 เครื่อง

  • ผู้ใช้คาดหวังมากกว่าฟังก์ชันการทำงานแบบสแตนด์อโลนในอุปกรณ์เหล่านี้

  • ผู้ใช้ต้องการประสบการณ์การทำงานร่วมกันที่ดียิ่งขึ้นอย่างมาก

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

  • เมื่อดูจากตัวเลขแล้ว ระบบนิเวศนี้มีขนาดใหญ่และเติบโตอย่างรวดเร็ว

  • ในปีนี้ มีอุปกรณ์ IoT ประมาณ 2.2 หมื่นล้านเครื่องทั่วโลก ซึ่งเพิ่มขึ้น 14% เมื่อเทียบกับปีก่อน

  • และในบรรดาอุปกรณ์ปลายทางทั้งหมดนี้ Wi-Fi คิดเป็น 1 ใน 3 และบลูทูธคิดเป็น 1 ใน 4

  • การเชื่อมต่อข้ามอุปกรณ์ไม่ใช่เรื่องแปลกใหม่อีกต่อไป

  • ซึ่งเป็นส่วนหนึ่งของชีวิตประจำวันของเรา

  • แต่ในปัจจุบัน แอปส่วนใหญ่ยังคงสร้างฟีเจอร์ข้ามอุปกรณ์บน API เครือข่ายและบลูทูธระดับต่ำ ซึ่งทำให้เกิดความท้าทาย 3 ประการ

  • อย่างแรกคือแบตเตอรี่และหน่วยความจำ

  • การสแกนและบริการที่ทำงานอยู่เบื้องหลังอย่างต่อเนื่องจะทำให้แบตเตอรี่และหน่วยความจำหมดเร็วขึ้น

  • อย่างที่ 2 คือเวลาในการตอบสนอง

  • ความล่าช้าที่คาดเดาไม่ได้จะรบกวนการโทรและการซิงค์ข้อมูลแบบเรียลไทม์

  • และประการที่ 3 คือความยุ่งยากในการเชื่อมต่อ

  • การจัดการการค้นหา การจับคู่ และการเชื่อมต่ออีกครั้งในอุปกรณ์ทั้งหมดเป็นเรื่องที่ซับซ้อนและอาจทำให้ผู้ใช้ได้รับประสบการณ์การใช้งานที่ไม่ดีได้ง่ายๆ

  • เพื่อขจัดปัญหาที่น่าปวดหัวเหล่านั้น เราจึงได้สร้าง API ที่ออกแบบมาโดยเฉพาะใน 3 ด้านหลักๆ เพื่อให้ฟีเจอร์ข้ามอุปกรณ์ใช้งานได้ง่ายมาก

  • ฉันจะเริ่มด้วยแอปที่ใช้ร่วมกัน จากนั้น Nataraj จะพูดถึงแอป VoIP และ Yacine จะพูดถึงการแชร์แบบ P2P ในภายหลัง

ภาพรวมของแอปที่ใช้ร่วมกัน

  • มาดูแอปที่ใช้ร่วมกันก่อน

  • แอปที่ใช้ร่วมกันคือแอปที่คุณติดตั้งในโทรศัพท์เพื่อให้อุปกรณ์ที่ใช้ร่วมกัน เช่น สมาร์ทวอทช์หรือเซ็นเซอร์วัดระดับกลูโคส ทำงานร่วมกับโทรศัพท์ได้ดี

  • ในส่วนนี้ เราจะเน้นที่อุปกรณ์ที่เชื่อมต่อบลูทูธ

  • โดยทั่วไปแล้ว อุปกรณ์ที่ใช้ร่วมกันจะมี 4 หมวดหมู่

  • อย่างแรกคืออุปกรณ์ทางการแพทย์ เช่น เซ็นเซอร์วัดระดับน้ำตาลกลูโคสและเครื่องตรวจวัดสัญญาณชีพ

  • และอุปกรณ์ที่สวมใส่ได้ เช่น สมาร์ทวอทช์และสายรัดข้อมือเพื่อสุขภาพ

  • ชุดหูฟังที่มีการจับคู่ด่วนและการควบคุมอัจฉริยะ

  • และชุดอุปกรณ์ในรถยนต์สำหรับสิ่งต่างๆ เช่น กุญแจรถยนต์แบบดิจิทัลและการโทรแบบแฮนด์ฟรี

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

  • สำหรับอุปกรณ์ทางการแพทย์ การเชื่อมต่อดังกล่าวอาจมีความสำคัญต่อชีวิตด้วยซ้ำ

  • มาดูความต้องการที่พบบ่อย 4 ประการในหมวดหมู่เหล่านี้กัน

  • อย่างแรกคือการจัดการอุปกรณ์

  • แอปต้องค้นหาอุปกรณ์ที่ถูกต้องจากอุปกรณ์ทั้งหมดที่อยู่ใกล้เคียง เช่น นาฬิกา ไม่ใช่หูฟังเอียร์บัดหรือลำโพง จากนั้นจึงเริ่มขั้นตอนการจับคู่เพื่อเชื่อมต่อ

  • อย่างที่ 2 คือการตรวจสอบสถานะการอยู่บ้าน

  • แอปจำเป็นต้องทราบเมื่ออุปกรณ์อยู่ใกล้เคียงและเมื่ออุปกรณ์ไม่อยู่ในบริเวณนั้น

  • และเมื่ออุปกรณ์ปรากฏขึ้น แอปต้องมีวิธีปลุกให้ตื่นเพื่อให้ทำงานได้แม้ว่าผู้ใช้จะไม่ได้เปิดแอปก็ตาม

  • ประการที่ 3 การรักษาการเชื่อมต่อ

  • เมื่อเชื่อมต่อแล้ว แอปต้องการให้การเชื่อมต่อมีความเสถียรและต่อเนื่อง

  • หากการเชื่อมต่อขาดหาย เช่น ผู้ใช้เดินออกนอกระยะแล้วกลับเข้ามา แอปจะต้องเชื่อมต่อใหม่โดยอัตโนมัติ แม้ว่าแอปจะไม่ได้ทำงานอยู่ในขณะนั้นก็ตาม

  • และประการที่ 4 การซิงค์และการโอนข้อมูล

  • นี่คือจุดที่มูลค่าที่แท้จริงอยู่

  • ซิงค์ค่าที่อ่านได้จากเซ็นเซอร์ พุชการอัปเดตเฟิร์มแวร์ หรือส่งการตั้งค่าไปยังอุปกรณ์

  • ซึ่งอาจเป็นเรื่องสำคัญอย่างยิ่งสำหรับอุปกรณ์ทางการแพทย์

  • การพลาดการอ่านค่าอาจหมายถึงการพลาดการแจ้งเตือน

  • ทั้งหมดนี้ต้องใช้กระบวนการของแอปที่ทำงานอยู่และเชื่อมต่อในเวลาที่เหมาะสม

  • แล้วแอปจะตอบสนองความต้องการทั้งหมดนี้ได้อย่างไร

  • โดยปกติแล้ว แอปจะพึ่งพาบริการที่ทำงานอยู่เบื้องหน้าเป็นอย่างมาก

  • ตัวอย่างการใช้งานทั่วไปมีดังนี้

  • หากคุณเคยสร้างแอปที่ใช้ร่วมกันมาก่อน ขั้นตอนนี้อาจดูคุ้นเคย

  • คุณประกาศสิทธิ์การสแกนหาบลูทูธและเชื่อมต่อ สิทธิ์บริการที่ทำงานอยู่เบื้องหน้า และประเภทบริการที่ทำงานอยู่เบื้องหน้าของอุปกรณ์ที่เชื่อมต่อ จากนั้นประกาศสิทธิ์การแจ้งเตือนเนื่องจากบริการที่ทำงานอยู่เบื้องหน้าต้องแสดงการแจ้งเตือนแบบถาวร

    <uses-permission android:name="android.permission.BLUETOOTH_SCAN"
                     android:usesPermissionFlags="neverForLocation" />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" />
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
  • จากนั้นคุณเรียกใช้บริการแบบติดหนึบเพื่อคงกระบวนการของแอปไว้

    class BleForegroundService : Service() {
       override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
          …
          return START_STICKY
       }
    }
  • วิธีนี้ใช้ได้ผล แต่จะใช้แบตเตอรี่และหน่วยความจำเนื่องจากบริการทำงานตลอดเวลา แม้ว่าอุปกรณ์จะไม่ได้อยู่ใกล้ๆ ก็ตาม

  • เราจึงสร้าง Companion Device Manager หรือเรียกสั้นๆ ว่า CDM ขึ้นมา

  • ประการแรก ระบบสามารถปลุกแอปของคุณให้ทำงานตามการปรากฏตัวของอุปกรณ์ และตราบใดที่อุปกรณ์ยังอยู่ในระยะ ระบบจะทำให้กระบวนการของแอปทำงานต่อไป

  • ไม่จำเป็นต้องใช้บริการที่ทำงานอยู่เบื้องหน้า

  • ประการที่ 2 CDM รองรับโปรไฟล์อุปกรณ์

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

  • ซึ่งจะช่วยปรับปรุงประสบการณ์ของผู้ใช้และอัตรา Conversion ได้อย่างมาก

  • โปรไฟล์นาฬิกาพร้อมใช้งานตั้งแต่ Android 12 ส่วนแว่นตาพร้อมใช้งานตั้งแต่ Android 14

  • ใน Android 17 เราได้เพิ่มโปรไฟล์ใหม่ 2 รายการสำหรับอุปกรณ์ทางการแพทย์และเครื่องติดตามการเคลื่อนไหวโดยเฉพาะ

  • นอกจากนี้ยังมีโปรไฟล์ที่มีสิทธิ์พิเศษบางโปรไฟล์สำหรับแอประบบเท่านั้นในปัจจุบัน

  • หากเราทราบถึงความต้องการที่กว้างขึ้นจากระบบนิเวศ เราอาจพิจารณาเปิดให้ใช้งานสำหรับนักพัฒนาแอปจำนวนมากขึ้น

การติดตั้งใช้งานโดยใช้ Companion Device Manager

  • การใช้ CDM นั้นง่ายมาก

  • ลองใช้อุปกรณ์ทางการแพทย์เป็นตัวอย่าง

  • ก่อนอื่น ให้ประกาศสิทธิ์ที่จำเป็น ได้แก่ สิทธิ์สำหรับอุปกรณ์ทางการแพทย์ สิทธิ์ในการทำงานในเบื้องหลัง และสิทธิ์ในการสังเกตการปรากฏตัวของอุปกรณ์

    <uses-permission android:name="android.permission.REQUEST_COMPANION_PROFILE_MEDICAL" />
    <uses-permission android:name="android.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND" />
    <uses-permission android:name="android.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE" />
  • สิ่งหนึ่งที่ควรทราบคือ สิทธิ์ทั้งหมดที่ระบุไว้ที่นี่เป็นสิทธิ์ทั่วไป ซึ่งหมายความว่าจะได้รับสิทธิ์เมื่อติดตั้งโดยไม่มีกล่องโต้ตอบข้อความแจ้ง ซึ่งต่างจากสิทธิ์ที่เราเพิ่งเห็นในการใช้งานบริการที่ทำงานอยู่เบื้องหน้า

  • สิ่งเดียวที่ผู้ใช้ต้องอนุมัติคือการเชื่อมโยง

  • มาดูวิธีสร้างการเชื่อมโยงดังกล่าวกัน

  • ในที่นี้ เราจะสร้างคำขอการเชื่อมโยงที่มีตัวกรองอุปกรณ์เพื่อให้แสดงเฉพาะอุปกรณ์ที่ถูกต้องเท่านั้น

    val paringRequest = AssociationRequest.Builder()
       .addDeviceFilter(deviceFilter)
       .setSingleDevice(true)
       .setDeviceProfile(AssociationRequest.DEVICE_PROFILE_MEDICAL)
       .build()
    
    companionDeviceManager.associate(paringRequest, ContextCompat.getMainExecutor(this),
       object : CompanionDeviceManager.Callback() {
           override fun onAssociationPending(intentSender: IntentSender) {
               intentSenderLauncher.launch(IntentSenderRequest.Builder(intentSender).build())
           }
    
           override fun onAssociationCreated(associationInfo: AssociationInfo) { … }
    
           override fun onFailure(error: CharSequence?) { … }
       }
    )
  • setSingleDevice เป็น "จริง" เนื่องจากเราต้องการการจับคู่เพียงรายการเดียว และตั้งค่าโปรไฟล์เป็น "ทางการแพทย์"

  • จากนั้นโทรหาพนักงาน

  • CDM จะจัดการการสแกน

  • ใน onAssociationPending เราจะได้รับ IntentSender

  • เปิดแอป ระบบจะแสดงกล่องโต้ตอบการเชื่อมโยง

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

  • เมื่อผู้ใช้แตะ "อนุญาต" เราจะได้รับ onAssociationCreated พร้อม AssociationInfo ซึ่งรวมถึงรหัสการเชื่อมโยง

  • จากนั้นเราจะสังเกตการปรากฏตัวของอุปกรณ์ได้โดยเรียกใช้ startObservingDevicePresence ด้วยรหัสการเชื่อมโยงนั้น

  • และคุณยังต้องใช้บริการที่ขยาย CompanionDeviceService ด้วย

    class BleCompanionDeviceService : CompanionDeviceService() {
    
       override fun onDevicePresenceEvent(event: DevicePresenceEvent) {
           when (event.event) {
               DevicePresenceEvent.EVENT_BLE_APPEARED -> onDeviceAppeared(event.associationId)
               DevicePresenceEvent.EVENT_BLE_DISAPPEARED -> onDeviceDisappeared(event.associationId)
           }
       }
    
       private fun onDeviceAppeared(associationId: Int) { … }
    
       private fun onDeviceDisappeared(associationId: Int) { … }
    }
  • เมื่ออุปกรณ์อยู่ในระยะ ระบบจะเชื่อมโยงกับบริการของคุณแม้ว่าแอปจะไม่ได้ทำงานอยู่ก็ตาม

  • และระบบจะเรียก onDevicePresenceEvent ด้วย EVENT_BLE_APPEARED

  • จากนั้นคุณจะเชื่อมต่อและซิงค์ได้

  • เมื่ออุปกรณ์ออกจากพื้นที่ คุณจะได้รับEVENT_BLE_DISAPPEARED

  • จากนั้นคุณจะล้างข้อมูลได้

  • ไม่มีบริการที่เปิดตลอดเวลาและไม่มีการแจ้งเตือนเพื่อคงสถานะการทำงานไว้เท่านั้น

  • เราต้องยอมรับว่า CDM มีข้อจำกัดบางประการที่นักพัฒนาแอปต้องคำนึงถึง

  • อย่างแรกคือเวอร์ชันของระบบปฏิบัติการ

  • ฟีเจอร์ CDM ส่วนใหญ่เปิดตัวใน Android 12 และ 13

  • แต่มีการปรับปรุงที่น่าสนใจบางอย่างใน Android 16 และโปรไฟล์ใหม่ใน Android 17

  • ดังนั้น ให้ตรวจสอบเวอร์ชันระบบปฏิบัติการที่รันไทม์และเก็บเวอร์ชันสำรองไว้สำหรับเวอร์ชันเก่า

  • อย่างไรก็ตาม SDK เป้าหมายจะเพิ่มขึ้นทุกปีและ SDK ขั้นต่ำก็มักจะเพิ่มขึ้นตามไปด้วย

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

  • และหากคุณมีกรณีการใช้งานที่ CDM ยังไม่รองรับในปัจจุบัน โปรดแจ้งให้เราทราบ

  • ประการที่ 2 ปัจจุบัน CDM รองรับการสแกนในเบื้องหลัง แต่ไม่รองรับการกระจายข้อมูลในเบื้องหลัง

  • เราไม่ค่อยได้ยินว่ามีความต้องการในเรื่องนี้

  • แต่หากแอปของคุณต้องการให้โทรศัพท์ทำหน้าที่เป็นอุปกรณ์ต่อพ่วงและกระจายข้อมูลอย่างต่อเนื่องในเบื้องหลัง เรายินดีที่จะรับทราบข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้

  • 3. CDM ใช้โหมดสแกนพลังงานต่ำ

  • ซึ่งจะลดการตอบสนองแบบเรียลไทม์ลงเล็กน้อยเพื่อประหยัดแบตเตอรี่และหน่วยความจำ

  • ดังนั้นอย่าคาดหวังว่าอุปกรณ์จะตื่นขึ้นทันที

  • สุดท้ายคือไม่มีการแอบดูเพย์โหลด

  • คุณไม่สามารถลงทะเบียนเพื่อรับข้อมูลลักษณะเฉพาะหรือข้อมูลโฆษณาที่เจาะจงได้

  • แต่เมื่ออุปกรณ์อยู่ในระยะ แอปจะถูกปลุกขึ้นมา

  • เพื่อให้สามารถเชื่อมต่อและตรวจสอบเพย์โหลดได้ตามต้องการ

  • ทั้งหมดนี้คือข้อมูลเกี่ยวกับแอปที่ใช้ร่วมกันและ CDM

  • ฉันจะส่งต่อให้ Nataraj พูดถึงแอป VoIP

ปัญหาเกี่ยวกับการโทรผ่าน VoIP จากหลายอุปกรณ์

  • CompanionDeviceManager เป็นเครื่องมือที่เหมาะสมหากแอปของคุณมีอุปกรณ์ต่อพ่วงเฉพาะและสื่อสารผ่านอุปกรณ์ดังกล่าวอย่างต่อเนื่อง

  • สวัสดีทุกคน

  • ฉันชื่อ Nataraj K R

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

  • ปัจจุบัน วิธีที่ผู้คนจัดการกับการโทรเปลี่ยนไป

  • การโทรมากกว่า 40% เกิดขึ้นผ่านเครือข่าย VoIP

  • และ Android ก็มีบทบาทสำคัญในเรื่องนี้

  • อันที่จริงแล้ว 71% ของการโทรเหล่านั้นเกิดขึ้นในอุปกรณ์ Android ซึ่งก็เหมือนกับการโทรอื่นๆ ทั้งหมด

  • ไม่ใช่แค่การโทรเท่านั้น

  • ระบบนิเวศของอุปกรณ์ที่ผู้คนเป็นเจ้าของก็เติบโตขึ้นอย่างมากเช่นกัน

  • มีรถยนต์กว่า 250 ล้านคันที่ใช้ Android Auto อยู่บนท้องถนน และเรายังจัดส่งอุปกรณ์บลูทูธมากกว่า 1 พันล้านเครื่องให้แก่ผู้ใช้ด้วย

  • หูฟังเอียร์บัด, นาฬิกา Wear OS, Android, รถยนต์ที่ใช้ Android Auto, ลำโพงบลูทูธ ล้วนเป็นอุปกรณ์ที่ผู้ใช้มีอยู่รอบๆ โทรศัพท์ และผู้ใช้ต้องการให้การโทรดำเนินไปในอุปกรณ์ทั้งหมดนี้ได้อย่างราบรื่น

  • เช่น ผู้ใช้จะได้รับสายเรียกเข้า และจะเหลือบมองนาฬิกาเพื่อดูข้อมูลผู้โทร

  • ผู้ใช้จะรับสายบนนาฬิกา

  • โดยจะปิดหรือเปิดเสียงตามความจำเป็น และจะใส่หูฟังเอียร์บัดเพื่อโทรต่อ

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

  • ดังนั้น การดำเนินการนี้จึงกลายเป็นกิจวัตรปกติสำหรับผู้ใช้ และไม่ใช่ประสบการณ์การใช้งานแบบพรีเมียม

  • สำหรับผู้ใช้แล้ว นี่เป็นข้อกำหนดพื้นฐาน และเป็นหน้าที่ของนักพัฒนาแอป Android อย่างเราที่จะมอบประสบการณ์ที่ราบรื่นในแอป VoIP ให้แก่ผู้ใช้

  • แต่หากคุณพยายามสร้างทั้งหมดนี้ด้วยตนเองตั้งแต่ต้น คุณจะพบปัญหาหลัก 3 ประการ

  • หนึ่งคือการกระจาย Fragment ด้วยซ็อกเก็ตบลูทูธ

  • เนื่องจากระบบไม่ทราบว่าการโทรของคุณกำลังจัดการการโทรอยู่ คุณจึงต้องสร้างซ็อกเก็ตบลูทูธที่กำหนดเองและเซสชันสื่อที่กำหนดเองเพื่อให้สามารถฉายการโทรไปยังนาฬิกาหรือ Android Auto ได้

  • ปัญหาที่ 2 คือโฟกัสเสียง

  • เนื่องจากคุณต้องจัดการกับ AudioManager API และ Bluetooth API ระดับต่ำ จึงเกิดการรั่วไหลของเสียง และระบบไม่ได้ให้ความสำคัญกับเรื่องนี้ใช่ไหม

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

  • ที่แย่ที่สุดคือเมื่อใดก็ตามที่มีการโทร แม้ว่าการโทรผ่านเครือข่ายมือถือจะสิ้นสุดลงแล้ว แต่โฟกัสเสียงจะไม่กลับมาที่แอปของคุณ

  • และปัญหาที่ 3 คือการซิงค์ข้อมูล

  • ผู้ใช้แตะปิดเสียงในนาฬิกา แต่ UI ของโทรศัพท์จะยังคงแสดงการโทรเป็นแบบเปิดเสียงอยู่

  • ซึ่งทำให้เกิดความสับสนอย่างมาก

  • ผู้ใช้จะวางสายจากพวงมาลัยรถยนต์ แต่โทรศัพท์จะยังคงแสดงการแจ้งเตือนสายเรียกเข้าว่ามีสายที่กำลังดำเนินอยู่

  • ซึ่งเป็นเรื่องที่น่าหงุดหงิดมากสำหรับผู้ใช้เมื่อเกิดเหตุการณ์เช่นนั้น

ขอแนะนำ Jetpack Telecom

  • เราจึงสร้าง Jetpack Telecom ขึ้นมาเพื่อแก้ปัญหาทั้งหมดนี้โดยเฉพาะ

  • ดังนั้น คุณจึงลงทะเบียนการโทรกับ Jetpack Telecom เพียงครั้งเดียวโดยใช้ CallsManager และ Jetpack Telecom จะทำหน้าที่เป็นผู้ประสานงานการโทรของระบบส่วนกลาง

  • โดยมีหน้าที่รับผิดชอบในการฉายภาพการโทรไปยังนาฬิกาและ Android Auto รวมถึงแพลตฟอร์มระยะไกลอื่นๆ ที่ผู้ใช้เป็นเจ้าของ

  • และยังดูแลการจัดการโฟกัสเสียงด้วย

  • และที่สำคัญที่สุดคือทั้งหมดนี้ทำงานได้อย่างราบรื่นตั้งแต่ Android 8 เป็นต้นไป

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

  • ผู้ใช้จะต้องการปิดเสียงการโทรจากนาฬิกาหรือเปิดเสียงตามต้องการ

  • ผู้ใช้ต้องการวางสายจากพวงมาลัยรถยนต์หรือโดยการแตะหูฟังเอียร์บัด 2 ครั้ง

  • ดังนั้น Jetpack Telecom จะฟังเหตุการณ์ฮาร์ดแวร์เหล่านี้และแสดงเป็น Callback ทั้งหมดในที่เดียว ซึ่งก็คือ CallControlScope

  • สิ่งที่คุณต้องทำมีเพียงฟัง Callback เหล่านี้ จัดการเครื่องมือการโทร และอัปเดตสถานะการโทรตามความเหมาะสม

  • และ Jetpack Telecom จะรับผิดชอบในการซิงค์สถานะการโทรนี้ระหว่างอุปกรณ์ต่างๆ

  • ดังนั้นเบื้องหลังการทำงานของไลบรารีจึงให้ประโยชน์ 2 ด้าน

  • ข้อแรกคือช่วยแก้ปัญหาทั้งหมดที่เราพูดถึงได้อย่างชัดเจน

  • ดังนั้น แทนที่คุณจะต้องจัดการกับ AudioManager API ระดับต่ำ ไลบรารีจะให้ปลายทางการโทรแบบประกาศ จัดการโฟกัสเสียง และซิงค์ระหว่างอุปกรณ์

  • ซึ่งจะทำหน้าที่ส่งต่อการโทรระหว่างอุปกรณ์

  • และยังจัดการเมื่อมีสายโทรเข้าจากเครือข่ายมือถือด้วย

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

  • ดังนั้นจึงใช้ประโยชน์จากโครูทีน Kotlin และโครูทีน Kotlin นั้นจะยังคงทำงานอยู่จนกว่าการโทรจะสิ้นสุดลง

  • ดังนั้น งานที่คุณเรียกใช้เกี่ยวกับการโทรจะได้รับการล้างโดยอัตโนมัติทันทีที่การโทรถูกตัดการเชื่อมต่อ

  • ดังนั้น คุณจะไม่เหลืองานที่ผิดปกติ และวงจรการเรียกใช้จะได้รับการจัดการโดยไลบรารีด้วย

  • ตอนนี้คุณอาจสงสัยว่าไลบรารีที่ยอดเยี่ยมนี้ดีอย่างไรและต้องการนำไปใช้ใช่ไหม

  • ซึ่งทำได้ง่ายๆ เพียง 3 ขั้นตอน

  • ขั้นตอนที่ 1 คือคุณควรประกาศทรัพยากร Dependency อย่างชัดเจน

  • หลังจากนั้น ให้ประกาศสิทธิ์ที่จำเป็น ซึ่งก็คือ MANAGE_OWN_CALLS แล้วสร้างอินสแตนซ์ออบเจ็กต์ CallsManager

    <uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />
  • หลังจากสร้างอินสแตนซ์ออบเจ็กต์ CallsManager แล้ว ให้ลงทะเบียนแอปด้วยความสามารถที่ต้องการให้แอปมี เช่น วิดีโอคอลหรือการสตรีมการโทร

    // Initialize CallsManager & register supported capabilities once
    val callsManager = CallsManager(context)
    
    callsManager.registerAppWithTelecom(
        capabilities = CallsManager.CAPABILITY_SUPPORTS_VIDEO_CALLING or
                       CallsManager.CAPABILITY_SUPPORTS_CALL_STREAMING
    )
  • หลังจากนั้น ให้ทำตามขั้นตอนที่ 2

  • เมื่อลงทะเบียนแอปกับ Jetpack Telecom แล้ว ก็ถึงเวลาจัดการสายเรียกเข้าและสายโทรออก

  • คุณจึงต้องสร้างออบเจ็กต์ CallAttributesCompat ซึ่งเก็บข้อมูลเมตาของการโทร เช่น displayName ของผู้โทรหรือผู้รับสาย ที่อยู่ซึ่งเป็นปลายทางของผู้โทร ทิศทางที่ระบุว่าเป็นการโทรเข้าหรือโทรออกเพื่อให้ Jetpack Telecom แสดง UI ที่เกี่ยวข้องบนแพลตฟอร์มระยะไกลเหล่านี้ และcallType ไม่ว่าจะเป็นการโทรด้วยเสียงหรือวิดีโอคอลเพื่อให้คุณได้รับทรัพยากรที่จำเป็น

    val attributes = CallAttributesCompat(
        displayName = "Kukk Nat",
        address = Uri.parse("tel:+16505550199"),
        direction = CallAttributesCompat.DIRECTION_INCOMING,
        callType = CallAttributesCompat.CALL_TYPE_AUDIO_CALL
    )
    
    callsManager.addCall(
        attributes, onAnswer, onDisconnect, onSetActive, onSetInactive
    ) {
        // Coroutine CallControlScope active for the duration of the call
    }
  • เมื่อออบเจ็กต์ข้อมูลเมตาพร้อมแล้ว ให้เพิ่มออบเจ็กต์ดังกล่าวโดยใช้เมธอด callsManager.addCall

  • ซึ่งจะเปิดขอบเขตโครูทีนการควบคุมการโทร

  • เมื่อเพิ่มคลิปของคุณเสร็จแล้ว ขั้นตอนที่ 3

  • ขั้นตอนที่ 3 คือการฟังการดำเนินการที่ผู้ใช้จะทำจากแพลตฟอร์มระยะไกลเหล่านั้น

  • ดังนั้น เนื่องจากคุณมี CallControlScope สิ่งที่คุณต้องทำก็คือรวบรวม Kotlin Flow

    callsManager.addCall(attributes, onAnswer, onDisconnect, onSetActive, onSetInactive) {
        // 1. React to hardware mute toggles from Watch, Car, or Headset
        launch {
            isMuted.collect { muted -> audioEngine.setMicMuted(muted) }
        }
    
        // 2. Observe available endpoints & request declarative switches
        launch {
            currentCallEndpoint.collect { endpoint -> updateUi(endpoint) }
        }
        requestEndpointChange(preferredBluetoothEndpoint)
    }
  • คุณรวบรวม isMuted เพื่อตอบสนองเมื่อใดก็ตามที่ผู้ใช้ปิดเสียงการโทรจากแพลตฟอร์มระยะไกลเหล่านั้น และคุณสามารถอัปเดตสถานะการโทรได้ตามความเหมาะสม

  • รวบรวม currentCallEndpoint เพื่อให้ทราบว่าการโทรเกิดขึ้นที่ปลายทางใดในปัจจุบัน เพื่อให้คุณอัปเดต UI ได้ตามความเหมาะสม

  • คุณสามารถแสดงอุปกรณ์นั้นๆ ใน UI ของโทรศัพท์ได้

  • และเมื่อใดก็ตามที่ผู้ใช้ต้องการเปลี่ยนจากอุปกรณ์หนึ่งไปยังอีกอุปกรณ์หนึ่ง เพียงเรียกใช้เมธอด requestEndpointChange โดยใช้ปลายทางที่ผู้ใช้ต้องการ

  • ง่ายๆ เพียงเท่านี้

  • เพียงทำตาม 3 ขั้นตอนนี้ แอปของคุณก็พร้อมใช้งานและผสานรวม Jetpack Telecom แล้ว

  • แต่ความสนุกยังไม่หมดเพียงเท่านี้

  • Jetpack Telecom 1.1.0 มาพร้อมฟีเจอร์อื่นๆ อีกมากมาย เช่น ประวัติการโทรแบบรวม ซึ่งหมายความว่าการโทรผ่าน VoIP ทั้งหมดจะแสดงในแป้นโทรศัพท์ของระบบโดยค่าเริ่มต้น

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

  • คุณจึงไม่จำเป็นต้องไปค้นหาแอปที่ต้องการจากแอปทั้งหมด

  • ผู้ใช้สามารถเริ่มการโทรกลับจากแป้นโทรศัพท์ของระบบที่คุ้นเคยได้เลย

  • แต่สำหรับบางคน แต่ถ้าคุณ แต่เราก็มีการควบคุมแบบละเอียดให้ด้วย

  • หากไม่ต้องการให้ระบบบันทึกการโทรบางรายการ คุณเพียงแค่ต้องตั้งค่าแฟล็ก isLogExcluded เป็น "จริง" ภายในออบเจ็กต์ CallAttributesCompat

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

  • และฟีเจอร์ที่ยอดเยี่ยมอย่างที่ 2 ที่จะมาพร้อมกับเวอร์ชัน 1.1.0 คือการแบ่งส่วนเครือข่าย 5G

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

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

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

  • แต่หากไม่ต้องการใช้ฟีเจอร์นี้ด้วยเหตุผลบางประการ คุณก็เลือกไม่ใช้ได้โดยใช้แฟล็ก CAPABILITY_OPT_OUT_OF_PREMIUM_NETWORK

  • แอปการสื่อสารชั้นนำระดับโลก เช่น Google Meet, WhatsApp, KakaoTalk และ Zoho Arattai ได้นำ Jetpack Telecom ไปใช้แล้ว

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

  • เมื่อพูดถึงการโทรแบบเรียลไทม์แล้ว ฉันขอส่งต่อไมค์ให้ Yacine เพื่อนร่วมงานที่ยอดเยี่ยมของฉันเพื่อพูดถึงฟีเจอร์แตะเพื่อแชร์

  • ขอขอบคุณ

ความท้าทายในการแชร์แบบเพียร์ทูเพียร์

  • เอาล่ะทุกคน เรารู้ว่าคุณอาจจะเหนื่อยกันนิดหน่อย แต่ไม่ต้องกังวลไป นี่เป็นส่วนสุดท้ายแล้ว

  • ดังนั้นฉันจะพูดถึงการแชร์ไฟล์แบบเพียร์ทูเพียร์ แต่กรณีการใช้งานอื่นๆ เราก็สามารถทำได้ด้วยการแชร์แบบเพียร์ทูเพียร์เช่นกัน

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

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

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

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

  • แต่ก็ไม่ได้ดีมาก

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

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

  • ซึ่งไม่ใช่ประสบการณ์การใช้งานที่ดีที่สุดที่คุณต้องการได้รับจากอุปกรณ์ระดับพรีเมียม

  • อย่างที่ 2 คือตอนนี้ไฟล์มีขนาดค่อนข้างใหญ่

  • รูปภาพ 1 รูปมีขนาด 10 MB ได้ง่ายๆ วิดีโอความยาว 5 นาทีมีขนาดประมาณ 500 MB ดังนั้นการอัปโหลดและดาวน์โหลดไฟล์ทั้งหมดจึงใช้เวลานานพอสมควร

  • และสุดท้าย ในอีกด้านหนึ่ง คุณต้องรอให้เวลาในการตอบสนองนั้นผ่านไป

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

  • ดังนั้น แทนที่จะต้องพึ่งพาระบบคลาวด์เพื่อแชร์ไฟล์ทั้งหมดและต้องรอให้ระบบทำงานจนเสร็จ ทำไมไม่ใช้เครือข่ายในพื้นที่ เช่น บลูทูธหรือ Wi-Fi ล่ะ

  • แต่ถ้าคุณพยายามทำด้วยตัวเอง แน่นอนว่าคุณจะต้องจัดการกับตัวจัดการบลูทูธ ตัวจัดการ Wi-Fi และต้องเขียนโปรโตคอลของคุณเอง ซึ่งไม่ใช่ทุกคนที่อยากจะเสียเวลาทำแบบนั้น

  • แต่จริงๆ แล้ว Android มีฟีเจอร์ที่ทำแบบนี้ได้อยู่แล้ว

  • ฟีเจอร์นี้พร้อมใช้งานแล้วและคุณอาจเคยได้ยินมาบ้าง นั่นคือ Quick Share

ภาพรวมของ Quick Share

  • Quick Share ใน Android ช่วยให้คุณมีนามธรรมนี้อยู่ในระบบอยู่แล้ว และคุณสามารถแชร์ไฟล์กับอุปกรณ์อื่นได้โดยไม่ต้องจัดการทั้งหมดนั้น

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

  • และสุดท้าย UI และ UX ที่คุ้นเคยซึ่งคุณเห็นที่ด้านข้างจะช่วยผู้ใช้ของคุณได้เป็นอย่างดี

  • ดังนั้นผู้ใช้จะรู้ว่า UI คืออะไร และไม่จำเป็นต้องเรียนรู้วิธีใช้เพราะเคยเห็นมาแล้วในอดีต

  • แต่เราทราบดีว่านักพัฒนาแอปต้องการเป็นเจ้าของประสบการณ์ด้วยเช่นกัน

  • คุณรู้จักแอปและผู้ใช้ของคุณดีกว่าเรา

  • ดังนั้น Quick Share จึงเป็นฟีเจอร์ที่ควรมีในแอปของคุณโดยตรง

  • เราจึงเริ่มพูดคุยกับนักพัฒนาแอปและเห็นว่า Quick Share มีการใช้งานอย่างแพร่หลายอยู่แล้ว

  • โดยพร้อมให้บริการใน Android, Chromebook, Google Books และ Windows ซึ่งรวมแล้วมีอุปกรณ์มากกว่า 3 พันล้านเครื่องเลยทีเดียว

  • นอกจากนี้ เรายังเพิ่มความสามารถในการแตะเพื่อแชร์ใน Pixel 11 ด้วย

  • ดังนั้น แทนที่จะต้องเลือกอุปกรณ์ที่ต้องการแชร์ด้วย คุณก็แค่แตะและใช้ NFC ซึ่งเราจะทำให้คุณค้นพบอุปกรณ์ได้โดยตรง

  • คุณจึงเลือกรูปภาพได้ แต่ก็เลือกไฟล์ได้ด้วย เพียงแตะอุปกรณ์ 2 เครื่องเข้าด้วยกัน แล้วไฟล์ก็จะแชร์โดยตรงด้วยการชนกัน

  • และเราทราบดีว่านักพัฒนาซอฟต์แวร์ต้องการเป็นเจ้าของประสบการณ์

  • เราทราบดีว่านี่เป็นวิธีที่ดีที่สุดที่ผู้ใช้จะใช้ฟีเจอร์ที่เฉพาะเจาะจงได้ ซึ่งในกรณีนี้คือการแชร์ไฟล์

  • ดังนั้น ทำไมไม่ฝัง Quick Share ไว้ในแอปของคุณล่ะ

  • ดังนั้นในปีหน้า เราจะนำ Quick Share SDK มาให้คุณโดยตรง

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

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

  • และสำหรับอุปกรณ์ที่รองรับ Wi-Fi Direct ฟีเจอร์นี้จะรวมอยู่แล้ว

  • และไฟล์ที่คุณถ่ายด้วยกล้องที่ยอดเยี่ยมจะยังคงความละเอียดและรายละเอียดที่ดีที่สุดไว้ เพื่อให้คุณดูไฟล์เหล่านั้นบนหน้าจอขนาดใหญ่ได้อย่างสวยงาม

  • และเนื่องจากฟีเจอร์นี้อาศัยเครือข่ายในพื้นที่ คุณจึงใช้ฟีเจอร์นี้ในรถไฟใต้ดินได้ แม้จะอยู่ในส่วนที่ลึกที่สุด คุณก็ยังคงมีเครือข่ายที่สามารถแชร์กับเพื่อนได้

  • แม้จะอยู่บนเครื่องบินที่บินอยู่สูงจากพื้นดินหลายพันฟุต คุณก็ยังแชร์ไฟล์เหล่านั้นได้

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

  • นอกจากนี้ คุณยังไม่ต้องบำรุงรักษาเซิร์ฟเวอร์ของคุณเองด้วย

  • และเมื่อปีที่แล้ว เราได้แจ้งให้นักพัฒนาแอปและผู้ใช้ทราบว่า Quick Share จะช่วยให้แชร์ไฟล์กับอุปกรณ์ iPhone ผ่าน AirDrop ได้

  • Quick Share จะช่วยให้นักพัฒนาแอปทำสิ่งเดียวกันนี้ได้

  • เราจะมี Quick Share iOS SDK สำหรับนักพัฒนาแอปที่มีแอป iOS เพื่อให้สามารถแชร์ไฟล์ระหว่างทั้ง 2 แพลตฟอร์มได้ ไม่ว่าจะใช้อุปกรณ์ใดก็ตาม

  • ทั้งหมดนี้เป็นเพียงการนำเสนอที่สวยงามเท่านั้น ตอนนี้เรามาดูโค้ดกันแบบเร็วๆ ดีกว่า

  • เราพยายามทำให้กระบวนการนี้ง่ายที่สุดเท่าที่จะเป็นไปได้

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

    // Final API may undergo further updates
    val quickShareClient = QuickShareClient.create(activity)
    val attachment = FileAttachment(
      fileName = "report.pdf",
      size = 1_048_576L,
      uri = fileUri,
      mimeType = "application/pdf",
      // Sensitive content will be masked in preview
      isSensitiveContent = false,
    )
    
    val content = ShareableContent.withFiles(listOf(attachment))
    val request = SharingRequest.withContent(content)
    val session = quickShareClient.startSharingSession(request, lifecycleOwner)
  • เมื่อต้องการรับไฟล์ คุณก็ทำแบบเดียวกันในแอป แน่นอนว่าในกรณีนี้คุณไม่ได้เพิ่มไฟล์แนบ และทันทีที่เซสชันเริ่มต้นขึ้น คุณก็ไม่ต้องจัดการกับเรื่องนั้นเลย

    // Final API may undergo further updates
    val quickShareClient = QuickShareClient.create(activity)
    val request = SharingRequest.withoutContent()
    val session = quickShareClient.startSharingSession(request, lifecycleOwner)
    
    // Open the Quick Share overlay in receive mode
    session.launchWindow(activity, contentSelectionIntent = null)
  • จนถึงตอนนี้ คุณได้เห็นโค้ดเพียง 20 บรรทัดจากทั้ง 2 ฝั่ง

  • เรารู้ว่า Quick Share และการแตะเพื่อแชร์ ซึ่งเป็นความสามารถในการแชร์ไฟล์โดยการแตะอุปกรณ์นั้นช่วยให้เกิด Use Case ใหม่ได้จริงๆ

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

    // Final API may undergo further updates
    val quickShareClient = QuickShareClient.create(activity)
    val urlAttachment = TextAttachment(
      text = groupAddUrl,
      type = TextAttachment.Type.URL,
    )
    
    val content = ShareableContent.withText(urlAttachment)
    val appLink = AppLink("https://myapp.com/group/invite")
    val request = SharingRequest.withContent(content, appLink)
    val session = quickShareClient.startSharingSession(request, lifecycleOwner)
  • ดังนั้น คุณจึงไม่จำเป็นต้องเปิดแอปในอุปกรณ์ที่รับ

  • เมื่อแตะเพื่อแชร์ ระบบจะเปิดแอปนั้นโดยอัตโนมัติ

  • และแน่นอนว่าหากต้องการให้ UI ตอบสนองต่อการโอนไฟล์นั้น คุณก็แค่ใช้ Kotlin Flow และคุณจะมีเหตุการณ์ทั้งหมดเพื่อให้สามารถประมวลผลได้

    // Final API may undergo further updates
    scope.launch {
      for (event in session.sharingEvents) {
        when (event) {
          is SharingEvent.SendComplete ->
            println("Send finished")
          is SharingEvent.ReceiveComplete ->
            println("Received, files=${event.content?.files?.size}")
          else -> println("other event")
        }
      }
    }

สรุปและสรุปผล

  • เราได้เห็นข้อมูลมากมายในวันนี้ ดังนั้นเราจะสรุปให้ฟัง

  • และไม่ต้องกังวล คุณจะมีเวลาพักสักครู่

  • CompanionDeviceManager เป็น API ที่ดีที่สุดสำหรับคุณในการจัดการการโต้ตอบผ่านบลูทูธและการโต้ตอบผ่านบลูทูธอย่างต่อเนื่อง ดังที่ Hanrui ได้นำเสนอไปก่อนหน้านี้

  • หากแอปของคุณมีการโทรผ่านอินเทอร์เน็ต (VoIP) กรณีการใช้งานนี้ไม่จำเป็นต้องเป็นกรณีการใช้งานหลัก เช่น คุณอาจมีส่วนสนับสนุนลูกค้าในแอปที่ผู้ใช้สามารถโทรหาฝ่ายสนับสนุนได้

  • ในกรณีนี้ วิธีที่ดีที่สุดในการจัดการการโทรผ่านอินเทอร์เน็ตบน Android คือการใช้ Jetpack Telecom

  • และสุดท้าย สำหรับการแชร์ไฟล์แบบเพียร์ทูเพียร์หรือการเปิดแอป อย่างที่ฉันได้กล่าวไปแล้วว่า Quick Share เป็นโซลูชันสำหรับการแตะเพื่อแชร์

  • ขอขอบคุณทุกคน และก่อนจะจากกันไป เรามีเรื่องสั้นๆ จะบอกว่าเราจะอยู่ข้างนอกหลังจากนี้เพื่อตอบคำถามของคุณ

  • เรามีเวลาทำการหากคุณมีคำถามเกี่ยวกับกรณีการใช้งานทั้งหมดที่เรานำเสนอ

  • และอย่าลืมแชร์สิ่งที่คุณได้เรียนรู้จากการพูดคุยหรือเซสชันอื่นๆ บนโซเชียลมีเดียด้วย

  • เรามี #AndroidDevSummit

  • ขอย้ำอีกครั้งว่าการได้รู้ว่าเรามีส่วนร่วมและมีผู้ที่ชื่นชอบกิจกรรมนี้จริงๆ เป็นสิ่งสำคัญอย่างยิ่งสำหรับเรา

  • ซึ่งช่วยให้เราทราบว่าเรามีชุมชนที่ต้องการเห็นอีกครั้งอย่างแน่นอน

  • และรับจี้ห้อยกระเป๋าธีมโซเชียลที่คุณสามารถนำไปติดกับพวงกุญแจบ็อต Android ได้ที่โต๊ะประชาสัมพันธ์

  • ฉันทำถูกไหม

  • ขอขอบคุณ

รหัส

ข้อมูลโค้ด

ข้อมูลโค้ด XML ที่นาที 06:17 ใน "ภาพรวมของแอปที่ใช้ร่วมกัน"
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
                 android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
ข้อมูลโค้ด Kotlin ที่นาที 06:34 ใน "ภาพรวมของแอปที่ใช้ร่วมกัน"
class BleForegroundService : Service() {
   override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
      …
      return START_STICKY
   }
}
ข้อมูลโค้ด XML ที่นาที 08:03 ใน "การติดตั้งใช้งานโดยใช้ Companion Device Manager"
<uses-permission android:name="android.permission.REQUEST_COMPANION_PROFILE_MEDICAL" />
<uses-permission android:name="android.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND" />
<uses-permission android:name="android.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE" />
ข้อมูลโค้ด Kotlin ที่ 08:38 ใน "การติดตั้งใช้งานโดยใช้ Companion Device Manager"
val paringRequest = AssociationRequest.Builder()
   .addDeviceFilter(deviceFilter)
   .setSingleDevice(true)
   .setDeviceProfile(AssociationRequest.DEVICE_PROFILE_MEDICAL)
   .build()

companionDeviceManager.associate(paringRequest, ContextCompat.getMainExecutor(this),
   object : CompanionDeviceManager.Callback() {
       override fun onAssociationPending(intentSender: IntentSender) {
           intentSenderLauncher.launch(IntentSenderRequest.Builder(intentSender).build())
       }

       override fun onAssociationCreated(associationInfo: AssociationInfo) { … }

       override fun onFailure(error: CharSequence?) { … }
   }
)
ข้อมูลโค้ด Kotlin ที่นาที 09:47 ใน "การติดตั้งใช้งานโดยใช้ Companion Device Manager"
class BleCompanionDeviceService : CompanionDeviceService() {

   override fun onDevicePresenceEvent(event: DevicePresenceEvent) {
       when (event.event) {
           DevicePresenceEvent.EVENT_BLE_APPEARED -> onDeviceAppeared(event.associationId)
           DevicePresenceEvent.EVENT_BLE_DISAPPEARED -> onDeviceDisappeared(event.associationId)
       }
   }

   private fun onDeviceAppeared(associationId: Int) { … }

   private fun onDeviceDisappeared(associationId: Int) { … }
}
ข้อมูลโค้ด XML ที่ 18:29 ใน "Introducing Jetpack Telecom"
<uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />
ข้อมูลโค้ด Kotlin ที่นาที 18:36 ใน "ขอแนะนำ Jetpack Telecom"
// Initialize CallsManager & register supported capabilities once
val callsManager = CallsManager(context)

callsManager.registerAppWithTelecom(
    capabilities = CallsManager.CAPABILITY_SUPPORTS_VIDEO_CALLING or
                   CallsManager.CAPABILITY_SUPPORTS_CALL_STREAMING
)
ข้อมูลโค้ด Kotlin ที่ 18:55 ใน "ขอแนะนำ Jetpack Telecom"
val attributes = CallAttributesCompat(
    displayName = "Kukk Nat",
    address = Uri.parse("tel:+16505550199"),
    direction = CallAttributesCompat.DIRECTION_INCOMING,
    callType = CallAttributesCompat.CALL_TYPE_AUDIO_CALL
)

callsManager.addCall(
    attributes, onAnswer, onDisconnect, onSetActive, onSetInactive
) {
    // Coroutine CallControlScope active for the duration of the call
}
ข้อมูลโค้ด Kotlin ที่นาที 19:49 ใน "ขอแนะนำ Jetpack Telecom"
callsManager.addCall(attributes, onAnswer, onDisconnect, onSetActive, onSetInactive) {
    // 1. React to hardware mute toggles from Watch, Car, or Headset
    launch {
        isMuted.collect { muted -> audioEngine.setMicMuted(muted) }
    }

    // 2. Observe available endpoints & request declarative switches
    launch {
        currentCallEndpoint.collect { endpoint -> updateUi(endpoint) }
    }
    requestEndpointChange(preferredBluetoothEndpoint)
}
ข้อมูลโค้ด Kotlin ที่ 29:31 ใน "ภาพรวมของ Quick Share"
// Final API may undergo further updates
val quickShareClient = QuickShareClient.create(activity)
val attachment = FileAttachment(
  fileName = "report.pdf",
  size = 1_048_576L,
  uri = fileUri,
  mimeType = "application/pdf",
  // Sensitive content will be masked in preview
  isSensitiveContent = false,
)

val content = ShareableContent.withFiles(listOf(attachment))
val request = SharingRequest.withContent(content)
val session = quickShareClient.startSharingSession(request, lifecycleOwner)
ข้อมูลโค้ด Kotlin ที่นาที 29:57 ใน "ภาพรวมของ Quick Share"
// Final API may undergo further updates
val quickShareClient = QuickShareClient.create(activity)
val request = SharingRequest.withoutContent()
val session = quickShareClient.startSharingSession(request, lifecycleOwner)

// Open the Quick Share overlay in receive mode
session.launchWindow(activity, contentSelectionIntent = null)
ข้อมูลโค้ด Kotlin ที่นาที 30:23 ใน "ภาพรวมของ Quick Share"
// Final API may undergo further updates
val quickShareClient = QuickShareClient.create(activity)
val urlAttachment = TextAttachment(
  text = groupAddUrl,
  type = TextAttachment.Type.URL,
)

val content = ShareableContent.withText(urlAttachment)
val appLink = AppLink("https://myapp.com/group/invite")
val request = SharingRequest.withContent(content, appLink)
val session = quickShareClient.startSharingSession(request, lifecycleOwner)
ข้อมูลโค้ด Kotlin ที่นาที 30:49 ใน "ภาพรวมของ Quick Share"
// Final API may undergo further updates
scope.launch {
  for (event in session.sharingEvents) {
    when (event) {
      is SharingEvent.SendComplete ->
        println("Send finished")
      is SharingEvent.ReceiveComplete ->
        println("Received, files=${event.content?.files?.size}")
      else -> println("other event")
    }
  }
}