vivienda_webview_sdk
SDK Flutter para integrar el flujo embebido de Vivienda IA mediante una WebView.
Inyecta configuración de sesión por el bridge y expone eventos vivienda:* como
callbacks Dart. No incluye el frontend, el backend ni credenciales de acceso.
Instalación
dependencies:
vivienda_webview_sdk: ^0.2.1
Ejecuta flutter pub get. Requiere Dart 3.5+ y Flutter 3.24+, de acuerdo
con la dependencia Android existente. La selección de archivos descrita aquí es
para Android. El paquete usa webview_flutter y dart:io: no implementa Flutter
Web ni escritorio. La selección y subida en iOS deben validarse con WKWebView.
Integración básica
Importa únicamente la biblioteca pública:
import 'package:flutter/material.dart';
import 'package:vivienda_webview_sdk/vivienda_webview_sdk.dart';
Widget buildVivienda({
required String webUrl,
required String baseUrl,
required String embedSessionToken,
required VoidCallback onClosed,
ViviendaFileSelector? fileSelector,
}) {
return ViviendaWebViewSdk(
webUrl: webUrl,
baseUrl: baseUrl,
embedSessionToken: embedSessionToken,
mode: ViviendaMode.create,
initialStep: ViviendaInitialStep.client,
showDevLogs: false,
fileSelector: fileSelector,
onReady: () {},
onProjectCreated: (event) {
// Usar event.projectId para continuar el flujo de la aplicación.
},
onError: (event) {
// Presentar event.message; registrar únicamente event.code si hace falta.
},
onClosed: onClosed,
);
}
El host obtiene una sesión válida mediante su integración autorizada y entrega las URLs y el token al widget. Nunca incluyas credenciales reales en código, repositorios, ejemplos públicos o logs. Una configuración embebida en un APK no es almacenamiento seguro de secretos.
También puedes resolver URLs por environmentKey/environmentRegistry.
Los parámetros directos (webUrl, baseUrl, allowedOrigins) tienen prioridad.
QA_IT y LOCAL_ANDROID_DEBUG contienen placeholders que debes reemplazar.
Si no se resuelve webUrl, el widget muestra un error de configuración.
La opción autoRequestEmbedSession: true solicita la sesión antes de cargar la
WebView cuando no se entrega embedSessionToken. Requiere baseUrl, sdkToken
y una identidad admitida por el backend (employeeCode, gformCode,
codPromotor o promoterId, según el contrato de tu despliegue). Gestiona estos
valores desde el host; no son datos de ejemplo proporcionados por el paquete.
Archivos en Android / AppSIP
El SDK crea su WebViewController y registra
AndroidWebViewController.setOnShowFileSelector antes de cargar la página.
La aplicación debe conectar fileSelector para abrir el selector nativo.
Actualizar la dependencia sin configurar ese callback no habilita la carga.
API pública:
Future<List<String>> seleccionarArchivos(ViviendaFileSelectorParams params);
acceptTypes: MIME types/extensiones del input, normalizados y sin duplicados.allowMultiple: respetar si el input permite varios archivos.isCaptureEnabled: sugerencia de captura; no activa cámara ni permisos por sí sola.
Usa un selector de la aplicación, por ejemplo file_picker como en
example/lib/main.dart. El ejemplo adapta las pistas
del input y admite PNG, JPG/JPEG, WebP y PDF. El SDK no impone por sí mismo una
lista de extensiones, valida contenido ni limita bytes: el host, el formulario
web y la API deben aplicar sus restricciones de tipo y tamaño.
El callback debe devolver URIs locales accesibles por la WebView:
// Con una ruta local obtenida del selector:
return [Uri.file(path).toString()];
// Si el selector proporciona una URI de documento con acceso vigente:
return [contentUri];
// Solo cuando el usuario cancela:
return const <String>[];
Solo se aceptan esquemas file: y content: con una ruta no vacía. No devuelvas
URLs HTTP, rutas sin URI ni varios archivos para un input de selección única.
La validación del SDK comprueba la forma de la URI, no la existencia o el permiso
de lectura; el host debe mantener el archivo/acceso durante la subida.
No conviertas un fallo del selector en []: lanza una excepción para que el SDK
pueda informar el error. El SDK deduplica las URIs seleccionadas. En una
cancelación voluntaria devuelve una lista vacía sin emitir error.
Errores del selector
Los errores se reciben mediante onError como ViviendaErrorEvent:
| Código | Significado |
|---|---|
FILE_SELECTOR_MISSING |
El host no configuró fileSelector. |
FILE_SELECTOR_INVALID_RESULT |
URI no local/vacía o selección múltiple no permitida. |
FILE_SELECTOR_FAILED |
El callback lanzó otro error. |
En esos fallos el SDK devuelve [] al callback Android y notifica a la página
con vivienda:file-selection-failed; no los trata como una cancelación exitosa.
Los logs propios del selector no incluyen nombres, rutas ni contenido de archivos.
Si AppSIP utiliza una WebView propia en lugar de ViviendaWebViewSdk, debe
registrar su propio file chooser: este widget no puede configurar otro controller.
Consulta la guía de integración y aceptación.
Configuración Android
Declara acceso a Internet en android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
Prefiere HTTPS. Usar el selector de documentos del sistema no justifica añadir
MANAGE_EXTERNAL_STORAGE ni permisos generales de almacenamiento. Captura con
cámara requiere una implementación y permisos propios del host; el ejemplo no
la implementa.
Descargas PDF y eventos
El SDK recibe vivienda:download-requested y maneja bytes inline o descarga HTTP.
Además de PDF, el downloader admite PNG, JPEG, WebP y SVG, comprueba firmas
básicas y solo envía el token de sesión a URLs del mismo origen que baseUrl.
Los fallos de descarga de imágenes usan códigos FILE_*, no PDF_*.
El host puede inyectar pdfSaver y debe proporcionar pdfOpener si quiere abrir
el PDF; sin visor el SDK informa PDF_NO_VIEWER. El ejemplo usa dart:io para
guardar y open_filex para abrir. Están disponibles onDownloadRequested,
onDownloadCompleted y onDownloadError.
Desde 0.2.1, success significa que el archivo
se guardó; opened informa si el host aceptó solicitar su apertura, sin
certificar que el visor lo renderizó. Sin visor o si
éste falla, se llama onDownloadCompleted con opened: false y una advertencia
PDF_NO_VIEWER/FILE_NO_VIEWER o *_OPEN_FAILED. Sólo fallos de obtención,
validación o guardado llaman onDownloadError. El evento web de finalización
incluye saved, opened, fileName y, si corresponde, code/message, nunca
la ruta privada. El host debe ofrecer acceso al archivo guardado: el ejemplo
incluye «Guardar copia» mediante el selector del sistema, sin permisos amplios.
Su apertura usa el MIME de cada extensión, no application/pdf para imágenes.
En 0.2.0, esos avisos de apertura se entregaban como error aunque el archivo
estuviera guardado. No cambian las firmas públicas ni los mínimos de Flutter/Dart.
Consulta la guía AppSIP 0.2.1 para conectar los callbacks,
conservar acceso al archivo y generar el APK de integración.
onEvent entrega eventos genéricos. onReady, onRuntimeApplied,
onClientLoaded, onProjectCreated, onError y onClosed permiten conectar el
flujo de la aplicación. Mantén showDevLogs: false en producción y no registres
payloads sin revisar datos personales y tokens.
Migración desde 0.1.0
Los argumentos existentes del widget se conservan; fileSelector es opcional
para construir el widget, pero necesario para cargar archivos en Android.
Actualiza Flutter a 3.24+ / Dart a 3.5+ si tu toolchain es anterior. El perfil
LOCAL_ANDROID_DEBUG ya no incluye una IP local: configura tus URLs mediante
parámetros directos o tu propio registro. 0.1.1 fue un hito local no publicado;
sus correcciones están incluidas en 0.2.0.
Ejemplo y validación
La aplicación de example/ incluye selector, configuración
de sesión y callbacks PDF. Sus URLs de desarrollo son placeholders y no contiene
usuarios ni credenciales de prueba. Las pruebas automatizadas del paquete no
sustituyen la aceptación nativa: probar selección, cancelación, rechazo de
archivos y retorno a la app en un dispositivo Android con sesión autorizada.
Licencia
MIT. Consulta LICENSE.
Libraries
- vivienda_webview_sdk
- Vivienda IA · WebView SDK (wrapper Flutter).