Uygulama temeli

Jetpack Glance ve Remote Compose kullanarak kartları Wear widget'larına dönüştürme

Hoparlörler

  • François Deschênes

    Ürün Müdürü

  • Yuri Schimke

    Yazılım Mühendisi

Hakkında

Konuşma hakkında

Bu oturumda, tam ekran Kartlar'dan dinamik, kısmi yükseklikteki Wear Widget'larına geçişi teknik açıdan ayrıntılı bir şekilde inceleyeceğiz.

Birleştirilmiş Jetpack Glance API'nin ve yeni Remote Compose motorunun teknik avantajlarını inceleyerek bunların Modern Android Geliştirme ile nasıl sorunsuz bir şekilde uyum sağladığını ayrıntılı olarak ele alacağız.

Son olarak, en yeni kullanıcı deneyimi kılavuzunu paylaşacak ve yeni nesil göz atılabilir kullanıcı arayüzünü oluşturmanıza yardımcı olacak pratik geçiş stratejilerini inceleyeceğiz.

Özet

  • Wear OS, tam ekran Kartlar'ı Jetpack Glance ile oluşturulan ve Remote Compose tarafından desteklenen Wear Widget'larına dönüştürüyor.
  • Remote Compose, kullanıcı arayüzünüzü uygulama sürecinden güvenli bir şekilde ayırırken Jetpack Compose kullanıcı arayüzü ile aynı derleyiciyi ve çalışma zamanını paylaşır.
  • Küçük ve büyük kapsayıcı boyutları mobil ızgara biçimleriyle uyumludur. Jetpack Glance Wear API'leri ise Wear 4'e kadar geriye dönük uyumluluğu korur.
  • Mevcut Kartları widget'lara taşırken önerilen çift hizmet stratejisini veya tek bir uyumluluk hizmetini kullanabilirsiniz.

Beceriler

Kaynaklar

Gemini Notebook

Konular

  • wear-os
  • wear-widgets
  • jetpack-glance
  • remote-compose
  • tiles-migration
  • jetpack-compose

Transkript

Giriş

  • Merhaba,

  • Adım Frank. Wear OS'te bir bakışta bilgi edinme deneyimlerinden sorumlu ekibin yöneticisiyim.

  • Saatler, kullanıcılarınızın gün boyu yanlarından ayırmadığı vazgeçilmez aksesuarlardır. Bugün, yeni Wear widget'ları deneyiminden nasıl yararlanacağınızı anlatacağız.

  • En önemli özelliklerinizi doğrudan kullanıcılarınızın bileğine ulaştırmanın iki yolunu inceleyeceğiz. Bunu yaparken, Wear OS için geliştirme yapmayı sizin gibi Android geliştiricilerine tanıdık ve sezgisel hissettirmek üzere tasarlanmış en yeni API'leri kullanacağız.

  • Bunu tam olarak nasıl yaptığımızı incelemek için bugün sahnede bana eşlik edecek olan kişi, muhteşem meslektaşım ve masa arkadaşım Yuri.

  • Merhaba, ben Yuri Schimke.

  • Wear OS ekibinde mühendis olarak çalışıyorum ve asıl odak noktam Remote Compose API'leri üzerinde çalışmak.

  • Bugün size Uzaktan Oluşturma'yı kısaca tanıtacak ve ardından Kartlar'dan Wear Widget'larına geçiş sürecinden bahsedeceğim.

  • Şimdi sözü tekrar Frank'e bırakıyorum.

Kartlar, Wear Widget'larına Dönüşüyor

  • Müthiş.

  • Teşekkürler, Yuri.

  • Tam ekran Kartlarımızı Wear widget'larına dönüştürerek bilek cihazlarını birleşik Android widget ekosistemine resmen dahil ediyoruz.

  • Bu deneyimler artık Jetpack Glance kullanılarak oluşturulduğundan, mobil widget'lar için kullanılan altyapının aynısı olduğunu görebilirsiniz.

  • Gelecekte Wear için uygulama geliştirmenin sizin için daha da tanıdık hale geldiğini göreceksiniz.

