Cuando se trata de aplicaciones móviles, me plantean una serie de preguntas concretas: la primera es cómo guardar las imágenes capturadas, y la segunda, cómo sincronizarlas entre dispositivos o con una base de datos remota. Como soy un gran fan de NativeScript para el desarrollo de Android e iOS, pensé que sería genial compartir uno de los muchos ejemplos posibles para resolver este problema.
Vamos a ver cómo capturar imágenes en una aplicación NativeScript utilizando Angular y guardar esas imágenes capturadas en Couchbase Lite, una base de datos integrada a nivel de dispositivo.
En adelante, es importante tener en cuenta que hay muchas maneras de guardar imágenes o cualquier otro dato de archivo dentro de una aplicación móvil. Por ejemplo, puedes guardarlos en una base de datos o en el sistema de archivos. En este ejemplo vamos a guardarlos directamente en la base de datos, pero investiga qué estrategia te funcionará mejor.
En la imagen animada anterior se nos presenta la posibilidad de capturar imágenes. Las cosas son un poco diferentes en un simulador, pero en un dispositivo la cámara se abrirá. Después de capturar una imagen se presentará en la pantalla y se guardará en Couchbase Lite como una cadena con formato base64.
Requisitos
No hay muchos requisitos para tener éxito con esta guía. Como mínimo necesitarás lo siguiente:
- NativeScript CLI
- Android SDK para Android y Xcode para iOS
Para poder construir para Android necesitarás el SDK de Android y para poder construir para iOS necesitarás Xcode, que solo está disponible en ordenadores macOS. Para esta guía en particular, no es necesaria una instancia remota de Couchbase Server.
Creación de un nuevo proyecto NativeScript con Angular
Con los prerrequisitos instalados y listos para funcionar, necesitamos crear un nuevo proyecto en algún lugar de nuestro ordenador.
Desde la CLI de NativeScript, ejecute lo siguiente:
1 |
tns create foto-proyecto --ng |
El comando anterior creará un nuevo proyecto Angular, por lo tanto el comando --ng
bandera.
Antes de empezar a desarrollar, necesitaremos instalar el plugin de Couchbase para NativeScript. Esto se puede hacer ejecutando lo siguiente:
1 |
tns plugin add nativescript-couchbase |
Aunque técnicamente podemos empezar a desarrollar la aplicación, hay un asunto más del que ocuparse. En iOS es un requisito explicar cada uno de los permisos que se utilizan. Poder hacer fotos o usar la galería es una petición de permiso, así que tenemos que explicarlo.
Abra el archivo app/App_Resources/iOS/Info.plist e incluya lo siguiente:
1 2 |
NSPhotoLibraryUsageDescription Aviso de acceso a la fototeca |
Lo anterior evitará cualquier error durante el tiempo de compilación o de ejecución. Ahora podemos empezar a desarrollar con seguridad nuestra aplicación móvil para Android e iOS.
Desarrollo de la lógica central de la aplicación y de la interfaz de usuario
Antes de empezar a añadir nuestro propio código, vamos a despojarnos de un montón de código de plantilla que se incluye al crear un nuevo proyecto NativeScript con Angular.
Esto va a ser una aplicación de una sola página por lo que necesitamos eliminar cualquiera de las rutas de navegación preexistentes. Comience por abrir el proyecto app/app.routing.ts y que tenga el siguiente aspecto:
1 2 3 4 5 6 7 8 9 10 11 |
import { NgModule } from "@angular/core"; import { NativeScriptRouterModule } from "nativescript-angular/router"; import { Rutas } from "@angular/router"; const rutas: Rutas = []; @NgModule({ importaciones: [NativeScriptRouterModule.forRoot(routes)], exportaciones: [NativeScriptRouterModule] }) export class AppRoutingModule { } |
Lo único que hicimos fue eliminar las rutas del rutas
array. Técnicamente podemos eliminar este archivo, pero es más fácil quitar lo que no vamos a utilizar.
Ahora abra el proyecto app/app.module.ts y hacer que el TypeScript se parezca a lo siguiente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import { NgModule, NO_ERRORS_SCHEMA } from "@angular/core"; import { NativeScriptModule } from "nativescript-angular/nativescript.module"; import { AppRoutingModule } from "./app.routing"; import { AppComponent } from "./app.component"; @NgModule({ bootstrap: [ AppComponent ], importaciones: [ Módulo NativeScript, AppRoutingModule ], declaraciones: [ AppComponent ], proveedores: [], esquemas: [ NO_ERRORS_SCHEMA ] }) export class AppModule { } |
Fíjate que en lo anterior hemos eliminado cualquier referencia a los archivos MVC que antes eran rutas. Esto incluye HTML, TypeScript y el servicio Angular que se proporcionó.
A la hora de añadir nuevo contenido, vamos a centrarnos primero en la lógica TypeScript, para pasar después a la interfaz de usuario HTML. Abra el proyecto app/app.component.ts e incluya lo siguiente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
import { Component, OnInit } from "@angular/core"; import { Couchbase } from "nativescript-couchbase"; import * as Cámara from "cámara"; import * as ImageSource from "fuente-de-imagen"; @Componente({ selector: "ns-app", templateUrl: "app.component.html", }) export class AppComponent implements OnInit { base de datos pública: cualquiera; imágenes públicas: Array; public constructor() { this.database = new Couchbase("base-de-imágenes"); this.database.createView("images", "1", function(document, emitter) { if(document.type && document.type == "image") { emitter.emit(document._id, document); } }); this.images = []; } public ngOnInit() { let rows = this.database.executeQuery("images"); for(let i = 0; i < longitud.filas; i++) { this.images.push(ImageSource.fromBase64(filas[i].imagen)); } } public captura() { Camera.takePicture({ anchura: 300, altura: 300, keepAspectRatio: true, saveToGallery: false }).then(picture => { let base64 = picture.toBase64String("png", 70); this.database.createDocument({ "tipo": "imagen", "imagen": base64, "timestamp": (new Date()).getTime() }); this.images.push(picture); }, error => { console.dump(error); }); } } |
En el código anterior ocurren muchas cosas, así que vamos a desglosarlo.
Habíamos descargado previamente el plugin de Couchbase para NativeScript, pero ahora necesitamos importarlo junto con otras cosas:
1 2 3 |
import { Couchbase } from "nativescript-couchbase"; import * as Cámara from "cámara"; import * as ImageSource from "fuente-de-imagen"; |
La funcionalidad de la cámara ya está incluida en NativeScript, sólo tenemos que importarla. Cuando se trata de manipular los datos de la cámara, la función Fuente de imágenes
es lo que usaremos.
Dentro del AppComponent
tenemos dos variables:
1 2 |
base de datos privada: cualquiera; imágenes públicas: Array; |
En base de datos
contendrá nuestra instancia abierta de Couchbase Lite y el archivo imágenes
contendrá todas las imágenes guardadas que se presentarán en la pantalla.
Dentro del constructor
abrimos nuestra base de datos, creamos una vista que más tarde podremos consultar, e inicializamos el array que almacenará nuestras imágenes.
1 2 3 4 5 6 7 8 9 |
public constructor() { this.database = new Couchbase("base-de-imágenes"); this.database.createView("images", "1", function(document, emitter) { if(document.type && document.type == "image") { emitter.emit(document._id, document); } }); this.images = []; } |
La vista que estamos creando devolverá todos los documentos NoSQL que tengan una propiedad llamada tipo
que se establece en imagen
que nos representa que es una de las imágenes posibles para mostrar en la pantalla.
Porque los datos nunca deben cargarse en el constructor
llevamos las cosas al método ngOnInit
método:
1 2 3 4 5 6 |
public ngOnInit() { let rows = this.database.executeQuery("images"); for(let i = 0; i < longitud.filas; i++) { this.images.push(ImageSource.fromBase64(filas[i].imagen)); } } |
En ngOnInit
se activa después de que constructor
y consultará la vista previamente creada. Cada documento guardado tendrá una propiedad llamada imagen
que contiene datos de imagen en base64. Este modelo se basa en nuestro diseño.
Tras obtener los datos en base64 se convierten en un Fuente de imágenes
y se añade a nuestra matriz para que aparezca en la pantalla.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public captura() { Camera.takePicture({ anchura: 300, altura: 300, keepAspectRatio: true, saveToGallery: false }).then(picture => { let base64 = picture.toBase64String("png", 70); this.database.createDocument({ "tipo": "imagen", "imagen": base64, "timestamp": (new Date()).getTime() }); this.images.push(picture); }, error => { console.dump(error); }); } |
Lo anterior captura
es llamado a través de la pulsación de un botón en nuestro HTML. Lanzará la cámara con algunos ajustes definidos.
Si la captura se realiza correctamente, la imagen se convertirá a base64 y se creará un documento NoSQL con información diversa junto a los datos base64.
No está tan mal, ¿verdad?
Ahora queremos echar un vistazo al código HTML que acompaña a esta lógica. Abra el proyecto app/app.component.html e incluya lo siguiente:
1 2 3 4 5 6 |
<ActionBar title="{N} Couchbase Photos"> <ActionItem text="Capture" ios.position="right" (tap)="capture()"></ActionItem> </ActionBar> <StackLayout> <Image *ngFor="let image of images" [src]="image"></Image> </StackLayout> |
En el HTML anterior tenemos una barra de acción con un botón que activará la cámara. Dentro del contenido central de la página tenemos un bucle que recorrerá cada imagen del array y la mostrará en pantalla.
Conclusión
Acabas de ver cómo crear una aplicación básica de captura de imágenes con NativeScript y Angular que guarda los datos de las imágenes directamente en documentos NoSQL de Couchbase Lite como cadenas codificadas en base64. La próxima vez vamos a ver cómo sincronizar estos datos de imagen entre dispositivos y una instancia de base de datos remota.
Mientras tanto, echa un vistazo a este otro tutorial sobre el uso de NativeScript con Couchbase titulado, Operaciones clave-valor en Couchbase Mobile mediante NativeScript y Angular.
¿Quieres más ayuda con Couchbase para Android e iOS? Echa un vistazo a la Portal para desarrolladores de Couchbase para consultar documentación y ejemplos.
Gracias por el tutorial. Encontrado que para NS3.0, la importación de la cámara debe ser de "nativescript-cámara".
Sí, pero lo bueno es que es sólo un cambio menor :-)
Hola, acabo de probar este código (estoy intentando guardar imágenes en Couchbase como Base64 y luego recuperarlas), y me estoy encontrando con el mismo problema con esta aplicación de ejemplo que con la aplicación que estoy construyendo:
En la función capture(), no puedo utilizar let base64=picture.toBase64String("png", 70) porque "Property 'toBase64String' does not exist on type 'ImageAsset'". Si ejecuto picture a través de ImageSource.fromAsset(picture).then(...), puedo entonces aplicar .toBase64String, pero no soy capaz de restaurar con éxito usando .fromBase64.
Estoy totalmente perdido y espero que pueda ayudarme.