Software Engineer
Dalam sesi ini, kita akan membahas secara mendalam aspek teknis evolusi dari Kartu layar penuh ke Widget Wear dinamis dengan tinggi parsial.
Kita akan mempelajari manfaat teknis dari Jetpack Glance API terpadu dan mesin Remote Compose baru, serta menguraikan cara keduanya selaras dengan Modern Android Development.
Terakhir, kami akan membagikan panduan UX terbaru dan membahas strategi migrasi praktis untuk membantu Anda membangun UI sekilas generasi berikutnya.
Transkrip
Halo semuanya.
Nama saya Frank, dan saya memimpin tim pengalaman sekilas untuk Wear OS.
Smartwatch adalah pendamping penting sepanjang hari bagi pengguna Anda, dan hari ini, kami akan memandu Anda memanfaatkan pengalaman Widget Wear yang baru.
Kita akan membahas dua cara untuk menghadirkan fitur paling penting langsung ke pergelangan tangan pengguna, dan kita akan melakukannya menggunakan API terbaru, API yang dirancang untuk membuat proses pengembangan untuk Wear OS terasa familier dan intuitif bagi developer Android, seperti Anda.
Hari ini, rekan saya yang cerdas dan teman satu meja saya, Yuri, akan bergabung dengan saya di panggung untuk membahas cara kami melakukannya.
Halo, saya Yuri Schimke.
Saya adalah engineer di tim Wear OS, dan fokus utama saya adalah mengerjakan Remote Compose API.
Hari ini, saya akan memberikan pengantar singkat tentang Remote Compose, lalu membahas proses migrasi dari Kartu ke Widget Wear.
Sekarang, saya akan mengembalikan presentasi ini kepada Frank.
Bagus.
Terima kasih, Yuri.
Kami secara resmi menghadirkan smartwatch ke dalam ekosistem widget Android terpadu dengan mengembangkan Kartu layar penuh menjadi Widget Wear.
Dan karena pengalaman ini sekarang dibuat menggunakan Jetpack Glance, Anda dapat melihat bahwa infrastruktur dasar yang sama digunakan untuk widget seluler.
Anda akan melihat bahwa membangun untuk Wear akan menjadi lebih mudah bagi Anda di masa mendatang.
Untuk mendukung pengalaman ini, kami mengembangkan stack UI, yaitu stack UI yang mendasarinya.
Widget Wear didukung oleh Remote Compose, framework Android baru untuk UI jarak jauh.
Artinya, Anda akhirnya dapat menggunakan API deklaratif yang sangat selaras dengan Jetpack Compose untuk membangun pengalaman di luar aplikasi, seperti widget.
Remote Compose menghadirkan grafis modern dan tata letak responsif ke widget sekaligus memastikan performa dan efisiensi baterai.
Dengan memisahkan UI dari proses aplikasi, widget Anda akan diserialisasi dengan aman dan dirender dengan mudah di berbagai perangkat Android.
Artinya, Anda dapat menghadirkan pengalaman yang kaya ini ke hampir semua platform jarak jauh yang didukung dengan upaya minimal.
Untuk membuat transisi dari Kartu ke widget semulus mungkin, kami memperkenalkan dua ukuran penampung standar: kecil dan besar.
Format ini dirancang agar selaras dengan format widget berbasis petak dua kali satu dan dua kali dua yang sudah biasa Anda gunakan dengan membuat widget di perangkat seluler.
Dan mulai Wear 7 di beberapa produsen hardware, Widget Wear Anda kini akan berada di baki scroll vertikal bersama widget aplikasi lain.
Misalnya, seperti inilah tampilan Wear Widgets di Samsung Galaxy Watch.
Arsitektur platform dibuat untuk mendukung baki scroll vertikal karena produsen hardware akan mengadopsi pola ini di masa mendatang.
Anda juga tidak perlu khawatir akan meninggalkan pengguna, atau pengguna yang sudah ada.
API Jetpack Glance Wear dirancang untuk mendukung kompatibilitas mundur hingga Wear 4.
Pada perangkat lama yang mendukung baki widget atau Kartu horizontal, sistem akan menanganinya untuk Anda.
Anda hanya perlu menyatakan dalam kode bahwa Anda ingin mendukung mode layar penuh, dan sistem akan mengambil widget besar Anda dan menampilkannya sebagai Kartu tradisional layar penuh di perangkat ini.
Sekarang, Yuri akan memandu kita mempelajari kode untuk menunjukkan cara memigrasikan Kartu yang ada ke Widget Wear.
Terima kasih, Frank.
Jika Anda membuat Widget Wear baru dari awal, caranya mudah.
Anda hanya perlu menentukan GlanceWearWidgetService dan membangun UI menggunakan Remote Compose.
Namun, jika aplikasi Anda sudah memiliki Kartu dalam produksi, Anda harus memigrasikan layanan, UI, dan data.
Untuk membuat transisi ini selancar mungkin, kami telah menyediakan jalur untuk memastikan pengalaman yang lancar bagi pengguna yang sudah ada.
Untuk layanan, Anda dapat memilih antara dua strategi: layanan ganda atau layanan tunggal.
Dengan layanan ganda, yang kami rekomendasikan, Anda akan mempertahankan TileService yang ada untuk perangkat Wear OS lama dan menambahkan GlanceWearWidgetService baru untuk Wear OS 7+.
Sebaliknya, dengan layanan tunggal, Anda membuat GlanceWearWidgetService tunggal baru yang menangani kedua protokol, yang berjalan dalam mode kompatibilitas untuk menerjemahkan widget Anda menjadi Kartu di perangkat lama.
Apa pun caranya, Anda akan terus menjangkau pengguna.
Hal ini hanya memengaruhi kode yang Anda kelola ke depannya.
Kami juga baru saja memublikasikan dokumentasi komprehensif di situs developer Android yang menjelaskan secara mendetail cara dan waktu penggunaan kedua pola ini.
Lihat artikel tersebut untuk mempelajari lebih lanjut strategi yang paling sesuai untuk aplikasi Anda.
Sekarang, mari kita bahas lapisan UI.
Saat bermigrasi, model mental Anda akan berubah.
Sebelumnya, kartu menggunakan ProtoLayout, library yang dibuat khusus untuk kartu Wear.
Di sisi lain, Widget Wear dibuat di atas Remote Compose.
Remote Compose memiliki fondasi yang sama persis dengan UI Jetpack Compose, menggunakan compiler dan runtime inti yang sama.
Library ini dirancang agar terasa familier, sangat mirip dengan library Compose UI seperti foundation dan Material 3.
Namun, alih-alih kotak, kolom, atau teks, Anda cukup menukarnya dengan RemoteBox, RemoteColumn, atau RemoteText.
Dalam hal ini, Anda akan sering menulis "remote".
Selain itu, untuk mempercepat alur kerja Anda, kami telah menyertakan satu set lengkap komponen Remote Compose siap pakai yang dirancang khusus untuk widget.
Artinya, desain Wear Material 3 yang sudah ada, termasuk yang Anda miliki di Figma, dapat dengan mudah disesuaikan dengan widget, sehingga memudahkan engineer dan desainer.
Untuk melihat seberapa selarasnya framework ini, mari kita lihat contoh konkretnya.
Kita akan membuat komponen aplikasi sendiri di atas tombol beralih Material 3.
Di sebelah kiri, kita memiliki komponen Wear Compose standar yang akan Anda tulis di dalam aplikasi, dan di sebelah kanan adalah versi Remote Compose.
// Wear Compose
@Composable
fun HistoryEraserButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
checked: Boolean = true,
onCheckedChange: (Boolean) -> Unit = {},
)// Wear RemoteCompose
@RemoteComposable
@Composable
fun RemoteHistoryEraserButton(
onClick: Action,
modifier: RemoteModifier = RemoteModifier,
checked: RemoteBoolean = true.rb,
onCheckedChange: Action = Action.Empty,
)Perhatikan kemiripan polanya.
Namun, saat menulis kode Remote Compose, Anda akan menggunakan anotasi RemoteComposable.
Dan jika Anda menggunakan parameter yang sudah dikenal seperti pengubah dan boolean, parameter tersebut memiliki jenis Remote Compose yang setara seperti RemoteModifier dan RemoteBoolean.
Dan Anda menggunakan tindakan, bukan lambda.
Alih-alih menentukan eksekusi ke kode yang akan dieksekusi di dalam lambda, Anda harus mendeklarasikan tindakan seperti meluncurkan intent tertunda, memanggil layanan, atau memperbarui nilai.
Mari kita beralih ke isi komponen.
Anda akan melihat bahwa tema pun selaras.
Anda dapat menerapkan skema warna Material 3 ke komponen Remote Compose persis seperti yang Anda lakukan di Compose standar, yang memungkinkan widget Anda sama persis dengan branding aplikasi Anda.
// Wear Compose
val colors = MaterialTheme.colorScheme
SplitSwitchButton(
checked = checked,
onCheckedChange = onCheckedChange,
toggleContentDescription = "Arm Eraser",
onContainerClick = onClick,
modifier = modifier.fillMaxWidth(),
colors =
SwitchButtonDefaults.splitSwitchButtonColors(
checkedContainerColor = colors.errorContainer, …
),
label = { Text("History Eraser") },
secondaryLabel = { Text("Don't touch it!") },
)// Wear RemoteCompose
val colors = RemoteMaterialTheme.colorScheme
RemoteSplitSwitchButton(
checked = checked,
onCheckedChange = onCheckedChange,
toggleContentDescription = "Arm Eraser".rs,
onContainerClick = onClick,
modifier = modifier.fillMaxWidth(),
colors =
RemoteSplitSwitchButtonDefaults.splitSwitchButtonColors(
checkedContainerColor = colors.errorContainer, …
),
label = { RemoteText("History Eraser".rs) },
secondaryLabel = { RemoteText("Don't touch it!".rs) },
)Dan terakhir, mari kita lihat hasilnya. UI yang dihasilkan persis seperti yang Anda harapkan, tombol beralih animasi yang bersih, responsif, dan responsif.
Sulit untuk membedakannya.
Untuk membantu Anda mendesain, melakukan iterasi, dan memverifikasi tata letak widget tanpa harus selalu menjalankannya di perangkat atau emulator, kami telah menambahkan dukungan pratinjau Compose untuk Widget Wear.
Karena widget bergantung pada batasan container khusus OEM, seperti ukuran, bentuk, padding, radius sudut, kami membangun anotasi pratinjau standar, tetapi dengan penyedia parameter tambahan untuk memasukkan konfigurasi ini.
@Preview(name = "Squircle Preview", device = "spec:width=1000dp,height=1000dp,dpi=320")
@Composable
fun WeatherWidgetSquirclePreview(
@PreviewParameter(SquircleAllWidgetPreviewParams::class) params: WearWidgetParams
) = WearWidgetPreview(MockWeatherWidget(65, WeatherCondition.CLOUDY), params)
@Preview(name = "Round Preview", device = "spec:width=1000dp,height=1000dp,dpi=320")
@Composable
fun WeatherWidgetRoundPreview(
@PreviewParameter(RoundAllWidgetPreviewParams::class) params: WearWidgetParams
) = WearWidgetPreview(MockWeatherWidget(65, WeatherCondition.CLOUDY), params)Library ini menyediakan implementasi penyedia PreviewParameter yang telah dikonfigurasi sebelumnya dan sesuai dengan perangkat Wear OS di dunia nyata.
Anotasi pratinjau ini memungkinkan Anda memverifikasi tata letak dengan mudah di berbagai bentuk hardware yang sangat berbeda.
Selain menguji tata letak, Anda dapat menggunakan pratinjau ini untuk membuat gambar statis yang diperlukan untuk alat pilih widget di perangkat.
@Preview(name = "Widget Picker Preview", device = "spec:width=1000dp,height=1000dp,dpi=320")
@Composable
fun WeatherWidgetRectangularPreview(
@PreviewParameter(RectangularAllWidgetPreviewParams::class) params: WearWidgetParams
) = WearWidgetPreview(MockWeatherWidget(65, WeatherCondition.CLOUDY), params)Library ini menyediakan parameter untuk bentuk pratinjau persegi panjang yang mengemulasi penampung persegi panjang penuh yang tidak dipangkas.
Jika Anda ingin melihat cara kerjanya dalam praktik, kami telah memperbarui aplikasi contoh media Horologist untuk menyertakan widget baru yang menampilkan API ini.
Kami menunjukkan cara menambahkan widget media versi kecil dan besar.
Lihat di GitHub untuk melihat perbandingan berdampingan antara kode ProtoLayout lama dan implementasi Remote Compose baru.
Kami yakin Anda akan menyukainya.
Terakhir, ini tidak akan menjadi, Anda tahu, sebuah diskusi tanpa menyebutkan AI.
Untuk mempercepat migrasi Anda, kami telah memublikasikan keterampilan migrasi kartu ke widget baru di GitHub.
Anda dapat menggunakannya dengan agen pilihan Anda, atau Anda dapat menambahkannya langsung ke Android Studio menggunakan Android CLI.
android skills add wear-widgets
android skills add --allSekarang, saya akan mengembalikan Anda kepada François untuk mengakhiri sesi ini.
Terima kasih.
Terima kasih, Yuri.
Jadi, seperti yang Anda lihat, mengembangkan kartu menjadi Widget Wear adalah proses yang sangat mudah.
Singkatnya, dengan bermigrasi ke Jetpack Glance Wear dan Remote Compose, Anda tidak hanya mengupdate UI, tetapi juga bergabung dengan ekosistem widget Android yang lebih terpadu.
Sekarang Anda dapat mem-build widget yang menarik dan kompatibel dengan versi lama menggunakan framework deklaratif modern yang sepenuhnya selaras dengan Jetpack Compose.
Anda dapat mulai memigrasikan kartu sekarang dengan membuka panduan Memulai di situs Android Developers untuk mengetahui semua detailnya.
Kami menantikan semua pengalaman ekspresif dan sekilas yang Anda bangun untuk smartwatch.
Terima kasih banyak telah bergabung bersama kami hari ini, pagi ini, dan kami harap Anda menikmati sisa konferensi ini.
Terima kasih.
// Wear Compose
@Composable
fun HistoryEraserButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
checked: Boolean = true,
onCheckedChange: (Boolean) -> Unit = {},
)// Wear RemoteCompose
@RemoteComposable
@Composable
fun RemoteHistoryEraserButton(
onClick: Action,
modifier: RemoteModifier = RemoteModifier,
checked: RemoteBoolean = true.rb,
onCheckedChange: Action = Action.Empty,
)// Wear Compose
val colors = MaterialTheme.colorScheme
SplitSwitchButton(
checked = checked,
onCheckedChange = onCheckedChange,
toggleContentDescription = "Arm Eraser",
onContainerClick = onClick,
modifier = modifier.fillMaxWidth(),
colors =
SwitchButtonDefaults.splitSwitchButtonColors(
checkedContainerColor = colors.errorContainer, …
),
label = { Text("History Eraser") },
secondaryLabel = { Text("Don't touch it!") },
)// Wear RemoteCompose
val colors = RemoteMaterialTheme.colorScheme
RemoteSplitSwitchButton(
checked = checked,
onCheckedChange = onCheckedChange,
toggleContentDescription = "Arm Eraser".rs,
onContainerClick = onClick,
modifier = modifier.fillMaxWidth(),
colors =
RemoteSplitSwitchButtonDefaults.splitSwitchButtonColors(
checkedContainerColor = colors.errorContainer, …
),
label = { RemoteText("History Eraser".rs) },
secondaryLabel = { RemoteText("Don't touch it!".rs) },
)@Preview(name = "Squircle Preview", device = "spec:width=1000dp,height=1000dp,dpi=320")
@Composable
fun WeatherWidgetSquirclePreview(
@PreviewParameter(SquircleAllWidgetPreviewParams::class) params: WearWidgetParams
) = WearWidgetPreview(MockWeatherWidget(65, WeatherCondition.CLOUDY), params)
@Preview(name = "Round Preview", device = "spec:width=1000dp,height=1000dp,dpi=320")
@Composable
fun WeatherWidgetRoundPreview(
@PreviewParameter(RoundAllWidgetPreviewParams::class) params: WearWidgetParams
) = WearWidgetPreview(MockWeatherWidget(65, WeatherCondition.CLOUDY), params)@Preview(name = "Widget Picker Preview", device = "spec:width=1000dp,height=1000dp,dpi=320")
@Composable
fun WeatherWidgetRectangularPreview(
@PreviewParameter(RectangularAllWidgetPreviewParams::class) params: WearWidgetParams
) = WearWidgetPreview(MockWeatherWidget(65, WeatherCondition.CLOUDY), params)android skills add wear-widgets
android skills add --all