Uzaktan Oluşturma'ya genel bakış

  • Bu deneyimleri desteklemek için kullanıcı arayüzü yığınını (temel kullanıcı arayüzü yığını) geliştiriyoruz.

  • Wear widget'ları, uzaktan kullanıcı arayüzü için yeni bir Android çerçevesi olan Remote Compose tarafından desteklenir.

  • Bu sayede, widget'lar gibi uygulama dışı deneyimlerinizi oluşturmak için Jetpack Compose ile yakından uyumlu bir açıklayıcı API kullanabilirsiniz.

  • Remote Compose, performans ve pil verimliliği sağlarken widget'lara modern grafikler ve duyarlı düzenler getirir.

  • Kullanıcı arayüzünüzü uygulama sürecinden ayırarak widget'larınız güvenli bir şekilde serileştirilir ve çeşitli Android cihazlarda kolayca oluşturulur.

  • Bu sayede, bu zengin deneyimleri desteklenen tüm uzaktan yüzeylere minimum çabayla taşıyabilirsiniz.

Düzen boyutları ve geriye dönük uyumluluk

  • Kartlardan widget'lara geçişi olabildiğince sorunsuz hale getirmek için iki standart kapsayıcı boyutu sunuyoruz: küçük ve büyük.

  • Bu widget'lar, mobil cihazlarda widget oluştururken alışık olduğunuz 2x1 ve 2x2 ızgara tabanlı widget biçimleriyle uyumlu olacak şekilde tasarlanmıştır.

  • Bazı donanım üreticilerinin Wear 7 sürümünden itibaren Wear widget'larınız artık diğer uygulamaların widget'larıyla birlikte dikey olarak kaydırılan bir tepside yer alacak.

  • Örneğin, Wear widget'ları Samsung Galaxy Watch'ta bu şekilde görünür.

  • Platform mimarisi, donanım üreticilerinin gelecekte bu modeli benimsemesiyle dikey olarak kaydırılan tepsileri destekleyecek şekilde tasarlanmıştır.

  • Ayrıca, mevcut kullanıcıları geride bırakma konusunda endişelenmenize gerek yoktur.

  • Jetpack Glance Wear API'leri, Wear 4'e kadar geriye dönük uyumluluğu destekleyecek şekilde tasarlanmıştır.

  • Yatay widget veya Kart tepsisini destekleyen eski cihazlarda sistem bu işlemi sizin için gerçekleştirir.

  • Kodunuzda tam ekran modunu desteklemek istediğinizi belirtmeniz yeterlidir. Sistem, büyük widget'ınızı alır ve bu cihazlarda tam ekran geleneksel Kartlar olarak gösterir.

  • Şimdi Yuri, mevcut Kartlarınızı Wear widget'larına nasıl taşıyacağınızı tam olarak göstermek için kodu inceleyecek.

Mevcut kartlar için taşıma stratejileri

  • Teşekkürler Frank.

  • Sıfırdan yeni bir Wear widget'ı oluşturuyorsanız bu işlem basittir.

  • GlanceWearWidgetService tanımlayıp Remote Compose kullanarak kullanıcı arayüzünüzü oluşturmanız yeterlidir.

  • Ancak uygulamanızın üretimde bir Kart'ı varsa hem hizmetlerinizi hem de kullanıcı arayüzünüzü ve verilerinizi taşımanız gerekir.

  • Bu geçişin mümkün olduğunca sorunsuz olmasını sağlamak için mevcut kullanıcıların sorunsuz bir deneyim yaşamasını sağlayacak yollar sunduk.

  • Hizmet için iki strateji arasından seçim yapabilirsiniz: çift hizmet veya tek hizmet.

  • Önerdiğimiz ikili hizmette, eski Wear OS cihazlar için mevcut TileService'inizi kullanmaya devam eder ve Wear OS 7 ve sonraki sürümler için yeni bir GlanceWearWidgetService eklersiniz.

  • Buna karşılık, tek hizmette her iki protokolü de işleyen yeni ve tek bir GlanceWearWidgetService oluşturursunuz. Bu hizmet, widget'ınızı eski cihazlarda kartlara dönüştürmek için uyumluluk modunda çalışır.

  • Her iki durumda da kullanıcılarınıza ulaşmaya devam edersiniz.

  • Yalnızca gelecekte hangi kodu kullanacağınızı etkiler.

  • Ayrıca, Android geliştirici sitesinde bu iki kalıbın tam olarak nasıl ve ne zaman kullanılacağını ayrıntılı bir şekilde açıklayan kapsamlı bir doküman yayınladık.

  • Uygulamanız için en uygun stratejinin hangisi olduğunu öğrenmek için bu kılavuzu inceleyin.

