Upgrade to Pro — share decks privately, control downloads, hide ads and more …

[DroidconSF]Developing Apps optimized for Wear OS with Jetpack Compose

[DroidconSF]Developing Apps optimized for Wear OS with Jetpack Compose

This is the slide, "Developing Apps optimized for Wear OS with Jetpack Compose"
#wearos #android #droidconSF #dcsf23 #Droidcon

Kenichi Kambara

June 09, 2023
Tweet

More Decks by Kenichi Kambara

Other Decks in Technology

Transcript

  1. 2 About me Kenichi Kambara (@korodroid) •Mobile App Development •Speeches

    (e.g. 14 Int’l Confs.) •Writings (e.g. 8 Dev Books) •Principal Evangelist at NTT TechnoCross •[Private] iplatform.org
  2. Agenda •Wear OS Overview •Wear OS Topics from I/O 2023

    •Compose for Wear OS •How to optimize Apps for Wear OS? Source: Google I/O 2023 Keynote / Developer Keynote / Wear OS Session Android Developers Blog
  3. Wear OS Overview  Noti fi cation Complication Based on

    Android & optimized for the wrist Tile  App
  4. Wear OS Topics from I/O 2023  Watch Face Format

    Watch Face Studio Tile (Animation)
  5. Wear OS Features  App Noti fi cation Complication Based

    on Android & optimized for the wrist Tile 
  6. Implementation Example (Button)  @Composable fun ButtonExample() { Button( modifier

    = Modifier.size(ButtonDefaults.LargeButtonSize), onClick = { /* do anything */ }, enabled = true ){ Icon(Icons.Default.Mic, contentDescription = "mic") } }
  7.  Wear OS 
 (androidx.wear.*) Mobile 
 (androidx.*) androidx.wear.compose:compose-material androidx.compose.foundation:foundation

    androidx.wear.compose:compose-foundation androidx.compose.material:material androidx.navigation:navigation-compose androidx.compose.foundation:foundation ref: https://developer.android.com/training/wearables/compose Material androidx.wear.compose:compose-navigation Navigation Foundation 3rd difference: Development
  8. e.g. Button  Wear OS 
 (androidx.wear.*) Mobile 
 (androidx.*)

    androidx.wear.compose:compose-material androidx.compose.material:material
  9. Today's example: Contact App  @Composable fun ContactListScreenV0() { LazyColumn(

    horizontalAlignment = Alignment.CenterHorizontally ) { item { ListHeader { Text(text = "Contacts") } } items(model.data.size) { Chip( modifier = Modifier .fillMaxSize(), icon = { Icon( Icons.Rounded.Face, contentDescription = "faceIcon", ) }, label = { Text(model.data[it]) }, colors = ChipDefaults.primaryChipColors(), onClick = { }, ) } } } not BAD, but not GOOD
  10. Step1. Replacing to ScalingLazyColumn  @Composable fun ContactListScreenV1() { ScalingLazyColumn(

    horizontalAlignment = Alignment.CenterHorizontally ) { item { ListHeader { Text(text = "Contacts") } } items(model.data.size) { Chip( modifier = Modifier .fillMaxSize(), icon = { Icon( Icons.Rounded.Face, contentDescription = "faceIcon", ) }, label = { Text(model.data[it]) }, colors = ChipDefaults.primaryChipColors(), onClick = { }, ) } } } <wear>/MainActivity.kt
  11. Step2. Using Scaffold  @Composable fun ContactListScreenV2() { val listState

    = rememberScalingLazyListState() Scaffold( timeText = { if (!listState.isScrollInProgress) { TimeText() } }, vignette = { Vignette( vignettePosition = VignettePosition.TopAndBottom ) }, positionIndicator = { PositionIndicator( scalingLazyListState = listState, ) } ) { ScalingLazyColumn(state = listState) { // … }
  12. Step3. Adding a new Screen  @Composable fun ContactDetailScreen(id: Int)

    { Chip( modifier = Modifier .fillMaxSize(), icon = { Icon( Icons.Rounded.Face, contentDescription = "faceIcon", ) }, label = { Column( ) { Text(text = model.data[id].name,
 fontWeight = FontWeight.Bold) Text(text = model.data[id].phone) Text(text = model.data[id].nation) } }, colors = ChipDefaults.primaryChipColors(), onClick = { /* do anything */ }, ) }
  13. Implementing with Wear Navigation  Wear OS 
 (androidx.wear.*) Mobile

    
 (androidx.*) androidx.navigation:navigation-compose ref: https://developer.android.com/training/wearables/compose/navigation androidx.wear.compose:compose-navigation Navigation <wear>/build.gradle dependencies { def wear_compose_version = “1.1.2" implementation "androidx.wear.compose:compose-navigation:$wear_compose_version" }
  14.  @Composable fun ScreenNavigation_GoodImpl( navController: NavHostController = rememberSwipeDismissableNavController() ) {

    SwipeDismissableNavHost( navController = navController, startDestination = "contact_list" ) { composable("contact_list") { ContactListScreenV3(navController = navController) } composable("contact_detail/{id}") { val id = it.arguments?.getString("id")!! ContactDetailScreen(id = id.toInt()) } } } Step4. Implementing Wear Navigation
  15. Step4. Implementing Wear Navigation  @Composable fun ContactListScreenV3(navController: NavHostController) {

    Scaffold( // just same ) { ScalingLazyColumn(state = listState) { item { // just same } items(model.data.size) { Chip( modifier = Modifier.fillMaxSize(), icon = { // just same }, label = { Text(model.data[it].name) }, colors = ChipDefaults.primaryChipColors(), onClick = { navController.navigate("contact_detail/$it") }, ) } } } }
  16. Adding a Tile feature  Noti fi cation Complication Provide

    easier access to this app Tile  App +
  17. Step5. Implementing a Tile feature  class MainTileService : CoroutinesTileService()

    { // Abbreviates some procedures, such as reading data from the repository
 override suspend fun resourcesRequest( requestParams: RequestBuilders.ResourcesRequest ): ResourceBuilders.Resources { return ResourceBuilders.Resources.Builder().setVersion(RESOURCES_VERSION).build() } override suspend fun tileRequest( requestParams: RequestBuilders.TileRequest ): TileBuilders.Tile { val singleTileTimeline = TimelineBuilders.Timeline.Builder().addTimelineEntry( TimelineBuilders.TimelineEntry.Builder().setLayout( LayoutElementBuilders.Layout.Builder().setRoot(tileLayout(this)).build() ).build() ).build() return TileBuilders.Tile.Builder().setResourcesVersion(RESOURCES_VERSION) .setTimeline(singleTileTimeline).build() } } a Kotlin coroutine-friendly wrapper 
 from the Horologist Tiles library <wear>/MainTileService.kt
  18. Step5. Adding a Tile de fi nition  <application android:allowBackup="true"

    android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@android:style/Theme.DeviceDefault"> 
 …
 <service android:name=".tile.MainTileService" android:exported="true" android:label="@string/tile_label" android:permission="com.google.android.wearable.permission.BIND_TILE_PROVIDER"> <intent-filter> <action android:name="androidx.wear.tiles.action.BIND_TILE_PROVIDER" /> </intent-filter> <meta-data android:name="androidx.wear.tiles.PREVIEW" android:resource="@drawable/tile_preview" /> </service> </application> <wear>/AndroidManifest.xml
  19.  Tips💡 Next Step (How to optimize more) ref: Principles

    of Wear OS development 
 https://developer.android.com/training/wearables/principles