Multiventana en móviles
Tauri admite múltiples ventanas en Android e iOS, lo que permite a tu aplicación mostrar contenido lado a lado en tabletas o en escenas separadas en iPad.
En Android, las ventanas múltiples se implementan utilizando Activity Embedding, lo que permite al sistema mostrar dos actividades lado a lado en pantallas grandes.
En iOS, las ventanas múltiples utilizan la API UIScene, lo que permite a los usuarios de iPad abrir varias instancias de tu aplicación en ventanas separadas.
En teléfonos, el sistema generalmente no distribuye dos ventanas lado a lado. En Android, crear otra ventana sigue iniciando una actividad separada, pero en pantallas de tamaño de teléfono móvil normalmente se añade a la pila de actividades posterior (back stack), por lo que presionar Atrás regresa a la actividad anterior en lugar de cerrar una división. En iOS (especialmente en iPhone), abrir o crear otra ventana a menudo reemplaza la UI actual con el contenido de la nueva escena en lugar de mantener ambas visibles a la vez; las verdaderas ventanas concurrentes siguen siendo una experiencia de iPad (y Stage Manager).
Configuración compartida
Sección titulada “Configuración compartida”Ambas plataformas requieren un permiso de capacidad para crear nuevas ventanas desde el frontend.
Capacidades
Sección titulada “Capacidades”Añade el permiso core:webview:allow-create-webview-window a tu archivo de capacidad para que tu frontend pueda crear nuevas ventanas.
Si estás creando múltiples ventanas, usa un comodín o lista cada etiqueta de ventana en el array windows:
{ "$schema": "../gen/schemas/desktop-schema.json", "identifier": "default", "description": "Capability for the main window", "windows": ["main"], "permissions": ["core:default", "core:webview:allow-create-webview-window"]}Android
Sección titulada «Android»La función multiventana en Android utiliza Activity Embedding para dividir actividades lado a lado en pantallas grandes (tabletas, plegables). Debes crear una Activity de Android para cada tipo de ventana, configurar reglas de división y registrar un inicializador.
-
Añadir dependencias
Sección titulada “Añadir dependencias”Añade las librerías de AndroidX requeridas a tu
build.gradle.kts:src-tauri/gen/android/app/build.gradle.kts dependencies {// ... existing dependenciesimplementation("androidx.window:window:1.5.0")implementation("androidx.startup:startup-runtime:1.2.0")} -
Crear una nueva Activity
Sección titulada “Crear una nueva Activity”Crea una clase Kotlin para cada tipo de ventana adicional. Cada actividad debe extender de
TauriActivity:src-tauri/gen/android/app/src/main/java/com/example/app/DetailActivity.kt package com.example.appimport android.os.Bundleimport android.os.PersistableBundleclass DetailActivity: TauriActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)}} -
Actualizar AndroidManifest.xml
Sección titulada “Actualizar AndroidManifest.xml”Registra la nueva actividad y habilita activity embedding añadiendo el espacio de nombres
toolsy la propiedad de embedding:src-tauri/gen/android/app/src/main/AndroidManifest.xml <?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"><application ...><propertyandroid:name="android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED"android:value="true" /><!-- Existing MainActivity --><activityandroid:name=".MainActivity"android:exported="true"...>...</activity><!-- New activity for the detail window --><activity android:name=".DetailActivity" android:exported="true" /><!-- Register the split initializer --><provider android:name="androidx.startup.InitializationProvider"android:authorities="${applicationId}.androidx-startup"android:exported="false"tools:node="merge"><meta-data android:name="${applicationId}.SplitInitializer"android:value="androidx.startup" /></provider></application></manifest> -
Crear el inicializador de división (Split Initializer)
Sección titulada “Crear el inicializador de división”El inicializador carga las reglas de pares divididos al iniciar la app:
src-tauri/gen/android/app/src/main/java/com/example/app/SplitInitializer.kt package com.example.appimport android.content.Contextimport androidx.startup.Initializerimport androidx.window.core.ExperimentalWindowApiimport androidx.window.embedding.RuleController@OptIn(ExperimentalWindowApi::class)class SplitInitializer : Initializer<RuleController> {override fun create(context: Context): RuleController {return RuleController.getInstance(context).apply {setRules(RuleController.parseRules(context, R.xml.main_split_config))}}override fun dependencies(): List<Class<out Initializer<*>>> {return emptyList()}} -
Definir reglas de división
Sección titulada “Definir reglas de división”Crea un recurso XML que indique al sistema cómo emparejar actividades y dividir la pantalla:
src-tauri/gen/android/app/src/main/res/xml/main_split_config.xml <resourcesxmlns:window="http://schemas.android.com/apk/res-auto"><SplitPairRulewindow:splitRatio="0.33"window:splitLayoutDirection="locale"window:splitMinWidthDp="840"window:splitMaxAspectRatioInPortrait="alwaysAllow"window:finishPrimaryWithSecondary="never"window:finishSecondaryWithPrimary="never"window:clearTop="false"><SplitPairFilterwindow:primaryActivityName=".MainActivity"window:secondaryActivityName=".DetailActivity"/></SplitPairRule></resources>Atributos clave:
splitRatio— cómo se divide la pantalla (0.33 otorga a la actividad principal un tercio)splitMinWidthDp— ancho mínimo de pantalla para activar la división (840dp apunta a tabletas)splitMaxAspectRatioInPortrait— establécelo enalwaysAllowpara permitir la división en modo retrato (vertical)primaryActivityName/secondaryActivityName— qué par de actividades activa la división
En iOS, multiventana utiliza la API UIScene. Los usuarios de iPad pueden abrir nuevas ventanas manteniendo presionado el icono de la aplicación y seleccionando "Nueva ventana", o tu aplicación puede crearlas mediante programación.
-
Habilitar soporte de escenas (Scene Support)
Sección titulada “Habilitar soporte de escenas”Crea un archivo
Info.ios.plisten tu directoriosrc-tauripara declarar el soporte de escenas:src-tauri/Info.ios.plist <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN""http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict><key>UIApplicationSceneManifest</key><dict><key>UIApplicationSupportsMultipleScenes</key><true/><key>UISceneConfigurations</key><dict/></dict></dict></plist> -
Manejar solicitudes de escenas
Sección titulada “Manejar solicitudes de escenas”Cuando un usuario solicita una nueva ventana en iPad (por ejemplo, manteniendo presionado el icono de la app), Tauri emite un evento
RunEvent::SceneRequested. Manéjalo para crear una nueva ventana:src-tauri/src/lib.rs #[cfg_attr(mobile, tauri::mobile_entry_point)]pub fn run() {#[cfg(target_os = "ios")]let mut counter = 0;tauri::Builder::default().setup(|app| {tauri::WebviewWindowBuilder::new(app, "main", tauri::WebviewUrl::default()).build()?;Ok(())}).build(tauri::generate_context!()).expect("error while running tauri application").run(move |app, event| {#[cfg(target_os = "ios")]if let tauri::RunEvent::SceneRequested { .. } = event {counter += 1;tauri::WebviewWindowBuilder::new(app,format!("main-{counter}"),tauri::WebviewUrl::default(),).build().unwrap();}#[cfg(not(target_os = "ios"))]let _ = (app, event);});}
Creación de ventanas
Sección titulada “Creación de ventanas”Puedes crear ventanas adicionales tanto desde Rust como desde la API JavaScript del frontend. El WebviewWindowBuilder (Rust) y WebviewWindow (JavaScript) aceptan opciones específicas de la plataforma:
Opciones de Android:
activityName— el nombre de la clase Activity de Android a crear para esta ventana.createdByActivityName— el nombre de la Activity que está creando esta ventana. Esto determina a qué pila de actividades pertenece la nueva actividad, lo cual es importante para que las reglas de división funcionen correctamente. Cuando no se establece, se hereda automáticamente del gestor (p. ej. al construir desde un manejador deWindowoWebview).
Opciones de iOS:
requestedBySceneIdentifier— establece el identificador de la UIScene que solicita la creación de esta nueva escena, estableciendo una relación entre ambas escenas. Por defecto, el sistema utiliza la escena en primer plano. Cuando no se establece, se hereda automáticamente del gestor.
import { WebviewWindow } from '@tauri-apps/api/webviewWindow';
function openDetail(id) { const webview = new WebviewWindow(`detail-${id}`, { url: `detail/${id}`, activityName: 'DetailActivity', }); webview.once('tauri://created', () => { console.log('window created'); }); webview.once('tauri://error', (e) => { console.error(e); });}use tauri::Manager;
let main_window = app.get_webview_window("main").unwrap();// use the main_window instance so the relationships are determined automaticallylet builder = tauri::WebviewWindowBuilder::new(main_window, "detail", tauri::WebviewUrl::App("detail/1".into()));
#[cfg(target_os = "android")]let builder = builder.activity_name("DetailActivity");
let window = builder.build()?;APIs de instancias de ventanas
Sección titulada “APIs de instancias de ventanas”Una vez que se ha creado una ventana, puedes obtener su identificador específico de la plataforma:
const activityName = await window.activityName();const sceneId = await window.sceneIdentifier();#[cfg(target_os = "android")]let activity = window.activity_name()?;
#[cfg(target_os = "ios")]let scene_id = window.scene_identifier()?;Estos getters son útiles para hacer referencia a la identidad de una ventana al crear ventanas relacionadas. Por ejemplo, puedes leer la activityName de una ventana para pasarla como createdByActivityName en una nueva ventana, o leer sceneIdentifier para pasarlo como requestedBySceneIdentifier.
© 2026 Colaboradores de Tauri. CC-BY / MIT