Remote Compose ile kullanıcı arayüzü oluşturma

  • Şimdi kullanıcı arayüzü katmanından bahsedelim.

  • Geçiş yaparken zihinsel modeliniz değişir.

  • Kartlar daha önce yalnızca Wear kartları için oluşturulmuş bir kitaplık olan ProtoLayout'u kullanıyordu.

  • Wear Widget'ları ise Remote Compose'u temel alır.

  • Remote Compose, Jetpack Compose kullanıcı arayüzü ile aynı temele sahiptir ve aynı temel derleyici ile çalışma zamanını kullanır.

  • Ayrıca, Foundation ve Material 3 gibi Compose kullanıcı arayüzü kitaplıklarıyla yakından eşleşerek tanıdık bir his verecek şekilde tasarlanmıştır.

  • Ancak kutu, sütun veya metin yerine bunları RemoteBox, RemoteColumn veya RemoteText ile değiştirirsiniz.

  • Bu durumda, "remote" (uzak) kelimesini sık sık yazmaya alışacaksınız.

  • Ayrıca iş akışınızı hızlandırmak için widget'lara özel olarak tasarlanmış, kullanıma hazır Remote Compose bileşenlerini de ekledik.

  • Bu sayede, Figma'da bulunanlar da dahil olmak üzere mevcut Wear Material 3 tasarımlarınız widget'lara kolayca uyarlanabilir. Bu da hem mühendisler hem de tasarımcılar için tanıdık bir deneyim sunar.

  • Bu çerçevelerin ne kadar uyumlu olduğunu görmek için somut bir örneğe bakalım.

  • Material 3 anahtar düğmesinin üzerine kendi uygulama bileşenimizi oluşturacağız.

  • Solda, uygulamanızın içine yazacağınız standart Wear Compose bileşeni, sağda ise Remote Compose sürümü yer alıyor.

    // 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,
    )
  • Modellerin ne kadar benzer olduğuna dikkat edin.

  • Ancak Remote Compose kodu yazarken RemoteComposable ek açıklamasını kullanırsınız.

  • Değiştirici ve boole gibi tanıdık parametreleri kullandığınız yerlerde, RemoteModifier ve RemoteBoolean gibi eşdeğer Remote Compose türleri bulunur.

  • Lambda yerine işlem kullanırsınız.

  • Lambda içinde yürütülecek kodu tanımlamak yerine, beklemede olan intent'i başlatma, hizmet çağırma veya bir değeri güncelleme gibi bir işlem bildirmeniz gerekir.

  • Şimdi bileşenimizin gövdesine geçelim.

  • Temanın bile uyumlu olduğunu fark edeceksiniz.

  • Material 3 renk şemanızı standart Compose'da olduğu gibi Remote Compose bileşenine uygulayabilirsiniz. Böylece widget'ınız, uygulamanızın markasıyla tam olarak eşleşir.

    // 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) },
      )
  • Son olarak sonuca bakalım. Sonuçta ortaya çıkan kullanıcı arayüzü, tam olarak beklediğiniz gibi temiz, duyarlı ve animasyonlu bir açma/kapatma düğmesidir.

Widget'lar için Compose önizleme desteği

  • Aradaki farkı anlamak zor.

  • Widget düzenlerinizi her zaman bir cihazda veya emülatörde çalıştırmadan tasarlamanıza, yinelemenize ve doğrulamanıza yardımcı olmak için Wear widget'larına Compose önizleme desteği ekledik.

  • Widget'lar boyut, şekil, dolgu ve köşe yarıçapı gibi OEM'e özgü kapsayıcı kısıtlamalarına bağlı olduğundan standart önizleme ek açıklamasını temel alırız ancak bu yapılandırmaları eklemek için ek bir parametre sağlayıcı kullanırız.

    @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)
  • Kitaplık, gerçek Wear OS cihazlarla eşleşen önceden yapılandırılmış PreviewParameter sağlayıcı uygulamaları sunar.

  • Bu önizleme ek açıklamaları, düzeninizi çok çeşitli donanım şekillerinde kolayca doğrulamanıza olanak tanır.

  • Bu önizlemeleri, düzenlerinizi test etmenin yanı sıra cihaz üzerindeki widget seçici için gereken statik resimleri oluşturmak amacıyla da kullanabilirsiniz.

    @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)
  • Kitaplık, kırpılmamış tam dikdörtgen kapsayıcıları taklit eden dikdörtgen önizleme şekli için bir parametre sağlar.

