วิศวกรนักพัฒนาซอฟต์แวร์สัมพันธ์
เมื่อผู้ใช้เปลี่ยนไปมาระหว่างโทรศัพท์ อุปกรณ์ที่สวมใส่ได้ และอุปกรณ์ต่อพ่วงเสียง การมอบประสบการณ์การใช้งานข้ามอุปกรณ์ที่ราบรื่นจึงกลายเป็นสิ่งสำคัญสำหรับการมีส่วนร่วม อย่างไรก็ตาม การพึ่งพาวิธีการสร้างเครือข่ายมาตรฐานมักทำให้แบตเตอรี่หมดเร็ว เวลาในการตอบสนองเพิ่มขึ้นอย่างรวดเร็ว และเซสชันของผู้ใช้กระจัดกระจาย
ข้อมูลเจาะลึกนี้จะแนะนำ Android API เฉพาะทางที่สร้างขึ้นสำหรับการสื่อสารแบบหลายอุปกรณ์ โดยนำเสนอรูปแบบที่ประหยัดหน่วยความจำและพลังงานเพื่อให้การเปลี่ยนระหว่างอุปกรณ์เป็นไปอย่างรวดเร็ว เชื่อถือได้ และใช้งานง่าย
ข้อความถอดเสียง
สวัสดีทุกคน
ยินดีต้อนรับสู่การเปิดใช้การโต้ตอบข้ามอุปกรณ์ที่ราบรื่น
ฉันชื่อ 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 รายการสำหรับอุปกรณ์ทางการแพทย์และเครื่องติดตามการเคลื่อนไหวโดยเฉพาะ
นอกจากนี้ยังมีโปรไฟล์ที่มีสิทธิ์พิเศษบางโปรไฟล์สำหรับแอประบบเท่านั้นในปัจจุบัน
หากเราทราบถึงความต้องการที่กว้างขึ้นจากระบบนิเวศ เราอาจพิจารณาเปิดให้ใช้งานสำหรับนักพัฒนาแอปจำนวนมากขึ้น
การใช้ 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
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 เพียงครั้งเดียวโดยใช้ 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 ใน 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 ได้ที่โต๊ะประชาสัมพันธ์
ฉันทำถูกไหม
ขอขอบคุณ
<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
}
}<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?) { … }
}
)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) { … }
}<uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />// Initialize CallsManager & register supported capabilities once
val callsManager = CallsManager(context)
callsManager.registerAppWithTelecom(
capabilities = CallsManager.CAPABILITY_SUPPORTS_VIDEO_CALLING or
CallsManager.CAPABILITY_SUPPORTS_CALL_STREAMING
)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(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)
}// 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)// 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)// 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")
}
}
}