appstate-recipes

Activity, over time

Daily observations from the public event archive.

Attention

Daily stars & forks

Loading attention chart

Star accumulation

Cumulative stars

Loading star accumulation chart

Pull requests

Daily opens & merges

Loading pull requests chart

Conversations

Daily issues & comments

Loading conversations chart

Community

Daily accounts & reviews

Loading community chart

Releases

Daily releases

Loading releases chart

Mentions

4posts · 30d
Nov 30 posts
  1. Android Dev Summit 2026: Google vuelve a reunir a los devs después de cuatro años y pone a los agentes en el centro de Android --- title: "Android Dev Summit 2026: Google vuelve a reunir a los devs después de cuatro años y pone a los agentes en el centro de Android" published: true description: "Un briefing del primer Android Dev Summit desde 2022: qué anunció Google, en qué etapa está cada novedad y cómo usarla, con código." tags: android, kotlin, ai, jetpackcompose series: Android Dev Summit 2026 cover_image: dev-to-uploads.s3.us-east-2.amazonaws.com --- !Android Dev Summit 2026: Google vuelve a reunir a los devs después de cuatro años y pone a los agentes en el centro de Android Mountain View, 28 de octubre de 2026 — Después de cuatro años sin un evento propio, Google volvió a realizar el Android Dev Summit. La última edición había sido en 2022; desde entonces, las novedades de la plataforma compartían espacio con el resto del Google I/O. Esta vez fueron dos días dedicados solo a Android, en el campus Bay View, con el keynote transmitido en YouTube y una edición extendida en Londres. El mensaje del keynote fue directo: Android ahora se construye con agentes de IA y para agentes de IA. Android Studio abrió sus puertas a agentes de otras empresas, como Claude y Codex. Android CLI les dio a esos agentes acceso a dispositivos reales. Y las apps ganaron una forma estándar de ofrecer sus funciones a Gemini. En este briefing reúno lo que se anunció, en qué etapa está cada novedad y — la parte que el keynote recorre rápido — cómo usar cada una en el día a día, con código. {% embed youtube.com %} Ficha del evento | | | | --- | --- | | Cuándo | 28 y 29 de octubre de 2026 | | Dónde | Campus Bay View de Google, Mountain View (EE. UU.), con edición extendida en Londres | | Contexto | Primer Android Dev Summit desde 2022 | | Tracks | AI experiences, Android XR, Apps foundation, Tools & performance | | Keynote | Cerca de una hora, con demos en vivo — míralo en YouTube | Los titulares - Android Studio Rabbit 2 llega a stable y acepta cualquier agente de código compatible con ACP — Claude, Codex, Antigravity y más de 40 otros. - Android CLI suma dispositivos físicos remotos, render de Compose Preview en la terminal, un profiler con LeakCanary y plugins oficiales para Claude Code y Codex. - Checklist de publicación en semáforo: la skill play-policy-insights audita la app antes del envío a Google Play y marca 🟢🟡🔴 lo que falta. - Migración de XML a Compose con un clic derecho, guiada por un agente dentro de Android Studio. - AppFunctions pasa a beta: las funciones de tu app se vuelven tools para Gemini y otros agentes, vía Android MCP. - A2UI (alpha): los agentes ahora pueden responder con pantallas nativas en Compose, hechas con tu design system. - Gemini Nano 4 + ML Kit Agentic API (alpha): un agente completo corriendo en el dispositivo, con llamada de funciones. - Jetpack AppState (alpha) lleva el modelo de estado de Compose a ViewModels y repositorios. - Googlebook, plegables y Android XR: un código para muchas pantallas. XREAL AURA debuta como las primeras gafas XR con cable que corren Android XR. --- 1. Lo que ya puedes usar (y lo que todavía es laboratorio) Antes de instalar todo, conviene mirar la madurez de cada anuncio. !Mapa de madurez de los anuncios Mi regla práctica: stable va a producción, beta entra detrás de un feature flag, alpha y preview se quedan en POC y estudio. --- 2. Android Studio Rabbit 2: trae tu propio agente Android Studio dejó de ser "el IDE con Gemini". Con Bring Your Own Agent (BYOA), ahora stable en Rabbit 2, se convierte en el host de cualquier agente compatible con el Agent Client Protocol (ACP). Cómo activarlo: 1. Abre Settings > Tools > AI > Agents. 2. Instala agentes desde el marketplace (Claude Agent, Codex, Antigravity…). Puedes tener varios y alternar. 3. El agente pasa a ver lo que solo el IDE sabe: estructura del proyecto y del build, resolución de símbolos, render de Compose Preview, el Emulator y Logcat. Además llegaron tres funciones que cambian el día a día: - Change Review — revisión agéntica de los cambios que hizo el agente. Inícialo desde los cambios pendientes, la ventana de Git o con /review. Genera un reporte de problemas y un recorrido guiado para cambios grandes. - Migration Assistant (Canary) — clic derecho en un layout XML > AI › Migrate to Compose y el agente migra la pantalla a Compose. Más abajo hay una sección completa sobre esto. - Android Bench 2.0 — un leaderboard que evalúa modelos y harnesses en tareas Android largas (migrar UI, construir una app desde mocks), midiendo si realmente funciona, además de costo y tiempo. Ideal para elegir el agente del equipo: developer.android.com. ACP vs MCP: no los confundas Es el punto que más confusión genera. Son dos protocolos con funciones distintas: !ACP te ayuda a construir; MCP deja que los agentes usen tu app --- 3. Android CLI: todo el toolchain en manos del agente Android CLI es la interfaz "tool-first" para cualquier terminal, agente o pipeline de CI. La idea es simple: el agente deja de gastar tokens adivinando cómo funciona Android y usa herramientas oficiales. # instala el CLI y configura el agente android init # un dispositivo físico real, en un device lab de Google (vía Firebase) android device remote connect android device hub # ventana para ver y controlar dispositivos y emuladores # Compose Previews sin emulador ni IDE android preview # rendimiento y memoria android profiler systemtrace android profiler heapdump capture android profiler leakcanary # calidad del binario y señales de producción android analyze app-release.aab android signals # skills y documentación android skills list android skills add jetpack-compose-performance android docs search "predictive back" Los números que publicó Google llaman la atención: los agentes que usaron android preview terminaron tareas de UI 77% más rápido con hasta 3x menos tokens. Plugins oficiales para Claude Code y Codex # Claude Code (dentro de la sesión) /plugin marketplace add android/android-cli-plugin /plugin install android-cli@android-cli-plugin # Claude Code (terminal) claude plugin marketplace add android/android-cli-plugin claude plugin install android-cli@android-cli-plugin # Codex codex plugin marketplace add android/android-cli-plugin codex plugin add android-cli@android-cli-plugin El plugin le da al agente lo necesario para crear proyectos, gestionar emuladores, inspeccionar layouts en vivo, ejecutar Journeys, instalar skills oficiales y consultar la Android Knowledge Base. Skills oficiales Son más de 30 skills en más de 20 áreas, cada una respaldada por evaluaciones. Apuntan a donde los modelos suelen fallar: rendimiento de Compose, APIs nuevas de cámara, auditorías de seguridad. Algunas que vale instalar ya: - jetpack-compose-performance - android-profiler - r8-analyzer - play-policy-insights (audita código, manifest y SDKs contra las políticas de Play antes del envío) - android-intent-security y android-permissions-security Repositorio: android/skills. --- 4. Validación: el agente revisa su propio trabajo El bloque "Validating apps with Android Prototype" del keynote (12:45) insiste en una idea: un buen agente verifica lo que hizo. La demo más memorable fue con Claude Code: !Bucle de validación agéntica Google le dio al agente una lista de recorridos críticos y un único prompt — encontrar y corregir memory leaks. Claude ejecutó cada recorrido en un dispositivo distinto, en paralelo, usó android profiler leakcanary, siguió las cadenas de referencias hasta el código, lo corrigió y volvió a ejecutar todo para confirmar. Lo que sostiene ese flujo: - Journeys — flujos de usuario descritos en lenguaje natural. El equipo los escribe; el agente los ejecuta. - LeakCanary integrado — en el CLI y en el Profiler de Studio, con Fix with AI (Canary). - Android Performance Analyzer (APA) — el motor del Profiler ahora también alimenta el CLI. Con la skill android-profiler, el agente captura un trace, lo analiza, propone una corrección y mide el impacto. - androidx.tracing 2.0 — traces con archivo, línea y argumentos; las coroutines aparecen como flujos conectados. Empieza con androidx.tracing:tracing-wire. - Recomposition tracing (Compose 1.13) — muestra por qué algo se recompuso, hasta la escritura de estado que lo causó. Del crash en producción a la corrección android signals trae crashes, ANRs y problemas de memoria a la terminal. Y Crashlytics ahora recolecta heap dumps de OOMs reales y de Memory Limiter Kills de Android 17, desofuscados con el mapping de R8 y abiertos en Perfetto (early access). R8 sin miedo # AGP 9.3: puntaje de tu configuración y ranking de las keep rules más costosas ./gradlew :app:analyzeReleaseR8Config Combínalo con la skill r8-analyzer y reemplaza keep rules genéricas por Jetpack Keep (alpha), anotaciones type-safe que lint puede agregar por ti. --- 5. Antes del deploy: el checklist en semáforo Uno de los momentos más prácticos del evento: en lugar de un checklist manual de publicación, le pides al agente que audite la app y te devuelve un reporte en semáforo — 🟢 lo que está bien, 🟡 lo que necesita revisión, 🔴 lo que bloquea el envío. !El agente muestra, en semáforo, lo que falta antes del deploy La skill oficial: play-policy-insights Ese formato viene de la skill oficial play-policy-insights, que audita tu código, manifest y SDKs contra las políticas de Google Play y lo cruza con tu declaración de Data safety. 1. Instala la skill android skills add play-policy-insights # alternativa, fuera de Android CLI: npx skills add https://github.com/android/skills --skill play-policy-insights 2. Ejecútala con un prompt (este es el que sugiere Google): Audit this app for Google Play policy compliance before I submit it. 3. Qué revisa - Data safety — compara lo que tu código recolecta y transmite con lo que declaraste en Play Console. - Credenciales de login de demostración — si los revisores de Play pueden entrar a la app. - Permisos restringidos — permisos sensibles u obsoletos donde se espera una alternativa con alcance limitado. 4. Cómo leer el reporte | Estado general | Significado | Qué hacer | | --- | --- | --- | | 🟢 Compliant | No se encontraron violaciones activas | Seguir con el envío | | 🟡 Needs Review | Sin violaciones críticas, pero hay declaraciones manuales en Play Console o permisos restringidos para revisar | Revisar antes de enviar | | 🔴 Non-Compliant | Violaciones o diferencias en Data safety | Corregir antes del envío | Cada hallazgo tiene severidad — 🔴 Critical (violación confirmada), 🟡 Important (por ejemplo, un permiso obsoleto donde se espera uno con alcance), 🔵 Suggestion (recomendación) — e incluye la política, los archivos afectados, la evidencia, un nivel de confianza, una recomendación y enlaces. El reporte termina con diferencias de Data safety, accesos locales a datos y un checklist de remediación. Dos cuidados: - El reporte es consultivo: no es asesoría legal ni garantía de aprobación. - La skill escribe archivos temporales en .scratch/play_policy_insights_<uuid> en la raíz del proyecto. Agrega .scratch/ al .gitignore. En Android Studio, Play Policy Insights también aparece como verificaciones de lint directamente en el código. Más allá: una skill de "release readiness" con todos los gates La política de Play es solo una de las puertas. Con las herramientas de Android CLI puedes escribir tu propia skill que ejecute todos los gates y devuelva un único semáforo. Este es un ejemplo que escribí para estudio — adapta rutas y umbrales a tu proyecto: --- name: release-readiness description: Úsala antes de publicar una release. Ejecuta los gates de build, tamaño, política de Play, seguridad, estabilidad y recorridos críticos y devuelve un reporte en semáforo. --- # Release readiness Ejecuta todos los gates de abajo, en orden. No te detengas en la primera falla: el reporte debe mostrar todos. ## Gates 1. **Build** — `./gradlew :app:bundleRelease`. 🔴 si falla. 2. **Tamaño y R8** — ejecuta `android analyze` sobre el AAB de release y `./gradlew :app:analyzeReleaseR8Config`. 🟡 si el puntaje de shrinking bajó respecto de `docs/release/last-analyze.json`. 🔴 si la ofuscación está desactivada. 3. **Política de Play** — ejecuta la skill `play-policy-insights` y copia su estado general. 4. **Seguridad** — ejecuta las skills `android-permissions-security` y `android-intent-security`. 🔴 ante cualquier hallazgo Critical. 5. **Estabilidad** — `android signals` para la versión actual en producción. 🟡 ante nuevos clusters de crash o ANR. 🔴 si los usuarios sin crash cayeron por debajo del umbral de `docs/release/thresholds.md`. 6. **Recorridos críticos** — ejecuta las Journeys de `journeys/`. 🔴 si alguna falla. ## Salida Escribe `release-report.md` con: - el estado general (el peor gate define el estado); - una fila por gate: estado, gate, evidencia, próxima acción; - un checklist de remediación. No publiques, no subas nada y no crees tags. Publicar es una decisión humana. En Claude Code, guárdala en .claude/skills/release-readiness/SKILL.md y llámala con /release-readiness. En otros agentes, usa su carpeta de skills equivalente. La regla "el peor gate define el estado" es lo que convierte seis verificaciones en un semáforo único y honesto. --- 6. Compose-first en la práctica: de XML a Compose con un clic derecho Otro punto destacado del keynote: migrar una pantalla de XML Views a Jetpack Compose dejó de ser un proyecto manual. El Migration Assistant (Android Studio Canary) aparece en el menú contextual del layout y le delega el trabajo a un agente. !Flujo del Migration Assistant Paso a paso 1. Instala el Android Studio Canary más reciente — la función está en ese canal. 2. Elige el agente. Funciona con el agente integrado de Studio o con cualquier agente agregado vía Bring Your Own Agent (Claude, Codex…). También conviene instalar la skill oficial Migrate to Compose, que aparece en android skills list. 3. Haz clic derecho en el layout XML (por ejemplo, res/layout/fragment_profile.xml) y elige AI › Migrate to Compose. Para migrar todo el proyecto, abre la action palette y ejecuta la migración desde ahí. 4. Define el alcance con el agente. Te pregunta qué migrar ahora, qué queda en interoperabilidad y cómo tratar las vistas personalizadas. 5. Revisa el plan. El agente arma un plan por etapas antes de tocar cualquier archivo. 6. Conversión. El agente convierte el layout, el código de view binding y la lógica asociada en Compose idiomático. 7. Sigue la timeline. La ventana del agente muestra qué etapa está corriendo y desde dónde retomar si se detiene. El progreso se guarda con la conversación: puedes irte y volver después. 8. Valida. Revisa los Compose Previews (o android preview en la terminal) y ejecuta Change Review con /review antes del commit. Ejemplo: lo que entra y lo que sale Un ejemplo ilustrativo de este tipo de conversión — una pantalla de perfil con ViewBinding. Antes (XML + ViewBinding): <!-- res/layout/fragment_profile.xml --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="16dp"> <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?attr/textAppearanceHeadlineSmall" /> <TextView android:id="@+id/role" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:id="@+id/follow" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/follow" /> </LinearLayout> class ProfileFragment : Fragment(R.layout.fragment_profile) { private val viewModel: ProfileViewModel by viewModels() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val binding = FragmentProfileBinding.bind(view) viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.uiState.collect { state -> binding.name.text = state.name binding.role.text = state.role binding.follow.isEnabled = !state.isFollowing } } } binding.follow.setOnClickListener { viewModel.follow() } } } Después (Compose idiomático, con estado elevado): @Composable fun ProfileRoute(viewModel: ProfileViewModel = viewModel()) { val state by viewModel.uiState.collectAsStateWithLifecycle() ProfileScreen(state = state, onFollow = viewModel::follow) } @Composable fun ProfileScreen(state: ProfileUiState, onFollow: () -> Unit, modifier: Modifier = Modifier) { Column(modifier.padding(16.dp)) { Text(state.name, style = MaterialTheme.typography.headlineSmall) Text(state.role) Button(onClick = onFollow, enabled = !state.isFollowing) { Text(stringResource(R.string.follow)) } } } @Preview @Composable private fun ProfileScreenPreview() { ProfileScreen(ProfileUiState(name = "Ada", role = "Android Engineer"), onFollow = {}) } Durante la transición, el Fragment puede seguir existiendo y solo alojar Compose: class ProfileFragment : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) = ComposeView(requireContext()).apply { setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) setContent { MaterialTheme { ProfileRoute() } } } } Checklist para revisar lo que generó el agente - [ ] ¿El estado está elevado (Composable sin estado + un Route que recolecta el ViewModel)? - [ ] ¿Los textos usan stringResource en lugar de strings fijos? - [ ] ¿El tema del XML se mapeó a MaterialTheme (colores, tipografía, formas)? - [ ] ¿Se preservó la accesibilidad: contentDescription, tamaños táctiles, orden de lectura? - [ ] ¿Las pruebas de UI pasaron a composeTestRule (o screenshot tests)? - [ ] ¿Sin recomposiciones innecesarias? Usa el recomposition tracing de Compose 1.13 y la skill jetpack-compose-performance. - [ ] ¿Se eliminaron el XML y la clase de binding antiguos una vez estabilizada la pantalla? Estrategia recomendada: migra pantalla por pantalla, empezando por las más simples o las que vas a tocar de todos modos, y usa ComposeView como puente. Migrar toda la app de una vez genera un diff imposible de revisar — incluso con un agente. --- 7. Compose-first: estado fuera de la UI con Jetpack AppState Si alguna vez peleaste con un combine de cinco Flows, esto te va a gustar. Jetpack AppState (alpha) usa el runtime de Compose fuera de la UI, en ViewModels, repositorios y servicios. Son dos piezas: - Transform — ejecuta un bloque @Composable sin UI y devuelve un State<R> que se recompone solo cuando cambia cualquier estado leído. - StateStore — un mapa type-safe de estado compartido entre activities, services y widgets, con persistencia opcional en DataStore. [versions] appstate = "1.0.0-alpha01" [libraries] androidx-appstate-transform = { module = "androidx.appstate.transform:transform", version.ref = "appstate" } androidx-appstate-transform-testing = { module = "androidx.appstate.transform:transform-testing", version.ref = "appstate" } androidx-appstate-statestore = { module = "androidx.appstate.statestore:statestore", version.ref = "appstate" } > Ojo: todo módulo que llama a transform necesita buildFeatures { compose = true } y el plugin del Compose Compiler, aunque no tenga UI. Un ViewModel que cambia de fuente según la conectividad: class HomeViewModel( private val mediaRepository: MediaRepository, private val networkMonitor: NetworkMonitor, ) : ViewModel() { val uiState: State<HomeUiState> = transform<HomeUiState>( initialValue = HomeUiState.Loading, scope = viewModelScope, ) { val isOnline by networkMonitor.isOnline val tracks = if (isOnline) { mediaRepository.allTracksFlow.collectAsState(initial = null).value } else { mediaRepository.downloadedTracksFlow.collectAsState(initial = null).value } ?: return@transform HomeUiState.Loading HomeUiState.Success(tracks = tracks, isOnline = isOnline) } } Sin flatMapLatest, sin stateIn: un if común decide qué fuente observar. Debounce de búsqueda con LaunchedEffect, dentro de transform: var query: String by mutableStateOf("") val searchResults: List<String> by transform<List<String>>( initialValue = emptyList(), scope = coroutineScope, ) { var results by remember { mutableStateOf(emptyList<String>()) } LaunchedEffect(query) { if (query.isBlank()) { results = emptyList(); return@LaunchedEffect } delay(300.milliseconds) results = api.search(query) } results } Cuándo NO usar transform: representa el valor actual, no un flujo de eventos. Las actualizaciones rápidas antes de la recomposición se descartan y los valores iguales consecutivos no disparan nada. Para totales acumulados, logs, eventos únicos y backpressure, sigue con Flow. Las pruebas son simples con transformTest: @Test fun testStateUpdate() = transformTest { var sourceState by mutableStateOf(0) val state = transform(initialValue = 0, scope = backgroundScope, dispatcher = testDispatcher) { sourceState } sourceState = 1 advance() assertThat(state.value).isEqualTo(1) } Completan el paquete Compose 1.13 (stable pronto: Grid y FlexBox stable, Progressive Blur, Formatted Text) y Navigation 3 1.2 (stable: deep links y predictive back más rico). Ejemplos: android/appstate-recipes. --- 8. A2UI: cuando la respuesta del agente es una pantalla Un muro de texto en un chat no es buena UX. Con A2UI (Agent-to-UI), el agente envía JSON declarativo y tu app renderiza componentes nativos de tu propio catálogo — sin ejecutar código arbitrario. !Flujo de A2UI en Jetpack Compose dependencies { implementation("androidx.a2ui.compose:compose-runtime:1.0.0-alpha01") implementation("androidx.a2ui.compose:compose-ui:1.0.0-alpha01") androidTestImplementation("androidx.a2ui.compose:compose-ui-testing:1.0.0-alpha01") } ViewModel: class AgenticUiViewModel : ViewModel() { private val parser = A2uiMessageParser() private val processor = A2uiMessageProcessor(catalogs = listOf(CustomDesignSystemCatalog)) val a2uiSurfaces: StateFlow<List<A2uiSurfaceModel>> = processor.activeSurfaces init { viewModelScope.launch(Dispatchers.Default) { processor.collectMessages() } // clics y errores vuelven al agente viewModelScope.launch(start = CoroutineStart.UNDISPATCHED) { processor.outboundEvents.collect(::handleOutboundA2uiEvent) } } fun onNetworkMessage(json: String) = processor.processInput(parser, json) } Pantalla: @Composable fun AgenticUiScreen(viewModel: AgenticUiViewModel) { val surfaces by viewModel.a2uiSurfaces.collectAsStateWithLifecycle() Column(Modifier.fillMaxSize()) { surfaces.forEach { surface -> key(surface.id) { A2uiSurface(surfaceModel = surface) } } } } Lo que más me gustó: las defensas contra alucinaciones vienen incluidas. Un componente desconocido se convierte en un error reportado al agente para que se corrija; el payload se valida contra un schema; los índices de lista absurdos pasan a un mapa disperso para no agotar la memoria. --- 9. Gemini Nano 4: un agente completo en el dispositivo Gemini Nano 4 trajo function calling nativo, y ML Kit sumó una Agentic API (alpha) que ejecuta el bucle agéntico completo en el dispositivo, sobre AICore. !Gemini Nano 4 y la ML Kit Agentic API Requisitos: Android 14+ inscrito en el AICore Developer Preview, un dispositivo compatible, minSdk 26, Kotlin 2.3+. dependencies { implementation("com.google.mlkit:genai-agent:1.0.0-alpha1") // opcional: tools vía AppFunctions implementation("androidx.appfunctions:appfunctions:1.0.0-alpha13") ksp("androidx.appfunctions:appfunctions-compiler:1.0.0-alpha13") } val agent = Agent.builder() .setName("Assistant") .setInstructions("You are a helpful on-device assistant.") .build() val runner = AgentRunner(agent) val session = runner.getOrCreateSession("chat_session") val prompt = Content.builder().text("Can you help me organize my day?").build() lifecycleScope.launch { session.runAsync(prompt) .textTokens() .collect { token -> Log.d("Agent", token) } } // sin historial: runner.runSingleTurnAsync(prompt) // al destruir: runner.close() Límites que debes conocer: - maxTurns es 10 por defecto, para evitar bucles infinitos y ahorrar batería. - La inferencia solo corre con la app en primer plano; demasiadas llamadas devuelven ErrorCode.BUSY. - El modelo puede elegir la tool o el argumento equivocado: la seguridad de las acciones es responsabilidad de tu app. Confirma con el usuario las acciones sensibles. - Para bases de conocimiento enormes, el propio Google recomienda una arquitectura híbrida con modelos en la nube. --- 10. Android MCP y AppFunctions: tu app como tool de Gemini Para mí, este es el cambio más estratégico del evento. AppFunctions es el equivalente móvil de las tools de MCP: tu app se convierte en un servidor MCP on-device, y Gemini (u otro agente autorizado) descubre y llama a funciones de tu app para cumplir lo que pide el usuario. Está en beta y funciona en Android 16+. !Cómo una función de tu app se vuelve una tool de Gemini @RequiresApi(36) @AndroidEntryPoint @AppFunctionServiceEntryPoint( serviceName = "TaskAppFunctionService", appFunctionXmlFileName = "task_app_function_service", ) abstract class BaseTaskAppFunctionService : AppFunctionService() { @Inject internal lateinit var taskRepository: TaskRepository /** * Creates a task based on [createTaskParams]. * * @param createTaskParams The parameter to describe how to create the task. */ @AppFunction(isDescribedByKDoc = true) suspend fun createTask(createTaskParams: CreateTaskParams): Task = withContext(Dispatchers.IO) { if (createTaskParams.title == null && createTaskParams.content == null) { throw AppFunctionInvalidArgumentException("Title or content should be non-null") } val id = taskRepository.createTask(createTaskParams.title, createTaskParams.content) taskRepository.getTask(id)?.toTask() ?: throw AppFunctionElementNotFoundException("Task not found for ID = $id") } } /** The parameter to create the task. */ @AppFunctionSerializable(isDescribedByKDoc = true) data class CreateTaskParams( /** The title of the task. */ val title: String?, /** The content of the task. */ val content: String?, ) Fíjate en dos detalles: 1. El KDoc es el prompt. Con isDescribedByKDoc = true, la documentación se convierte en la descripción que lee el agente para decidir cuándo llamar a la función. Escríbela pensando en el modelo. 2. Las excepciones tipadas (AppFunctionInvalidArgumentException, AppFunctionElementNotFoundException) le dicen al agente por qué falló, para que intente de otra manera. Probando sin Gemini: adb shell cmd app_function list-app-functions AppFunctions vs servidor MCP remoto: AppFunctions corre localmente, usa el estado real de la app y no necesita backend. Un MCP remoto es agnóstico de plataforma y depende de la red. Los agentes consideran ambos juntos. Para llegar a los usuarios, la Connected Apps Platform (preview) lleva los servicios de tu app a Gemini y a la Búsqueda: construyes con Android MCP o MCP remoto, prototipas en el Gemini dev mode y te registras en Google Connected Console. > ⚠️ Realidad a oct/2026: la integración con Gemini todavía está limitada a apps seleccionadas. Puedes implementarla y probarla hoy; para producción hay un Early Access Program. --- 11. Un código, muchas pantallas: Googlebook, plegables y XR !Un código, muchas pantallas Googlebook es la nueva categoría de laptops sobre una base Android, con socios como HP, Dell, Lenovo, Acer y Asus. La misma app corre en el teléfono y en la laptop, sin un código separado. La Compose adaptive skill se actualizó para que el agente haga el trabajo pesado: atajos de teclado, cursores, hover y tooltips; migración a Grid, FlexBox y mediaQuery; manejo de estado de punta a punta; y posturas de plegables, como layouts tabletop para pantallas de multimedia y cámara. > 📌 Aviso de Google Play: en 2027 Play revisará de cerca cómo corren las apps y los juegos en plegables. Sigue las adaptive app quality guidelines. Android XR y XREAL AURA XREAL AURA son las primeras gafas XR con cable que corren Android XR. Pesan menos de 95 g porque el procesamiento va en un "puck" con Snapdragon Reality Elite. Tienen pantalla Sony Micro-OLED 1200p a 120 Hz, ejecutan apps de Google Play y hasta cinco ventanas virtuales. Precio: US$ 1.099 de lanzamiento hasta diciembre (US$ 1.279 después), a la venta en Estados Unidos, Canadá, Japón y Corea del Sur. Para los devs, lo más importante: el núcleo de Jetpack XR ya es stable (SceneCore, ARCore for Jetpack XR y XR Runtime), igual que los emuladores de gafas XR en Android Studio y el Android XR Engine Hub. Compose for XR sigue en alpha. El primer paso es espacializar una pantalla que ya tienes: Subspace { SpatialPanel( SubspaceModifier .height(824.dp) .width(1400.dp) .resizable() .transformingMovable(), ) { MyExistingScreen() // tu pantalla Compose actual } } El contenido dentro de Subspace solo se muestra cuando la espacialización está activa. En el teléfono se ignora, así que el mismo código sirve para ambos mundos. --- 12. Más allá del keynote: 5 laboratorios para esta semana 1. Un agente con ojos y manos (stable) — instala Android CLI y el plugin en Claude Code o Codex, escribe 3 Journeys de tus flujos críticos y pide: "ejecuta los recorridos, captura un trace de inicio y propón la corrección de mayor impacto". Mide el cold start antes y después. 2. Calidad en CI (stable) — ejecuta android analyze sobre el AAB de release, guarda el JSON como artefacto y haz fallar el build si baja el puntaje de shrinking. Usa analyzeReleaseR8Config para atacar las 5 keep rules más costosas. 3. Un ViewModel sin combine (alpha) — reescribe un ViewModel con 3+ fuentes usando transform y pruébalo con transformTest. Compara la legibilidad y verifica si se perdió algún evento. 4. Tu app como tool (beta) — usa la skill de AppFunctions para encontrar las 3 funciones de mayor valor, implementa una y valídala con adb shell cmd app_function list-app-functions. 5. Una respuesta como UI (alpha) — arma un catálogo A2UI con 3 componentes de tu design system y aliméntalo con JSON fijo antes de conectar un modelo real. Prueba el camino de error. --- Lo que deja el Dev Summit El regreso del Android Dev Summit no estuvo marcado por una API aislada. Estuvo marcado por un cambio en el rol de quien desarrolla para Android: orquestar agentes que construyen, validan y optimizan la app — y diseñar la app para que la usen agentes. Si quieres actuar ya, esta es mi lectura: - Para adoptar hoy: Rabbit 2 con BYOA, Android CLI con skills, Change Review y el checklist en semáforo en el flujo del equipo. - Este trimestre: migrar las pantallas XML que más se tocan, definir qué funciones de la app serán AppFunctions y preparar la UI adaptativa para plegables y Googlebook. - En POC: A2UI, Gemini Nano 4 y AppState, siguiendo las APIs en su camino a stable. ¿Cuál de estas novedades vas a probar primero? Cuéntame en los comentarios. 👇 --- Fuentes - Android Dev Summit 2026 keynote - Agentic and Flexible: A next era of Android development - What's new in Android developer tools and performance at Android Dev Summit - Android skills (catálogo) y play-policy-insights - Overview of AppFunctions - Render A2UI surfaces in your app - Build agentic workflows with Gemini Nano - Jetpack AppState y Transform - Develop UI with Jetpack Compose for XR - TechCrunch — Xreal Aura Este artículo también está disponible en portugués e inglés.

  2. Android Dev Summit 2026: Google brings developers back together after four years and puts agents at the center of Android --- title: "Android Dev Summit 2026: Google brings developers back together after four years and puts agents at the center of Android" published: true description: "A briefing on the first Android Dev Summit since 2022: what Google announced, how mature each piece is, and how to use it, with code." tags: android, kotlin, ai, jetpackcompose series: Android Dev Summit 2026 cover_image: dev-to-uploads.s3.us-east-2.amazonaws.com --- !Android Dev Summit 2026: Google brings developers back together after four years and puts agents at the center of Android Mountain View, October 28, 2026 — After four years without a dedicated event, Google brought back the Android Dev Summit. The last edition was in 2022; since then, platform news had to share the stage with the rest of Google I/O. This time it was two days devoted entirely to Android, at the Bay View campus, with the keynote streamed on YouTube and an extended edition in London. The keynote's message was blunt: Android is now built with AI agents and for AI agents. Android Studio opened its doors to agents from other companies, such as Claude and Codex. Android CLI gave those agents access to real devices. And apps gained a standard way to offer their functions to Gemini. In this briefing I gather what was announced, how mature each piece is and — the part the keynote moves through quickly — how to use each one day to day, with code. {% embed youtube.com %} Event fact sheet | | | | --- | --- | | When | October 28–29, 2026 | | Where | Google's Bay View campus, Mountain View (US), plus an extended edition in London | | Context | First Android Dev Summit since 2022 | | Tracks | AI experiences, Android XR, Apps foundation, Tools & performance | | Keynote | About one hour, with live demos — watch on YouTube | The headlines - Android Studio Rabbit 2 reaches stable and accepts any ACP-compatible coding agent — Claude, Codex, Antigravity and 40+ others. - Android CLI gains remote physical devices, Compose Preview rendering in the terminal, a LeakCanary-powered profiler and official plugins for Claude Code and Codex. - A traffic-light release checklist: the play-policy-insights skill audits your app before you submit to Google Play and flags 🟢🟡🔴 what's missing. - XML-to-Compose migration with a right-click, driven by an agent inside Android Studio. - AppFunctions goes beta: functions in your app become tools for Gemini and other agents, through Android MCP. - A2UI (alpha): agents can now answer with native Compose screens built from your design system. - Gemini Nano 4 + ML Kit Agentic API (alpha): a whole agent running on the device, with function calling. - Jetpack AppState (alpha) brings Compose's state model to ViewModels and repositories. - Googlebook, foldables and Android XR: one codebase for many screens. XREAL AURA debuts as the first wired XR glasses running Android XR. --- 1. What you can ship today (and what is still a lab) Before installing everything, check how mature each announcement is. !Maturity map of the announcements My rule of thumb: stable goes to production, beta goes behind a feature flag, alpha and preview stay in POCs and study projects. --- 2. Android Studio Rabbit 2: bring your own agent Android Studio is no longer "the IDE with Gemini". With Bring Your Own Agent (BYOA), now stable in Rabbit 2, it hosts any agent that speaks the Agent Client Protocol (ACP). How to turn it on: 1. Open Settings > Tools > AI > Agents. 2. Install agents from the marketplace (Claude Agent, Codex, Antigravity…). You can keep several and switch. 3. The agent now sees what only the IDE knows: project and build structure, symbol resolution, Compose Preview rendering, the Emulator and Logcat. Three more features change the daily workflow: - Change Review — agentic review of the changes your agent made. Start it from pending agent changes, the Git window, or with /review. You get an issues report and a guided walkthrough for large changes. - Migration Assistant (Canary) — right-click an XML layout > AI › Migrate to Compose and the agent migrates the screen to Compose. There's a full section on it further down. - Android Bench 2.0 — a leaderboard that scores models and agent harnesses on long Android tasks (migrating UI, building an app from mocks), measuring whether the result actually works, plus cost and time. Great for picking your team's agent: developer.android.com. ACP vs MCP: don't mix them up This is the point I see causing the most confusion. Two protocols, two jobs: !ACP helps you build; MCP lets agents use your app --- 3. Android CLI: the whole toolchain in your agent's hands Android CLI is the tool-first interface for any terminal, agent or CI pipeline. The idea is simple: your agent stops burning tokens guessing how Android works and uses official tools instead. # install the CLI and set up your agent android init # a real physical device from a Google device lab (via Firebase) android device remote connect android device hub # window to view and control devices and emulators # Compose Previews with no emulator and no IDE android preview # performance and memory android profiler systemtrace android profiler heapdump capture android profiler leakcanary # binary quality and production signals android analyze app-release.aab android signals # skills and docs android skills list android skills add jetpack-compose-performance android docs search "predictive back" Google's numbers stand out: agents using android preview finished UI tasks 77% faster with up to 3x fewer tokens. Official plugins for Claude Code and Codex # Claude Code (inside a session) /plugin marketplace add android/android-cli-plugin /plugin install android-cli@android-cli-plugin # Claude Code (terminal) claude plugin marketplace add android/android-cli-plugin claude plugin install android-cli@android-cli-plugin # Codex codex plugin marketplace add android/android-cli-plugin codex plugin add android-cli@android-cli-plugin The plugin gives your agent what it needs to create projects, manage emulators, inspect live layouts, run Journeys, install official skills and search the Android Knowledge Base. Official skills There are 30+ skills across 20+ areas, each backed by evaluations. They target the areas where models tend to fall short: Compose performance, new camera APIs, security audits. A few worth installing now: - jetpack-compose-performance - android-profiler - r8-analyzer - play-policy-insights (audits code, manifest and SDKs against Play policies before you submit) - android-intent-security and android-permissions-security Repo: android/skills. --- 4. Validation: the agent checks its own work The "Validating apps with Android Prototype" segment of the keynote (12:45) drives home one idea: a good agent verifies what it did. The most memorable demo used Claude Code: !Agentic validation loop Google gave the agent a list of critical user journeys and a single prompt — find and fix memory leaks. Claude ran each journey on a separate device in parallel, used android profiler leakcanary, followed each reference chain back to the code, fixed it and re-ran everything to confirm. What powers this workflow: - Journeys — user flows written in natural language. Your team writes them; the agent runs them. - Built-in LeakCanary — in the CLI and in the Studio Profiler, with Fix with AI (Canary). - Android Performance Analyzer (APA) — the Profiler's engine now powers the CLI too. With the android-profiler skill, the agent captures a trace, analyzes it, proposes a fix and measures the impact. - androidx.tracing 2.0 — trace sections with file, line and arguments; coroutines show up as connected flows. Start with androidx.tracing:tracing-wire. - Recomposition tracing (Compose 1.13) — shows why something recomposed, back to the state write that caused it. From a production crash to a fix android signals brings crashes, ANRs and memory issues to the terminal. Crashlytics now collects heap dumps from real OOMs and Android 17 Memory Limiter Kills, deobfuscated with your R8 mapping and opened in Perfetto (early access). R8 without fear # AGP 9.3: a score for your config and a ranking of the costliest keep rules ./gradlew :app:analyzeReleaseR8Config Pair it with the r8-analyzer skill and replace broad keep rules with Jetpack Keep (alpha), type-safe annotations that lint can add for you. --- 5. Before you ship: the traffic-light checklist One of the most practical moments of the event: instead of a manual release checklist, you ask the agent to audit the app and it returns a traffic-light report — 🟢 what's fine, 🟡 what needs a review, 🔴 what blocks submission. !The agent shows what's still missing before release, traffic-light style The official skill: play-policy-insights This format comes from the official play-policy-insights skill, which audits your code, manifest and SDKs against Google Play policies and cross-checks your Data safety declaration. 1. Install the skill android skills add play-policy-insights # alternative, outside Android CLI: npx skills add https://github.com/android/skills --skill play-policy-insights 2. Run it with a prompt (this is the one Google suggests): Audit this app for Google Play policy compliance before I submit it. 3. What it checks - Data safety — compares what your code collects and transmits with what you declared in the Play Console. - Demo login credentials — whether Play reviewers can actually get into the app. - Restricted permissions — sensitive or deprecated permissions where a scoped alternative is expected. 4. How to read the report | Overall status | Meaning | What to do | | --- | --- | --- | | 🟢 Compliant | No active violations found | Go ahead and submit | | 🟡 Needs Review | No critical violations, but manual Play Console declarations or restricted permissions need attention | Review before submitting | | 🔴 Non-Compliant | Violations or Data safety mismatches | Fix before submitting | Each finding has a severity — 🔴 Critical (verified violation), 🟡 Important (for example, a deprecated permission where a scoped one is expected), 🔵 Suggestion (advisory) — and lists the policy, affected files, evidence, a confidence level, a recommendation and reference links. The report ends with Data safety discrepancies, local data access and a remediation checklist. Two caveats: - The report is advisory: it is not legal advice or a guarantee of approval. - The skill writes scratch files to .scratch/play_policy_insights_<uuid> at the project root. Add .scratch/ to your .gitignore. In Android Studio, Play Policy Insights also shows up as lint checks right in your code. Going further: a "release readiness" skill with every gate Play policy is only one gate. With Android CLI's tools you can write your own skill that runs every gate and returns a single traffic light. Here's an example I wrote for study — adapt paths and thresholds to your project: --- name: release-readiness description: Use before publishing a release. Runs build, size, Play policy, security, stability and critical-journey gates and returns a traffic-light report. --- # Release readiness Run every gate below, in order. Do not stop at the first failure: the report must show all gates. ## Gates 1. **Build** — `./gradlew :app:bundleRelease`. 🔴 if it fails. 2. **Size and R8** — run `android analyze` on the release AAB and `./gradlew :app:analyzeReleaseR8Config`. 🟡 if the shrinking score dropped vs. `docs/release/last-analyze.json`. 🔴 if obfuscation is off. 3. **Play policy** — run the `play-policy-insights` skill and copy its overall status. 4. **Security** — run the `android-permissions-security` and `android-intent-security` skills. 🔴 for any Critical finding. 5. **Stability** — `android signals` for the current production version. 🟡 for new crash or ANR clusters. 🔴 if crash-free users fell below the threshold in `docs/release/thresholds.md`. 6. **Critical journeys** — run the Journeys in `journeys/`. 🔴 if any fails. ## Output Write `release-report.md` with: - the overall status (the worst gate wins); - one row per gate: status, gate, evidence, next action; - a remediation checklist. Do not publish, upload or tag anything. Shipping is a human decision. In Claude Code, save it as .claude/skills/release-readiness/SKILL.md and call it with /release-readiness. In other agents, use their equivalent skills folder. The "worst gate wins" rule is what turns six checks into one honest traffic light. --- 6. Compose-first in practice: from XML to Compose with a right-click Another keynote highlight: migrating a screen from XML Views to Jetpack Compose is no longer a manual project. The Migration Assistant (Android Studio Canary) shows up in the layout's context menu and hands the work to an agent. !Migration Assistant flow Step by step 1. Install the latest Android Studio Canary — the feature lives in that channel. 2. Pick your agent. It works with Studio's built-in agent or with any agent added through Bring Your Own Agent (Claude, Codex…). It's also worth installing the official Migrate to Compose skill, listed in android skills list. 3. Right-click the XML layout (for example, res/layout/fragment_profile.xml) and choose AI › Migrate to Compose. To migrate the whole project, open the action palette and run the migration from there. 4. Scope it with the agent. It asks what to migrate now, what stays in interop, and how to handle custom views. 5. Review the plan. The agent drafts a step-by-step plan before touching any file. 6. Conversion. The agent converts the layout, the view-binding code and the related logic into idiomatic Compose. 7. Follow the timeline. The agent window shows which step is running and where to resume if it stops. Progress is saved with the conversation, so you can step away and come back. 8. Validate. Check the Compose Previews (or android preview in the terminal) and run Change Review with /review before committing. Example: what goes in and what comes out An illustrative example of this kind of conversion — a profile screen using ViewBinding. Before (XML + ViewBinding): <!-- res/layout/fragment_profile.xml --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="16dp"> <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?attr/textAppearanceHeadlineSmall" /> <TextView android:id="@+id/role" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:id="@+id/follow" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/follow" /> </LinearLayout> class ProfileFragment : Fragment(R.layout.fragment_profile) { private val viewModel: ProfileViewModel by viewModels() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val binding = FragmentProfileBinding.bind(view) viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.uiState.collect { state -> binding.name.text = state.name binding.role.text = state.role binding.follow.isEnabled = !state.isFollowing } } } binding.follow.setOnClickListener { viewModel.follow() } } } After (idiomatic Compose, with hoisted state): @Composable fun ProfileRoute(viewModel: ProfileViewModel = viewModel()) { val state by viewModel.uiState.collectAsStateWithLifecycle() ProfileScreen(state = state, onFollow = viewModel::follow) } @Composable fun ProfileScreen(state: ProfileUiState, onFollow: () -> Unit, modifier: Modifier = Modifier) { Column(modifier.padding(16.dp)) { Text(state.name, style = MaterialTheme.typography.headlineSmall) Text(state.role) Button(onClick = onFollow, enabled = !state.isFollowing) { Text(stringResource(R.string.follow)) } } } @Preview @Composable private fun ProfileScreenPreview() { ProfileScreen(ProfileUiState(name = "Ada", role = "Android Engineer"), onFollow = {}) } During the transition, the Fragment can stay and simply host Compose: class ProfileFragment : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) = ComposeView(requireContext()).apply { setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) setContent { MaterialTheme { ProfileRoute() } } } } Checklist to review what the agent produced - [ ] Is state hoisted (stateless Composable + a Route that collects the ViewModel)? - [ ] Do texts use stringResource instead of hardcoded strings? - [ ] Was the XML theme mapped to MaterialTheme (colors, typography, shapes)? - [ ] Is accessibility preserved: contentDescription, touch target sizes, reading order? - [ ] Were UI tests moved to composeTestRule (or screenshot tests)? - [ ] No needless recompositions? Use Compose 1.13's recomposition tracing and the jetpack-compose-performance skill. - [ ] Were the old XML and binding class removed once the screen settled? Recommended strategy: migrate screen by screen, starting with the simplest ones or the ones you're about to touch anyway, and use ComposeView as the bridge. Migrating the whole app at once produces a diff nobody can review — even with an agent. --- 7. Compose-first: state beyond the UI with Jetpack AppState If you have ever fought a five-Flow combine, you will like this one. Jetpack AppState (alpha) runs the Compose runtime outside the UI, in ViewModels, repositories and services. Two pieces: - Transform — runs a @Composable block with no UI and returns a State<R> that recomposes whenever any state it reads changes. - StateStore — a type-safe map of state shared across activities, services and widgets, with optional DataStore persistence. [versions] appstate = "1.0.0-alpha01" [libraries] androidx-appstate-transform = { module = "androidx.appstate.transform:transform", version.ref = "appstate" } androidx-appstate-transform-testing = { module = "androidx.appstate.transform:transform-testing", version.ref = "appstate" } androidx-appstate-statestore = { module = "androidx.appstate.statestore:statestore", version.ref = "appstate" } > Note: any module that calls transform needs buildFeatures { compose = true } and the Compose Compiler plugin, even without UI. A ViewModel that switches sources based on connectivity: class HomeViewModel( private val mediaRepository: MediaRepository, private val networkMonitor: NetworkMonitor, ) : ViewModel() { val uiState: State<HomeUiState> = transform<HomeUiState>( initialValue = HomeUiState.Loading, scope = viewModelScope, ) { val isOnline by networkMonitor.isOnline val tracks = if (isOnline) { mediaRepository.allTracksFlow.collectAsState(initial = null).value } else { mediaRepository.downloadedTracksFlow.collectAsState(initial = null).value } ?: return@transform HomeUiState.Loading HomeUiState.Success(tracks = tracks, isOnline = isOnline) } } No flatMapLatest, no stateIn — a plain if decides which source to observe. Search debounce with LaunchedEffect, inside transform: var query: String by mutableStateOf("") val searchResults: List<String> by transform<List<String>>( initialValue = emptyList(), scope = coroutineScope, ) { var results by remember { mutableStateOf(emptyList<String>()) } LaunchedEffect(query) { if (query.isBlank()) { results = emptyList(); return@LaunchedEffect } delay(300.milliseconds) results = api.search(query) } results } When NOT to use transform: it represents the current value, not a stream of events. Rapid updates before recomposition are dropped, and equal consecutive values trigger nothing. For running totals, logs, one-time events and backpressure, stick with Flow. Testing is simple with transformTest: @Test fun testStateUpdate() = transformTest { var sourceState by mutableStateOf(0) val state = transform(initialValue = 0, scope = backgroundScope, dispatcher = testDispatcher) { sourceState } sourceState = 1 advance() assertThat(state.value).isEqualTo(1) } Rounding it out: Compose 1.13 (stable soon: Grid and FlexBox stable, Progressive Blur, Formatted Text) and Navigation 3 1.2 (stable: deep links and richer predictive back). Examples: android/appstate-recipes. --- 8. A2UI: when the agent's answer is a screen A wall of chat text is poor UX. With A2UI (Agent-to-UI), the agent sends declarative JSON and your app renders native components from your own catalog — no arbitrary code is executed. !A2UI flow in Jetpack Compose dependencies { implementation("androidx.a2ui.compose:compose-runtime:1.0.0-alpha01") implementation("androidx.a2ui.compose:compose-ui:1.0.0-alpha01") androidTestImplementation("androidx.a2ui.compose:compose-ui-testing:1.0.0-alpha01") } ViewModel: class AgenticUiViewModel : ViewModel() { private val parser = A2uiMessageParser() private val processor = A2uiMessageProcessor(catalogs = listOf(CustomDesignSystemCatalog)) val a2uiSurfaces: StateFlow<List<A2uiSurfaceModel>> = processor.activeSurfaces init { viewModelScope.launch(Dispatchers.Default) { processor.collectMessages() } // clicks and errors flow back to the agent viewModelScope.launch(start = CoroutineStart.UNDISPATCHED) { processor.outboundEvents.collect(::handleOutboundA2uiEvent) } } fun onNetworkMessage(json: String) = processor.processInput(parser, json) } Screen: @Composable fun AgenticUiScreen(viewModel: AgenticUiViewModel) { val surfaces by viewModel.a2uiSurfaces.collectAsStateWithLifecycle() Column(Modifier.fillMaxSize()) { surfaces.forEach { surface -> key(surface.id) { A2uiSurface(surfaceModel = surface) } } } } My favorite part: hallucination defenses come built in. An unknown component becomes an error reported back to the agent so it can self-correct; payloads are validated against a schema; absurd list indexes switch to a sparse map so they can't blow up memory. --- 9. Gemini Nano 4: a whole agent on the device Gemini Nano 4 brings native function calling, and ML Kit gained an Agentic API (alpha) that runs the complete agent loop on the device, on top of AICore. !Gemini Nano 4 and the ML Kit Agentic API Requirements: Android 14+ enrolled in the AICore Developer Preview, a supported device, minSdk 26, Kotlin 2.3+. dependencies { implementation("com.google.mlkit:genai-agent:1.0.0-alpha1") // optional: tools via AppFunctions implementation("androidx.appfunctions:appfunctions:1.0.0-alpha13") ksp("androidx.appfunctions:appfunctions-compiler:1.0.0-alpha13") } val agent = Agent.builder() .setName("Assistant") .setInstructions("You are a helpful on-device assistant.") .build() val runner = AgentRunner(agent) val session = runner.getOrCreateSession("chat_session") val prompt = Content.builder().text("Can you help me organize my day?").build() lifecycleScope.launch { session.runAsync(prompt) .textTokens() .collect { token -> Log.d("Agent", token) } } // no history: runner.runSingleTurnAsync(prompt) // on destroy: runner.close() Limits you need to know: - maxTurns defaults to 10, to prevent runaway loops and save battery. - Inference only runs while your app is in the foreground; too many calls return ErrorCode.BUSY. - The model can pick the wrong tool or argument: the safety of actions is your app's job. Confirm sensitive actions with the user. - For huge knowledge bases, Google itself recommends a hybrid architecture with cloud models. --- 10. Android MCP and AppFunctions: your app as a Gemini tool To me, this is the most strategic change of the event. AppFunctions is the mobile equivalent of MCP tools: your app becomes an on-device MCP server, and Gemini (or any authorized agent) discovers and calls your app's functions to fulfill a user's request. It is in beta and runs on Android 16+. !How a function in your app becomes a Gemini tool @RequiresApi(36) @AndroidEntryPoint @AppFunctionServiceEntryPoint( serviceName = "TaskAppFunctionService", appFunctionXmlFileName = "task_app_function_service", ) abstract class BaseTaskAppFunctionService : AppFunctionService() { @Inject internal lateinit var taskRepository: TaskRepository /** * Creates a task based on [createTaskParams]. * * @param createTaskParams The parameter to describe how to create the task. */ @AppFunction(isDescribedByKDoc = true) suspend fun createTask(createTaskParams: CreateTaskParams): Task = withContext(Dispatchers.IO) { if (createTaskParams.title == null && createTaskParams.content == null) { throw AppFunctionInvalidArgumentException("Title or content should be non-null") } val id = taskRepository.createTask(createTaskParams.title, createTaskParams.content) taskRepository.getTask(id)?.toTask() ?: throw AppFunctionElementNotFoundException("Task not found for ID = $id") } } /** The parameter to create the task. */ @AppFunctionSerializable(isDescribedByKDoc = true) data class CreateTaskParams( /** The title of the task. */ val title: String?, /** The content of the task. */ val content: String?, ) Two details worth noticing: 1. The KDoc is the prompt. With isDescribedByKDoc = true, your docs become the description the agent reads to decide when to call the function. Write them for the model. 2. Typed exceptions (AppFunctionInvalidArgumentException, AppFunctionElementNotFoundException) tell the agent why a call failed, so it can try another way. Testing without Gemini: adb shell cmd app_function list-app-functions AppFunctions vs a remote MCP server: AppFunctions runs locally, uses the app's real state and needs no backend. A remote MCP server is platform-agnostic and depends on the network. Agents consider both together. To reach users, the Connected Apps Platform (preview) brings your app's services to Gemini and Search: build with Android MCP or remote MCP, prototype in Gemini dev mode, and register through the Google Connected Console. > ⚠️ Reality check (Oct 2026): the Gemini integration is still limited to selected apps. You can implement and test today; for production there is an Early Access Program. --- 11. One codebase, many screens: Googlebook, foldables and XR !One codebase, many screens Googlebook is the new category of laptops built on an Android foundation, with partners such as HP, Dell, Lenovo, Acer and Asus. The same app runs on the phone and the laptop, with no separate codebase. The Compose adaptive skill was updated so your agent can do the heavy lifting: keyboard shortcuts, pointer cursors, hover states and tooltips; migration to Grid, FlexBox and mediaQuery; end-to-end state handling; and foldable postures, such as tabletop layouts for media and camera screens. > 📌 Heads-up from Google Play: in 2027 Play will look closely at how apps and games run on foldables. Follow the adaptive app quality guidelines. Android XR and XREAL AURA XREAL AURA is the first wired XR glasses running Android XR. It stays under 95 g because the compute lives in a puck powered by Snapdragon Reality Elite. It has a Sony Micro-OLED 1200p display at 120 Hz, runs Google Play apps and up to five virtual windows. Price: US$1,099 launch price through December (US$1,279 after), available in the US, Canada, Japan and South Korea. For developers, the key news: the Jetpack XR core is now stable (SceneCore, ARCore for Jetpack XR and XR Runtime), and so are the XR glasses emulators in Android Studio and the Android XR Engine Hub. Compose for XR is still alpha. The first step is spatializing a screen you already have: Subspace { SpatialPanel( SubspaceModifier .height(824.dp) .width(1400.dp) .resizable() .transformingMovable(), ) { MyExistingScreen() // your current Compose screen } } Content inside Subspace only renders when spatialization is on. On a phone it is ignored, so the same code serves both worlds. --- 12. Beyond the keynote: 5 labs to try this week 1. An agent with eyes and hands (stable) — install Android CLI and the plugin in Claude Code or Codex, write 3 Journeys for your critical flows, and ask: "run the journeys, capture a startup trace and propose the highest-impact fix". Measure cold start before and after. 2. Quality gates in CI (stable) — run android analyze on your release AAB, store the JSON as a pipeline artifact and fail the build if the shrinking score drops. Use analyzeReleaseR8Config to go after the 5 costliest keep rules. 3. A ViewModel without combine (alpha) — rewrite a ViewModel with 3+ sources using transform and test it with transformTest. Compare readability and check whether any event got lost. 4. Your app as a tool (beta) — use the AppFunctions skill to find your 3 highest-value functions, implement one and validate it with adb shell cmd app_function list-app-functions. 5. An answer as UI (alpha) — build an A2UI catalog with 3 components from your design system and feed it fixed JSON before wiring a real model. Test the error path. --- What the Dev Summit leaves behind The return of the Android Dev Summit was not defined by a single API. It was defined by a shift in the Android developer's role: orchestrating agents that build, validate and optimize the app — and designing the app to be used by agents. If you want to act now, here is my read: - Adopt today: Rabbit 2 with BYOA, Android CLI with skills, Change Review and the traffic-light checklist in your team's workflow. - This quarter: migrate the XML screens you touch most, map which app functions become AppFunctions, and get the UI adaptive for foldables and Googlebook. - As POCs: A2UI, Gemini Nano 4 and AppState, following the APIs on their way to stable. Which of these will you try first? Tell me in the comments. 👇 --- Sources - Android Dev Summit 2026 keynote - Agentic and Flexible: A next era of Android development - What's new in Android developer tools and performance at Android Dev Summit - Android skills (catalog) and play-policy-insights - Overview of AppFunctions - Render A2UI surfaces in your app - Build agentic workflows with Gemini Nano - Jetpack AppState and Transform - Develop UI with Jetpack Compose for XR - TechCrunch — Xreal Aura This article is also available in Portuguese and Spanish.

  3. Android Dev Summit 2026: o Google volta a reunir devs depois de quatro anos e coloca os agentes no centro do Android --- title: "Android Dev Summit 2026: o Google volta a reunir devs depois de quatro anos e coloca os agentes no centro do Android" published: true description: "Briefing do primeiro Android Dev Summit desde 2022: o que o Google anunciou, em que estágio está cada novidade e como usar, com código." tags: android, kotlin, ai, jetpackcompose series: Android Dev Summit 2026 cover_image: dev-to-uploads.s3.us-east-2.amazonaws.com --- !Android Dev Summit 2026: o Google volta a reunir devs depois de quatro anos e coloca os agentes no centro do Android Mountain View, 28 de outubro de 2026 — Depois de quatro anos sem um evento próprio, o Google voltou a realizar o Android Dev Summit. A última edição tinha sido em 2022; desde então, as novidades da plataforma dividiam espaço com o resto da programação do Google I/O. Desta vez foram dois dias dedicados só ao Android, no campus Bay View, com keynote transmitido no YouTube e uma edição estendida em Londres. O recado do keynote foi direto: o Android passa a ser construído com agentes de IA e para agentes de IA. O Android Studio abriu as portas para agentes de outras empresas, como Claude e Codex. O Android CLI deu a esses agentes acesso a aparelhos reais. E os apps ganharam um jeito padronizado de oferecer suas funções ao Gemini. Neste briefing eu reúno o que foi anunciado, em que estágio cada novidade está e — a parte que o keynote passa rápido — como usar cada uma no dia a dia, com código. {% embed youtube.com %} Ficha do evento | | | | --- | --- | | Quando | 28 e 29 de outubro de 2026 | | Onde | Campus Bay View do Google, Mountain View (EUA), com edição estendida em Londres | | Contexto | Primeiro Android Dev Summit desde 2022 | | Trilhas | AI experiences, Android XR, Apps foundation, Tools & performance | | Keynote | Cerca de 1 hora, com demos ao vivo — assista no YouTube | As manchetes - Android Studio Rabbit 2 chega ao canal stable e aceita qualquer agente de código compatível com ACP — Claude, Codex, Antigravity e mais de 40 outros. - Android CLI ganha aparelhos físicos remotos, renderização de Compose Preview no terminal, profiler com LeakCanary e plugins oficiais para Claude Code e Codex. - Checklist de publicação em semáforo: a skill play-policy-insights audita o app antes do envio ao Google Play e aponta 🟢🟡🔴 o que falta. - Migração de XML para Compose com um clique direito, conduzida por um agente dentro do Android Studio. - AppFunctions entra em beta: funções do seu app viram tools para o Gemini e outros agentes, via Android MCP. - A2UI (alpha): o agente passa a responder com telas nativas em Compose, montadas com o seu design system. - Gemini Nano 4 + ML Kit Agentic API (alpha): um agente inteiro rodando no aparelho, com chamada de funções. - Jetpack AppState (alpha) leva o modelo de estado do Compose para ViewModels e repositórios. - Googlebook, foldables e Android XR: um código para muitas telas. O XREAL AURA estreia como o primeiro óculos XR com fio rodando Android XR. --- 1. O que já dá para usar (e o que ainda é laboratório) Antes de sair instalando tudo, vale olhar a maturidade de cada anúncio. !Quadro de maturidade dos anúncios Minha regra prática: stable vai para produção, beta entra atrás de feature flag, alpha e preview ficam em POC e estudo. --- 2. Android Studio Rabbit 2: traga o seu agente O Android Studio deixou de ser "o IDE com o Gemini". Com o Bring Your Own Agent (BYOA), agora stable no Rabbit 2, ele vira o host de qualquer agente compatível com o Agent Client Protocol (ACP). Como ativar: 1. Abra Settings > Tools > AI > Agents. 2. Instale agentes pelo marketplace (Claude Agent, Codex, Antigravity…). Dá para ter vários e alternar. 3. O agente passa a enxergar o que só o IDE sabe: estrutura do projeto e do build, resolução de símbolos, render de Compose Preview, Emulator e Logcat. Junto vieram três recursos que mudam o dia a dia: - Change Review — revisão agêntica das mudanças que o agente fez. Inicie pela lista de mudanças pendentes, pela janela de Git ou com /review. Gera relatório de problemas e um walkthrough guiado para mudanças grandes. - Migration Assistant (Canary) — clique direito em um layout XML > AI › Migrate to Compose e o agente migra a tela para Compose. Tem uma seção inteira só sobre isso mais abaixo. - Android Bench 2.0 — leaderboard que avalia modelos e harnesses em tarefas Android longas (migrar UI, construir app a partir de mocks), medindo se funciona de verdade, custo e tempo. Ótimo para escolher o agente do time: developer.android.com. ACP x MCP: não confunda Esse foi o ponto que mais vi gerar confusão. São dois protocolos com papéis diferentes: !ACP ajuda você a construir; MCP deixa agentes usarem o seu app --- 3. Android CLI: o toolchain inteiro na mão do agente O Android CLI é a interface "tool-first" para qualquer terminal, agente ou pipeline de CI. A ideia é simples: o agente para de gastar tokens adivinhando como o Android funciona e passa a usar ferramentas oficiais. # instale o CLI e configure o agente android init # aparelho físico real, num device lab do Google (via Firebase) android device remote connect android device hub # janela para ver e controlar aparelhos e emuladores # Compose Previews sem emulador e sem IDE android preview # performance e memória android profiler systemtrace android profiler heapdump capture android profiler leakcanary # qualidade do binário e sinais de produção android analyze app-release.aab android signals # skills e documentação android skills list android skills add jetpack-compose-performance android docs search "predictive back" Os números divulgados pelo Google chamam atenção: agentes usando android preview terminaram tarefas de UI 77% mais rápido usando até 3x menos tokens. Plugins oficiais para Claude Code e Codex # Claude Code (dentro da sessão) /plugin marketplace add android/android-cli-plugin /plugin install android-cli@android-cli-plugin # Claude Code (terminal) claude plugin marketplace add android/android-cli-plugin claude plugin install android-cli@android-cli-plugin # Codex codex plugin marketplace add android/android-cli-plugin codex plugin add android-cli@android-cli-plugin O plugin dá ao agente o necessário para criar projetos, gerenciar emuladores, inspecionar layouts ao vivo, rodar Journeys, instalar skills oficiais e consultar a Android Knowledge Base. Skills oficiais São mais de 30 skills em mais de 20 áreas, cada uma com avaliação. Elas focam onde os modelos costumam errar: performance de Compose, APIs novas de câmera, auditoria de segurança. Algumas que valem instalar já: - jetpack-compose-performance - android-profiler - r8-analyzer - play-policy-insights (audita código, manifest e SDKs contra as políticas do Play antes do envio) - android-intent-security e android-permissions-security Repositório: android/skills. --- 4. Validação: o agente confere o próprio trabalho O trecho "Validating apps with Android Prototype" do keynote (12:45) bate numa tecla: agente bom é agente que valida o que fez. A demo mais marcante foi com o Claude Code: !Loop de validação agêntica O Google deu ao agente uma lista de jornadas críticas e um único prompt — encontrar e corrigir memory leaks. O Claude rodou cada jornada num aparelho separado, em paralelo, usou android profiler leakcanary, seguiu as cadeias de referência até o código, corrigiu e rodou tudo de novo para confirmar. O que sustenta esse fluxo: - Journeys — fluxos de usuário descritos em linguagem natural. O time escreve, o agente executa. - LeakCanary integrado — no CLI e no Profiler do Studio, com Fix with AI (Canary). - Android Performance Analyzer (APA) — o motor do Profiler agora também alimenta o CLI. Com a skill android-profiler, o agente captura trace, analisa, propõe correção e mede o impacto. - androidx.tracing 2.0 — traces com arquivo, linha e argumentos; coroutines aparecem como fluxos conectados. Comece com androidx.tracing:tracing-wire. - Recomposition tracing (Compose 1.13) — mostra por que algo recompôs, até a escrita de estado que causou. Do crash em produção à correção android signals traz crashes, ANRs e problemas de memória para o terminal. E o Crashlytics agora coleta heap dumps de OOMs reais e de Memory Limiter Kills do Android 17, desofuscados com o mapping do R8 e abertos no Perfetto (em early access). R8 sem medo # AGP 9.3: nota da sua configuração e ranking das keep rules mais caras ./gradlew :app:analyzeReleaseR8Config Combine com a skill r8-analyzer e troque keep rules genéricas por Jetpack Keep (alpha), com anotações type-safe que o lint adiciona por você. --- 5. Antes do deploy: o checklist em semáforo Um dos momentos mais práticos do evento: em vez de um checklist manual de publicação, você pede ao agente que audite o app e ele devolve um relatório em semáforo — 🟢 o que está ok, 🟡 o que precisa de revisão, 🔴 o que bloqueia o envio. !O agente mostra, em semáforo, o que ainda falta antes do deploy A skill oficial: play-policy-insights Esse formato vem da skill oficial play-policy-insights, que audita código, manifest e SDKs contra as políticas do Google Play e cruza com a sua declaração de Data safety. 1. Instale a skill android skills add play-policy-insights # alternativa, fora do Android CLI: npx skills add https://github.com/android/skills --skill play-policy-insights 2. Rode com um prompt (o Google sugere este): Audit this app for Google Play policy compliance before I submit it. 3. O que ela verifica - Data safety — compara o que o código coleta e envia com o que você declarou no Play Console. - Credenciais de login de demonstração — se os revisores do Play conseguem entrar no app. - Permissões restritas — uso de permissões sensíveis ou obsoletas onde há alternativa com escopo. 4. Como ler o relatório | Status geral | Significado | O que fazer | | --- | --- | --- | | 🟢 Compliant | Nenhuma violação ativa encontrada | Seguir com o envio | | 🟡 Needs Review | Sem violações críticas, mas há declarações manuais no Play Console ou permissões restritas para revisar | Revisar antes de enviar | | 🔴 Non-Compliant | Violações ou divergências no Data safety | Corrigir antes do envio | Cada achado tem severidade — 🔴 Critical (violação confirmada), 🟡 Important (por exemplo, permissão obsoleta onde se espera uma com escopo), 🔵 Suggestion (recomendação) — e vem com política afetada, arquivos, evidência, nível de confiança, recomendação e links. O relatório termina com divergências de Data safety, acessos locais a dados e um checklist de remediação. Dois cuidados: - O relatório é consultivo: não é parecer jurídico nem garantia de aprovação. - A skill grava arquivos temporários em .scratch/play_policy_insights_<uuid> na raiz do projeto. Coloque .scratch/ no .gitignore. No Android Studio, o Play Policy Insights também aparece como verificações de lint direto no código. Indo além: uma skill de "release readiness" com todos os gates A política do Play é só um dos portões. Com as ferramentas do Android CLI dá para montar uma skill própria que roda todos os gates e devolve um único semáforo. Este é um exemplo que escrevi para estudo — adapte os caminhos e limites ao seu projeto: --- name: release-readiness description: Use antes de publicar uma release. Roda os gates de build, tamanho, política do Play, segurança, estabilidade e jornadas críticas e devolve um relatório em semáforo. --- # Release readiness Rode todos os gates abaixo, em ordem. Não pare na primeira falha: o relatório precisa mostrar todos. ## Gates 1. **Build** — `./gradlew :app:bundleRelease`. 🔴 se falhar. 2. **Tamanho e R8** — rode `android analyze` no AAB de release e `./gradlew :app:analyzeReleaseR8Config`. 🟡 se a nota de shrinking caiu em relação a `docs/release/last-analyze.json`. 🔴 se a ofuscação estiver desligada. 3. **Política do Play** — rode a skill `play-policy-insights` e copie o status geral dela. 4. **Segurança** — rode as skills `android-permissions-security` e `android-intent-security`. 🔴 para qualquer achado Critical. 5. **Estabilidade** — `android signals` na versão de produção atual. 🟡 para novos clusters de crash ou ANR. 🔴 se a taxa de usuários sem crash ficou abaixo do limite em `docs/release/thresholds.md`. 6. **Jornadas críticas** — rode as Journeys de `journeys/`. 🔴 se alguma falhar. ## Saída Escreva `release-report.md` com: - status geral (o pior gate define o status); - uma linha por gate: status, gate, evidência, próxima ação; - checklist de remediação. Não publique, não faça upload e não crie tags. A decisão de publicar é humana. No Claude Code, salve em .claude/skills/release-readiness/SKILL.md e chame com /release-readiness. Em outros agentes, use a pasta de skills equivalente. A regra "o pior gate define o status" é o que transforma seis verificações num semáforo único e honesto. --- 6. Compose-first na prática: de XML para Compose com um clique direito Outro destaque do keynote: migrar uma tela de XML Views para Jetpack Compose deixou de ser um projeto manual. O Migration Assistant (Android Studio Canary) aparece no menu de contexto do layout e entrega o trabalho para um agente. !Fluxo do Migration Assistant Passo a passo 1. Instale o Android Studio Canary mais recente — a feature está nesse canal. 2. Escolha o agente. Funciona com o agente nativo do Studio ou com qualquer agente adicionado via Bring Your Own Agent (Claude, Codex…). Vale também instalar a skill oficial Migrate to Compose, que aparece em android skills list. 3. Clique direito no layout XML (por exemplo, res/layout/fragment_profile.xml) e escolha AI › Migrate to Compose. Para migrar o projeto inteiro, abra a action palette e rode a migração por lá. 4. Defina o escopo junto com o agente. Ele pergunta o que migrar agora, o que fica em interoperabilidade e como tratar componentes customizados. 5. Revise o plano. O agente monta um plano por etapas antes de alterar qualquer arquivo. 6. Conversão. O agente converte o layout, o código de view binding e a lógica associada em Compose idiomático. 7. Acompanhe pela timeline. A janela do agente mostra qual etapa está rodando e de onde retomar se ele parar. O progresso fica salvo com a conversa: dá para sair e voltar depois. 8. Valide. Confira os Compose Previews (ou android preview no terminal) e rode o Change Review com /review antes do commit. Exemplo: o que entra e o que sai Um exemplo ilustrativo do tipo de conversão — uma tela de perfil com ViewBinding. Antes (XML + ViewBinding): <!-- res/layout/fragment_profile.xml --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="16dp"> <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?attr/textAppearanceHeadlineSmall" /> <TextView android:id="@+id/role" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:id="@+id/follow" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/follow" /> </LinearLayout> class ProfileFragment : Fragment(R.layout.fragment_profile) { private val viewModel: ProfileViewModel by viewModels() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val binding = FragmentProfileBinding.bind(view) viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.uiState.collect { state -> binding.name.text = state.name binding.role.text = state.role binding.follow.isEnabled = !state.isFollowing } } } binding.follow.setOnClickListener { viewModel.follow() } } } Depois (Compose idiomático, com estado elevado): @Composable fun ProfileRoute(viewModel: ProfileViewModel = viewModel()) { val state by viewModel.uiState.collectAsStateWithLifecycle() ProfileScreen(state = state, onFollow = viewModel::follow) } @Composable fun ProfileScreen(state: ProfileUiState, onFollow: () -> Unit, modifier: Modifier = Modifier) { Column(modifier.padding(16.dp)) { Text(state.name, style = MaterialTheme.typography.headlineSmall) Text(state.role) Button(onClick = onFollow, enabled = !state.isFollowing) { Text(stringResource(R.string.follow)) } } } @Preview @Composable private fun ProfileScreenPreview() { ProfileScreen(ProfileUiState(name = "Ada", role = "Android Engineer"), onFollow = {}) } Durante a transição, o Fragment pode continuar existindo e só hospedar o Compose: class ProfileFragment : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) = ComposeView(requireContext()).apply { setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) setContent { MaterialTheme { ProfileRoute() } } } } Checklist para revisar o que o agente gerou - [ ] O estado está elevado (Composable sem estado + Route que coleta o ViewModel)? - [ ] Textos usam stringResource e não strings fixas? - [ ] O tema do XML foi mapeado para MaterialTheme (cores, tipografia, shapes)? - [ ] Acessibilidade preservada: contentDescription, tamanhos de toque, ordem de leitura? - [ ] Testes de UI migrados para composeTestRule (ou screenshot tests)? - [ ] Sem recomposições desnecessárias? Use o recomposition tracing do Compose 1.13 e a skill jetpack-compose-performance. - [ ] XML e classe de binding antigos removidos depois que a tela estabilizou? Estratégia recomendada: migre tela a tela, começando pelas mais simples ou pelas que você já vai mexer, e use ComposeView como ponte. Migrar o app inteiro de uma vez gera um diff impossível de revisar — mesmo com agente. --- 7. Compose-first: estado fora da UI com Jetpack AppState Quem já brigou com combine de cinco Flows vai gostar dessa. O Jetpack AppState (alpha) usa o runtime do Compose fora da UI, em ViewModels, repositórios e serviços. São duas peças: - Transform — roda um bloco @Composable sem UI e devolve um State<R> que recompõe sozinho quando qualquer estado lido muda. - StateStore — mapa type-safe de estado compartilhado entre activities, services e widgets, com integração opcional ao DataStore. [versions] appstate = "1.0.0-alpha01" [libraries] androidx-appstate-transform = { module = "androidx.appstate.transform:transform", version.ref = "appstate" } androidx-appstate-transform-testing = { module = "androidx.appstate.transform:transform-testing", version.ref = "appstate" } androidx-appstate-statestore = { module = "androidx.appstate.statestore:statestore", version.ref = "appstate" } > Atenção: todo módulo que chama transform precisa de buildFeatures { compose = true } e do plugin do Compose Compiler, mesmo sem UI. Antes e depois. Um ViewModel que troca de fonte conforme a conectividade: class HomeViewModel( private val mediaRepository: MediaRepository, private val networkMonitor: NetworkMonitor, ) : ViewModel() { val uiState: State<HomeUiState> = transform<HomeUiState>( initialValue = HomeUiState.Loading, scope = viewModelScope, ) { val isOnline by networkMonitor.isOnline val tracks = if (isOnline) { mediaRepository.allTracksFlow.collectAsState(initial = null).value } else { mediaRepository.downloadedTracksFlow.collectAsState(initial = null).value } ?: return@transform HomeUiState.Loading HomeUiState.Success(tracks = tracks, isOnline = isOnline) } } Sem flatMapLatest, sem stateIn, e o if comum decide qual fonte observar. Debounce de busca com LaunchedEffect, dentro do transform: var query: String by mutableStateOf("") val searchResults: List<String> by transform<List<String>>( initialValue = emptyList(), scope = coroutineScope, ) { var results by remember { mutableStateOf(emptyList<String>()) } LaunchedEffect(query) { if (query.isBlank()) { results = emptyList(); return@LaunchedEffect } delay(300.milliseconds) results = api.search(query) } results } Quando NÃO usar transform: ele representa o valor atual, não um fluxo de eventos. Atualizações rápidas antes da recomposição são descartadas e valores iguais em sequência não disparam nada. Para totais acumulados, logs, eventos únicos e backpressure, continue com Flow. Testes ficam simples com transformTest: @Test fun testStateUpdate() = transformTest { var sourceState by mutableStateOf(0) val state = transform(initialValue = 0, scope = backgroundScope, dispatcher = testDispatcher) { sourceState } sourceState = 1 advance() assertThat(state.value).isEqualTo(1) } Completam o pacote Compose 1.13 (stable em breve: Grid e FlexBox stable, Progressive Blur, Formatted Text) e Navigation 3 1.2 (stable: deep links e predictive back mais rico). Exemplos: android/appstate-recipes. --- 8. A2UI: quando a resposta do agente é uma tela Chat com muro de texto não é boa UX. Com o A2UI (Agent-to-UI), o agente envia JSON declarativo e o seu app renderiza componentes nativos do seu catálogo — sem executar código arbitrário. !Fluxo do A2UI em Jetpack Compose dependencies { implementation("androidx.a2ui.compose:compose-runtime:1.0.0-alpha01") implementation("androidx.a2ui.compose:compose-ui:1.0.0-alpha01") androidTestImplementation("androidx.a2ui.compose:compose-ui-testing:1.0.0-alpha01") } ViewModel: class AgenticUiViewModel : ViewModel() { private val parser = A2uiMessageParser() private val processor = A2uiMessageProcessor(catalogs = listOf(CustomDesignSystemCatalog)) val a2uiSurfaces: StateFlow<List<A2uiSurfaceModel>> = processor.activeSurfaces init { viewModelScope.launch(Dispatchers.Default) { processor.collectMessages() } // cliques e erros voltam para o agente viewModelScope.launch(start = CoroutineStart.UNDISPATCHED) { processor.outboundEvents.collect(::handleOutboundA2uiEvent) } } fun onNetworkMessage(json: String) = processor.processInput(parser, json) } Tela: @Composable fun AgenticUiScreen(viewModel: AgenticUiViewModel) { val surfaces by viewModel.a2uiSurfaces.collectAsStateWithLifecycle() Column(Modifier.fillMaxSize()) { surfaces.forEach { surface -> key(surface.id) { A2uiSurface(surfaceModel = surface) } } } } O que mais gostei: as defesas contra alucinação já vêm prontas. Componente desconhecido vira erro reportado ao agente para ele se corrigir; o payload é validado contra schema; índices de lista absurdos viram mapa esparso para não estourar memória. --- 9. Gemini Nano 4: um agente inteiro no aparelho O Gemini Nano 4 trouxe function calling nativo, e o ML Kit ganhou uma Agentic API (alpha) que roda o loop agêntico completo no aparelho, sobre o AICore. !Gemini Nano 4 e a ML Kit Agentic API Pré-requisitos: Android 14+ no AICore Developer Preview, aparelho suportado, minSdk 26, Kotlin 2.3+. dependencies { implementation("com.google.mlkit:genai-agent:1.0.0-alpha1") // opcional: tools via AppFunctions implementation("androidx.appfunctions:appfunctions:1.0.0-alpha13") ksp("androidx.appfunctions:appfunctions-compiler:1.0.0-alpha13") } val agent = Agent.builder() .setName("Assistant") .setInstructions("You are a helpful on-device assistant.") .build() val runner = AgentRunner(agent) val session = runner.getOrCreateSession("chat_session") val prompt = Content.builder().text("Can you help me organize my day?").build() lifecycleScope.launch { session.runAsync(prompt) .textTokens() .collect { token -> Log.d("Agent", token) } } // sem histórico: runner.runSingleTurnAsync(prompt) // ao destruir: runner.close() Limites que você precisa saber: - maxTurns padrão é 10, para evitar loop infinito e poupar bateria. - Inferência só com o app em primeiro plano; excesso de chamadas devolve ErrorCode.BUSY. - O modelo pode escolher a tool ou o argumento errado: a segurança das ações é do seu app. Confirme ações sensíveis com o usuário. - Para bases de conhecimento enormes, o próprio Google recomenda arquitetura híbrida com modelos em nuvem. --- 10. Android MCP e AppFunctions: seu app como tool do Gemini Esta é, para mim, a mudança mais estratégica do evento. AppFunctions é o equivalente mobile das tools do MCP: seu app vira um servidor MCP on-device e o Gemini (ou outro agente autorizado) descobre e chama funções do app para cumprir o pedido do usuário. Está em beta e roda no Android 16+. !Como uma função do seu app vira uma tool do Gemini @RequiresApi(36) @AndroidEntryPoint @AppFunctionServiceEntryPoint( serviceName = "TaskAppFunctionService", appFunctionXmlFileName = "task_app_function_service", ) abstract class BaseTaskAppFunctionService : AppFunctionService() { @Inject internal lateinit var taskRepository: TaskRepository /** * Creates a task based on [createTaskParams]. * * @param createTaskParams The parameter to describe how to create the task. */ @AppFunction(isDescribedByKDoc = true) suspend fun createTask(createTaskParams: CreateTaskParams): Task = withContext(Dispatchers.IO) { if (createTaskParams.title == null && createTaskParams.content == null) { throw AppFunctionInvalidArgumentException("Title or content should be non-null") } val id = taskRepository.createTask(createTaskParams.title, createTaskParams.content) taskRepository.getTask(id)?.toTask() ?: throw AppFunctionElementNotFoundException("Task not found for ID = $id") } } /** The parameter to create the task. */ @AppFunctionSerializable(isDescribedByKDoc = true) data class CreateTaskParams( /** The title of the task. */ val title: String?, /** The content of the task. */ val content: String?, ) Repare em dois detalhes: 1. O KDoc é o prompt. Com isDescribedByKDoc = true, a documentação vira a descrição que o agente lê para decidir quando chamar a função. Escreva pensando no modelo. 2. Exceções tipadas (AppFunctionInvalidArgumentException, AppFunctionElementNotFoundException) dizem ao agente por que falhou, para ele tentar de outro jeito. Testando sem o Gemini: adb shell cmd app_function list-app-functions AppFunctions x servidor MCP remoto: AppFunctions roda local, usa o estado real do app e não exige backend. MCP remoto é agnóstico de plataforma e depende de rede. Os agentes consideram os dois juntos. Para levar isso a usuários, a Connected Apps Platform (preview) leva os serviços do app ao Gemini e à Busca: você constrói com Android MCP ou MCP remoto, prototipa no Gemini dev mode e registra no Google Connected Console. > ⚠️ Realidade em out/2026: a integração com o Gemini ainda está restrita a apps selecionados. Dá para implementar e testar hoje; para produção, há um Early Access Program. --- 11. Um código, muitas telas: Googlebook, foldables e XR !Um código, muitas telas Googlebook é a nova categoria de laptops sobre base Android, com parceiros como HP, Dell, Lenovo, Acer e Asus. O mesmo app roda no celular e no notebook, sem codebase separado. A Compose adaptive skill foi atualizada para o agente fazer o trabalho pesado: atalhos de teclado, cursores, hover e tooltips; migração para Grid, FlexBox e mediaQuery; estado ponta a ponta; e posturas de foldable, como layout tabletop em telas de mídia e câmera. > 📌 Recado do Google Play: em 2027 o Play vai olhar de perto como apps e jogos rodam em foldables. Siga as adaptive quality guidelines. Android XR e XREAL AURA O XREAL AURA é o primeiro óculos XR com fio rodando Android XR. Fica abaixo de 95 g porque o processamento vai num "puck" com Snapdragon Reality Elite. Tem tela Sony Micro-OLED 1200p a 120 Hz, roda apps do Google Play e até cinco janelas virtuais. Preço: US$ 1.099 promocional até dezembro (US$ 1.279 depois), à venda nos EUA, Canadá, Japão e Coreia do Sul. Para devs, o mais importante: o núcleo do Jetpack XR ficou stable (SceneCore, ARCore for Jetpack XR e XR Runtime), assim como os emuladores de óculos XR no Android Studio e o Android XR Engine Hub. O Compose for XR segue em alpha. O primeiro passo é espacializar uma tela que você já tem: Subspace { SpatialPanel( SubspaceModifier .height(824.dp) .width(1400.dp) .resizable() .transformingMovable(), ) { MyExistingScreen() // sua tela Compose atual } } O conteúdo de Subspace só aparece quando a espacialização está ativa. No celular ele é ignorado, então o mesmo código serve para os dois mundos. --- 12. Indo além do keynote: 5 laboratórios para fazer esta semana 1. Agente com olhos e mãos (stable) — instale o Android CLI e o plugin no Claude Code ou Codex, escreva 3 Journeys dos fluxos críticos e peça: "rode as jornadas, capture o trace de startup e proponha a correção de maior impacto". Meça o cold start antes e depois. 2. Qualidade no CI (stable) — rode android analyze no AAB de release, salve o JSON como artefato e falhe o build se a nota de shrinking cair. Use analyzeReleaseR8Config para atacar as 5 keep rules mais caras. 3. ViewModel sem combine (alpha) — reescreva um ViewModel com 3+ fontes usando transform e teste com transformTest. Compare legibilidade e verifique se algum evento se perdeu. 4. Seu app como tool (beta) — use a skill de AppFunctions para achar as 3 funções de maior valor, implemente uma e valide com adb shell cmd app_function list-app-functions. 5. Resposta como UI (alpha) — monte um catálogo A2UI com 3 componentes do seu design system e alimente com JSON fixo antes de ligar um modelo real. Teste o caminho de erro. --- O que fica do Dev Summit O retorno do Android Dev Summit não foi marcado por uma API isolada. Foi marcado por uma mudança no papel de quem desenvolve para Android: orquestrar agentes que constroem, validam e otimizam o app — e projetar o app para ser usado por agentes. Para quem quer agir agora, minha leitura é esta: - Já dá para adotar: Rabbit 2 com BYOA, Android CLI com skills, Change Review e o checklist em semáforo no fluxo do time. - Neste trimestre: migrar as telas XML mais mexidas, mapear quais funções do app viram AppFunctions e preparar a UI adaptativa para foldables e Googlebook. - Em POC: A2UI, Gemini Nano 4 e AppState, acompanhando a evolução das APIs até o stable. E você, qual dessas novidades vai testar primeiro? Conta nos comentários. 👇 --- Fontes - Android Dev Summit 2026 keynote - Agentic and Flexible: A next era of Android development - What's new in Android developer tools and performance at Android Dev Summit - Android skills (catálogo) e play-policy-insights - Overview of AppFunctions - Render A2UI surfaces in your app - Build agentic workflows with Gemini Nano - Jetpack AppState e Transform - Develop UI with Jetpack Compose for XR - TechCrunch — Xreal Aura Este artigo também está disponível em inglês e espanhol.

  4. Qiita · · @Nabe1216

    Jetpack AppState TransformとStateStore AppState とは Jetpack Compose を UI レイヤーを超えて拡張し、アプリのあらゆるレイヤー間でリアクティブな状態を変換および共有できるようにするライブラリ群です。 Compose の UI で使用していた State を UI を超えて使うためのヘルパーを提供するものとなっています。 AppState 1.0.0-alpha01 時点では Transform と StateStore が用意されているので、それぞれ使い方を見ていきます。 Transform Flow のようなリアクティブデータを UI で使用可能な状態に変換したり、複数の Flow をまとめて一つの State に統合したりするのが Transform のユースケースです。 Transform が提供する API は以下の変換する処理だけを提供しています。引数の onUpdate が Composable fun になっているのが特徴で、内部で購読や LaunchedEffect の使用ができるようになっています。 (つまりは UI モジュール以外での Compose Compiler の設定や Compose の buildFeature を有効にする必要がある) public fun <R> transform( initialValue: R, scope: CoroutineScope, dispatcher: CoroutineDispatcher = Dispatchers.Default, onUpdate: @Composable (R) -> R, ): State<R> @Composable public fun <R> transform( initialValue: R, dispatcher: CoroutineDispatcher = Dispatchers.Default, onUpdate: @Composable (R) -> R, ): State<R> public suspend fun listener( dispatcher: CoroutineDispatcher = Dispatchers.Default, onUpdate: @Composable () -> Unit, ) 例えば ViewModel で Transform を利用すると次のようになります。 onUpdate が Composable fun なので networkMonitor.isOnline の State の状態更新や Flow の購読を行うことができます。 interface NetworkMonitor { val isOnline: State<Boolean> } interface MediaRepository { val allTracksFlow: Flow<List<Track>> val downloadedTracksFlow: Flow<List<Track>> } class HomeViewModel( private val mediaRepository: MediaRepository, private val networkMonitor: NetworkMonitor, ) : ViewModel() { val uiState: State<HomeUiState> = transform<HomeUiState>( initialValue = HomeUiState.Loading, scope = viewModelScope, ) { val isOnline by networkMonitor.isOnline val tracks = if (isOnline) { mediaRepository.allTracksFlow.collectAsState(initial = null).value } else { mediaRepository.downloadedTracksFlow .collectAsState(initial = null).value } ?: return@transform HomeUiState.Loading HomeUiState.Success( tracks = tracks, isOnline = isOnline, ) } } 以下は LaunchedEffect を使用した debounce の実装例です。 Composable fun を使っているので LaunchedEffect のような副作用も扱うことができます。 var query: String by mutableStateOf("") val searchResults: List<String> by transform<List<String>>( initialValue = emptyList(), scope = coroutineScope, ) { var results by remember { mutableStateOf(emptyList<String>()) } LaunchedEffect(query) { if (query.isBlank()) { results = emptyList() return@LaunchedEffect } delay(300.milliseconds) results = api.search(query) } results } StateStore State をアプリ本体だけでなくて、AppWidget であったり Glasses 、 AppFunctions などの同じプロセスのコンポーネント間で共有するのがユースケースです。 StateStore が提供する API は以下で、key と CURD の機能を提供しています。 public class StateStore { public val keys: Set<StateStoreKey<*>> public fun <T> getState( stateKey: StateStoreKey<T>, defaultValue: T = stateKey.defaultValue, ): State<T> public fun <T> setState(stateKey: StateStoreKey<T>, value: T) public inline fun <T> updateState( stateKey: StateStoreKey<T>, defaultValue: T = stateKey.defaultValue, update: (T) -> T, ) } @Serializable public open class StateStoreKey<T>( public val defaultValue: T, ) 基本的な使い方は以下のように、StateStore をインスタンス化して Repository などに渡して使います。 @Module @InstallIn(SingletonComponent::class) object AppModule { @Singleton @Provides fun provideStateStore(): StateStore = StateStore() } @Serializable private object AccessTokenKey : StateStoreKey<String>("") class AuthStateHolder @Inject constructor( private val stateStore: StateStore ) { val accessToken: State<String?> = derivedStateOf { stateStore.getState(AccessTokenKey).value.ifBlank { null } } val isLoggedIn: State<Boolean> = derivedStateOf { accessToken.value != null } fun setAccessToken(token: String) { stateStore.setState(AccessTokenKey, token) } fun clear() { stateStore.setState(AccessTokenKey, "") } } StateStore と DataStore を統合することもできます。 PersistToDataStore のインターフェースを key に実装することで、永続化すべきものをマークし、StateStore#syncToDataStore で DataStore を bind します。 @Serializable private object AccessTokenKey : StateStoreKey<String>(""), PersistToDataStore @Module @InstallIn(SingletonComponent::class) object AppModule { private val applicationScope = CoroutineScope(SupervisorJob() + Dispatchers.Default) @Singleton @Provides fun provideStateStore( @ApplicationContext context: Context, ): StateStore = StateStore().also { store -> applicationScope.launch { store.syncToDataStore( path = dataStoreFile(context.applicationContext.filesDir, "statestore.json").absolutePath, coroutineScope = applicationScope, ) } } } UI 以外で Compose を使うことについて Jetpack Compose の State は Compose の snapshot を使った汎用的な値ホルダーで、主に UI の再構成に使用されますが State 自体は UI レンダリングとは直接関係ありません。 Compose 特有の snapshot による状態管理の恩恵をアプリのアーキテクチャ全体で受けられることが UI 以外で Compose を使うことのメリットで、AppState が提供する機能になります。 StateFlow と比較した場合は、StateFlow のように「単一の巨大なStateFlowで全てを包む(StateFlow<UiState> のような関係ない値の更新でも全て再計算されてしまう)」か、「複数の StateFlow に分ける(同時に更新できないため読み取り側が不整合な中間状態を見てしまう)」のどちらかになることを避けられるのが利点になります。 ちなみにこのアプローチは Molecule が元になっています。 - * * AppState は Compose の機能を UI 以外でも使うかどうか、で議論が生まれると思います。個人的には現状の StateFlow で破綻していないなら、無理に採用する必要はないと見ています。 StateFlow を使っていて更新競合であったり combine での分岐の難しさに遭遇しているのであれば導入を検討してみるといいと思います。 参考 - developer.android.com - android/appstate-recipes - youtu.be

    4 likes

Latest stargazers

The last 10 distinct accounts we observed this year.

Most active participants

PR, issue, comment & review events in the past year.

Packages

Scan pending.

README badges

Embed a badge in your README or website.

Live mentions · last 30 days
android/appstate-recipes mentions in the last 30 days