Örnek uygulama ve taşıma araçları

  • Bu özelliğin pratikte nasıl çalıştığını görmek isterseniz Horologist medya örnek uygulamamızı bu API'yi gösteren yeni bir widget içerecek şekilde yeniledik.

  • Medya widget'ının hem küçük hem de büyük sürümlerinin nasıl ekleneceğini gösteriyoruz.

  • Eski ProtoLayout kodu ile yeni Remote Compose uygulamasının yan yana karşılaştırmasını görmek için GitHub'a göz atın.

  • Beğeneceğinizden eminiz.

  • Son olarak, yapay zekadan bahsetmeden bu konuşmayı bitiremeyiz.

  • Geçişinizi hızlandırmak için GitHub'da yeni bir "kartlardan widget'lara geçiş becerisi" yayınladık.

  • Bu aracı dilediğiniz temsilciyle kullanabilir veya Android KSA'yı kullanarak doğrudan Android Studio'ya ekleyebilirsiniz.

    android skills add wear-widgets
    android skills add --all
  • Şimdi sözü François'ya bırakıyorum.

Özet ve kapanış

  • Teşekkür ederiz.

  • Teşekkürler, Yuri.

  • Gördüğünüz gibi, kartlarınızı Wear widget'larına dönüştürmek çok basit bir işlemdir.

  • Özetlemek gerekirse Jetpack Glance Wear ve Remote Compose'a geçerek yalnızca kullanıcı arayüzünüzü güncellemekle kalmaz, aynı zamanda daha birleşik bir Android widget ekosistemine de katılırsınız.

  • Artık Jetpack Compose ile tamamen uyumlu, modern ve bildirime dayalı bir çerçeve kullanarak güzel, geriye dönük uyumlu widget'lar oluşturabilirsiniz.

  • Kartlarınızı taşımaya hemen başlayabilirsiniz. Tüm ayrıntılar için Android Developers sitesindeki başlangıç kılavuzuna göz atın.

  • Akıllı saatler için geliştireceğiniz etkileyici ve kolayca göz atılabilen deneyimleri görmeyi heyecanla bekliyoruz.

  • Bugün bize katıldığınız için çok teşekkür ederiz. Konferansın geri kalanında iyi vakit geçirmenizi dileriz.

  • Teşekkür ederiz.

Kod

Kod snippet'leri

"Building UI with Remote Compose" (Remote Compose ile Kullanıcı Arayüzü Oluşturma) videosunda 06:40'taki Kotlin snippet'i
// Wear Compose
@Composable
fun HistoryEraserButton(
  onClick: () -> Unit,
  modifier: Modifier = Modifier,
  checked: Boolean = true,
  onCheckedChange: (Boolean) -> Unit = {},
)
"Building UI with Remote Compose" (Uzaktan Oluşturma ile Kullanıcı Arayüzü Oluşturma) videosunda 06:40'taki Kotlin snippet'i
// Wear RemoteCompose
@RemoteComposable
@Composable
fun RemoteHistoryEraserButton(
  onClick: Action,
  modifier: RemoteModifier = RemoteModifier,
  checked: RemoteBoolean = true.rb,
  onCheckedChange: Action = Action.Empty,
)
"Building UI with Remote Compose" (Remote Compose ile kullanıcı arayüzü oluşturma) videosunda 07:39'daki Kotlin snippet'i
// 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!") },
  )
"Building UI with Remote Compose" (Uzaktan Oluşturma ile Kullanıcı Arayüzü Oluşturma) videosunda 07:39'daki Kotlin snippet'i
// 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) },
  )
"Compose preview support for widgets" (Widget'lar için Compose önizleme desteği) videosunda 08:20'deki Kotlin snippet'i
@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)
"Compose preview support for widgets" (Widget'lar için Compose önizleme desteği) videosunda 08:58'deki Kotlin snippet'i
@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)
"Örnek uygulama ve taşıma araçları" bölümünde 09:58'deki kabuk snippet'i
android skills add wear-widgets
android skills add --all