jetc.dev Newsletter Issue #229

Published: 2024-08-27

In positive news, we have a new Compose BOM, our first Compose 1.7.0 RC, a stable TV Compose, and more!

In negative news, there is a security issue with Navigation for Compose. đŸ˜±

And, in neutral news, we look at migrating away from fragments, explore the little-known ModifierLocal system, peek at a Material You implementation for CMP, and more!

Ooooo
 What Did We Get?

Reviewing the release notes for the latest Jetpack Compose update!

The Compose BOM is up to 2024.08.00, which pulls in 1.6.8 of the main Compose artifacts and 1.3.1 of the main Compose Material3 artifacts.

Compose itself is now up to 1.7.0-rc01. As you might expect, this contains a few bug fixes and little else.

In news on other Compose targets, Wear Compose is up to 1.4.0-rc01, and TV Compose has a stable 1.0.0 release.

We also got androidx.navigation:navigation-compose:2.8.0-rc01 and androidx.navigation:navigation-fragment-compose:2.8.0-rc01.

JetBrains released 1.7.0-alpha03 of Compose Multiplatform. This brings the Compose Material3 Adaptive code into CMP, as well as material3-window-size-class. Note, though, that those dependencies have an independent version numbering system and are starting out at 1.0.0-alpha01.

JetBrains also released Kotlin 2.0.20. The Compose Compiler has been updated to match, and the update contains a fix for a stability inference bug, as is noted in this Medium post.

One Off the Stack, One Off the Slack

You’ve got questions. That’s understandable!

Why Is My Clickable Callback Not Working?

I really hope that someday we will get a Lint check for cases like this one: you want to pass a click event to a composable’s caller, so you have onAction: () -> Unit as a parameter
 but you use clickable = { onAction } instead of clickable = onAction. Learn more in this week’s highlighted Stack Overflow question.

Is Compose for Web Practical?

It started out as a question about Compose Multiplatform’s SEO implications for Web development. The lengthy thread then covered whether the canvas-based Compose for Web is practical (answer: it depends on what you’re building), alternatives like Kobweb and Kilua, and more. See what all the fuss is about in this week’s highlighted Kotlinlang #compose Slack thread.

Composable Commentary

Posts, videos, and other new information related to Jetpack Compose!

Video: Fragments in Compose

Google’s Jeremy Woods walks us through migrating from a fragment-based UI to one powered by composables. Jeremy explains the use of ComposeView to allow a fragment to host a composable, using AndroidFragment() to get the fragment host inside a composable, and eventually using Navigation for Compose to wire together the composables without fragments.

Medium: Workaround for Jetpack Navigation vulnerability

Gergely KƑrössy points out a very interesting security writeup regarding Navigation for Compose. Simply put, every composable in your navigation graph can be accessed via a deeplink, even if you did not define one! Gergely describes a workaround for filtering out these unauthorized deeplinks. I talk a bit more about this in “
And One More Thing”, at the end of the newsletter.

Medium: Add powerful analytics modifiers in Jetpack Compose with ModifierLocal!

We hear a lot about composition locals, but did you know that there is a similar “modifier local” system? Joost Klitsie explains how to use modifierLocalOf(), modifierLocalProvider(), and modifierLocalConsumer(), illustrating their use for things like analytics collection.

Medium: Mastering Brushes in Jetpack Compose: Enhance Your App’s UI

Gorkem KARA gives us a tour of the Brush API, which we can use for backgrounds, drawing on a Canvas(), etc. The post covers a variety of brush types, animating brushes, creating custom brush implementations, and more.

Medium: Mastering Color Theming in Jetpack Compose

Stefano Natali is back, this time looking at managing your colors in a Compose Material3 theme, including using a composition local for custom color roles beyond those that Material3 offers.

Medium: Understanding @Immutable and @Stable Annotations in Jetpack Compose

Dobri Kostadinov walks us through the roles and uses of @Immutable and @Stable annotations, including their differences and why we do not just slap @Stable on everything.

Writing a Kotlin Multiplatform App from Start to Store

Zac Sweers (@ZacSweers@hachyderm.io) provides an overview of setting up a Kotlin Multiplatform app for Android and iOS, using Compose Multiplatform (along with compose-cupertino and Calf) for most of the UI. In particular, Zac explains some of the post-development details, like app distribution — useful for somebody new to one of the platforms (e.g., iOS).

Effective Map Composables: Draggable Markers

Uli Bubenheimer (@bubenheimer@androiddev.social) continues an exploration of Maps for Compose, this time looking at how to make draggable Marker() composables, powered by MarkerState.

Resource Roundup

100% pure code!

GitHub: zacharee / MultiplatformMaterialYou

Zachary Wander (@wander1236@androiddev.social) has released a Compose Multiplatform library supporting Material You-style dynamic theme generation. Use DynamicMaterialTheme() instead of MaterialTheme() to try to based the theme on the system accent color, or use lower-level alternatives.

GitHub: luiisca / floating-views

Luis Cadillo brings us a library designed to simplify having your app float over other apps using overlay views. It integrates permission management and a foreground service for keeping your floating view afloat.

GitHub: Mintakaaaa / number-scroller-compose

Mindaugas Brazlauskas published a library with a NumberScroller() composable to allow users to choose a number from within a range using gestures.

Notable Releases

Horologist is out with a 0.6.18 release, with a few responsive fixes.

Resaca — a per-composable viewmodel option — is up to 4.1.0. 4.0.0 added support for Kotlin Multiplatform and Compose Multiplatform, and 4.1.0 extends that multiplatform support to Resaca’s Koin integration.


And One More Thing

The security issue with Navigation for Compose is bad.

I have reasonable faith that this will get patched in some form or fashion, such as making those android-app deeplinks be opt-in (e.g., via a manifest <meta-data> element). In the meantime, if you wish to continue using Navigation for Compose, strongly consider filtering out those deeplinks described in the Medium post by Gergely KƑrössy or using similar techniques.

I am still unhappy. My concern is two-fold.

I am worried about Google’s “just use conditional navigation” solution. Certainly, a broad class of problems stemming from this security issue are ones where an attacker can get access to an authenticated screen without having been authenticated. However, that is not the entire problem space. The URL-as-nav-arg scenario mentioned in the security post demonstrates another, one that does not lend itself as neatly to conditional navigation.

Also, I simply do not understand why something like this was undocumented. They wrote plenty of unit tests for `android-app` deeplinks — see https://cs.android.com/search?q=%22android-app:%2F%2Fandroidx%22&sq=&ss=androidx. That indicates that this was intentional, not accidental. If you are writing several hundred lines of unit tests for a feature, it feels like users of the framework ought to know about the feature. And, when that feature expands the API surface for security, disclosure/documentation seems like it's the ethical answer.

(UPDATE: apparently, these are tests for manually-defined custom-Uri deeplinks, where the tests just happen to use the same android-app host that the automatic implicit deeplinks use)

I am hoping that the developers of other Compose navigation frameworks use this incident as a reason to examine their frameworks and see if they have similar sorts of “expand the attack surface” problems. And I hope to see navigation frameworks do what they can to help simplify conditional navigation, such as having “is this route eligible in our current state? if not, do X” be part of the framework’s API.