Cómo compilar una app para compartir fotos con Google Fotos y Flutter

Qué compilarás

En este codelab, compilaras una app de viajes, Field Trippa, que les permite a los usuarios compartir fotos.

Aprende a usar la API de la Biblioteca de Google Fotos para respaldar una experiencia de uso compartido de contenido multimedia en tu propia aplicación.

La app de este codelab se compiló con Flutter, el kit de herramientas de IU de Google diseñado para crear aplicaciones atractivas y compiladas de forma nativa que funcionen en dispositivos móviles, la Web y computadoras de escritorio a partir de una base de código única. Obtén más información en https://flutter.dev.

6571e359f222ccf6.png

Qué aprenderás

Requisitos

  • Entorno de desarrollo de Flutter
  • Dos cuentas de usuario de Google configuradas en diferentes emuladores o dispositivos que tengan acceso a Google Fotos, de modo que puedas probar el uso compartido entre los usuarios
  • Un dispositivo Android, un emulador o un dispositivo iOS físico: el simulador de iOS no es compatible por la falta de hardware de la cámara

En este codelab, compilarás una app para compartir fotos de una excursión o un viaje de estudio, que se creó con la API de la Biblioteca de Google Fotos.

El usuario ingresa mediante Acceso con Google y autoriza a que aplicación use la API de la Biblioteca de Google Fotos.

Luego, el usuario puede crear un elemento trip para subir fotos con una descripción. Cada trip puede compartirse con otros miembros de la aplicación, que también pueden contribuir con fotos.

146953eced1f4f92.png

De forma interna, cada trip se almacena como un álbum compartido en Google Fotos. La app controla el uso compartido y la carga en este álbum, pero también puedes compartirlo con otras personas que no tengan la app directamente a través de una URL de Google Fotos.

c4af82aa4bf8cc31.png

¿Qué te gustaría aprender en este codelab?

Soy nuevo en el tema y me gustaría ver una buena descripción general. Tengo algunos conocimientos sobre este tema, pero me gustaría repasarlo. Estoy buscando código de ejemplo para usar en mi proyecto. Estoy buscando una explicación sobre un tema específico.

b2f84ff91b0e1396.png Descarga el código fuente para este codelab:

Descargar código fuente Buscar en GitHub

(El código de inicio de la app está disponible en la rama main, en el repositorio).

Descomprime el archivo zip descargado. De esta manera, se crea una carpeta raíz, photos-sharing-main, que contiene todo el código y los recursos que necesitas para comenzar.

Abre la carpeta extraída en el IDE de Flutter que prefieras, como VSCode o Android Studio con los complementos de Dart y Flutter instalados.

Código final de implementación

En el siguiente vínculo, encontrarás la versión final de la aplicación que se implementó por completo. Puedes usarla si no puedes avanzar o si deseas comparar la implementación:

Descargar código fuente final Buscar código fuente final en GitHub

(El código final de la app está disponible en la rama final, en el repositorio).

Si nunca antes habías desarrollado contenido con Flutter, sigue estos pasos para configurar tu entorno de desarrollo.

Para ejecutar la app de "Field Trippa", haz clic en el botón "run" en el IDE de desarrollo o usa el siguiente comando desde el directorio raíz del código fuente:

flutter run

Deberías ver la pantalla "Connect with Google Photos":

6bfc7e3fab746b8d.png

La API de la Biblioteca de Google Fotos requiere que autentiques tus usuarios con OAuth 2.0. Los usuarios acceden a la aplicación y la autorizan para que interactúe con la API en su nombre.

Puedes encontrar algunas sugerencias adicionales para solucionar problemas al final de este paso.

Cómo crear un proyecto nuevo de Firebase y registrar tu app

b2f84ff91b0e1396.png Ve a Firebase console y selecciona "+ Agregar proyecto". Asígnale un nombre al proyecto y selecciona "Crear proyecto" para continuar. No sigas otros pasos en Firebase console. En cambio, regresa a este codelab y continúa con las partes "Android" o "iOS" que aparecen más adelante para configurar la aplicación.

Solo para Android: Si ejecutas la app en Android, registra una app para Android:

b2f84ff91b0e1396.png Haz clic en el ícono de Android a fin de abrir la pantalla de registro de la app para Android.

b2f84ff91b0e1396.png Para el paquete, introduce: com.google.codelab.photos.sharing

b2f84ff91b0e1396.png Recupera el certificado de firma SHA-1 desde tu computadora:

En Windows, ejecuta el siguiente comando:

keytool -alias androiddebugkey -keystore %USERPROFILE%\.android\debug.keystore -list -v -storepass android

En Mac o Linux, ejecuta el siguiente comando:

keytool -alias androiddebugkey -keystore ~/.android/debug.keystore -list -v -storepass android

b2f84ff91b0e1396.png Haz clic en "registrar app" para continuar.

b2f84ff91b0e1396.png Descarga el archivo google-service.json en tu computadora y muévelo al directorio "android/app/". (Sugerencia: En Android Studio, puedes arrastrar el archivo descargado directamente a la ubicación correcta en el panel lateral project).

Este archivo incluye la configuración para el proyecto de Firebase y Google Developers que configuraste recién.

(Consulta la documentación sobre package google_sign_in para obtener información).

No es necesario que completes ningún otro paso en Firebase console. El SDK de Firebase ya se agregó a la aplicación.

Solo para iOS: Si ejecutas la app en iOS, registra una app para iOS en Firebase:

b2f84ff91b0e1396.png Haz clic en el ícono de iOS a fin de abrir la pantalla de registro de la app para iOS.

b2f84ff91b0e1396.png Para el ID del paquete de iOS, introduce: com.google.codelab.photos.sharing

b2f84ff91b0e1396.png Haz clic en "siguiente" para continuar.

b2f84ff91b0e1396.png Descarga el archivo GoogleService-Info.plist a tu computadora.

b2f84ff91b0e1396.png Abre el proyecto de Flutter en Xcode

b2f84ff91b0e1396.png Haz clic con el botón derecho en el directorio Runner, selecciona "Add Files to Runner" y elige el archivo GoogleService-Info.plist que descargaste para agregarlo al módulo Runner.

b2f84ff91b0e1396.png Edita el código fuente del archivo ios/Runner/Info.plist y agrega el valor de la propiedad REVERSED_CLIENT_ID desde el archivo GoogleService-Info.plist. Reemplaza la entrada en la parte inferior del archivo:

ios/Runner/Info.plist

<!-- Google Sign-in Section -->
<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleTypeRole</key>
    <string>Editor</string>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>COPY_REVERSED_CLIENT_ID_HERE</string>
    </array>
  </dict>
</array>
<!-- End of the Google Sign-in Section -->

(Consulta la documentación sobre package google_sign_in para obtener más información).

Cómo habilitar la API de la Biblioteca de Google Fotos

b2f84ff91b0e1396.png Abre la pantalla de la API en Google Developers Console y habilita la "API de la Biblioteca de Google Fotos". (Es posible que primero debas seleccionar el proyecto de Firebase en la parte superior de la pantalla si el botón "habilitar" está inhabilitado).

b2f84ff91b0e1396.png Abre la configuración de la pantalla del consentimiento de OAuth en Google Developers Console para agregar los permisos de la API de la Biblioteca de Google Fotos y tu dirección de correo electrónico. (Esta configuración es obligatoria para que la revisión de la verificación de OAuth se realice con cualquier permiso que use la API de la Biblioteca de Google Fotos). No es necesario que envíes la verificación, pero debes completar el formulario y guardar la respuesta. De esta manera, se habilitarán los permisos para el desarrollo y las pruebas.

  • Ingresa el "Nombre de la aplicación" (por ejemplo, Field Trippa Codelab).
  • Selecciona "Support email address".
  • Selecciona "Add scope" y "manually add paste scopes" para introducir los siguientes permisos:
https://www.googleapis.com/auth/photoslibrary
https://www.googleapis.com/auth/photoslibrary.sharing
  • Selecciona "Save".
  • No es necesario enviar la verificación para continuar con este codelab. Solo es necesario cuando inicias tu aplicación, pero no para las pruebas personales.

Cómo ejecutar la app y acceder

Ya se implementó Acceso con Google mediante el paquete google_sign_in de Flutter. Este paquete requiere los archivos google-services.json o GoogleService-Info.plist que ya copiaste en el proyecto.

b2f84ff91b0e1396.png Vuelve a ejecutar la aplicación y selecciona "Connect to Google Photos". Se te pedirá que selecciones una cuenta de usuario y aceptes los permisos de autenticación.

Si todo se configuró de manera correcta, aparecerá una lista vacía en la siguiente pantalla.

9f3bcae1f8e7cd0d.png

Cómo solucionar problemas de acceso

Si tiene problemas para acceder a la aplicación, a continuación, te mostramos algunas cuestiones que puedes verificar:

b2f84ff91b0e1396.png Verifica que el dispositivo tenga conexión a Internet.

b2f84ff91b0e1396.png Si aparece el error PlatformException(sign_in_failed, com.google.android.gms.common.api.ApiException: 10: , null), asegúrate de haber seguido todos los pasos de la sección Cómo habilitar la API de la Biblioteca de Google Fotos. Debes agregar los permisos de la API de la Biblioteca de Google Fotos, ingresar una dirección de correo electrónico de asistencia y seleccionar Guardar.

b2f84ff91b0e1396.png Si aparece el error r PlatformException(sign_in_failed, com.google.android.gms.common.api.ApiException: 12500: , null), asegúrate de haber agregado una dirección de correo electrónico de asistencia en Firebase console. Abre Firebase console y navega hasta la Configuración del proyecto. Para ello, selecciona el ícono de ajustes que aparece junto al título del proyecto. Selecciona una dirección de correo electrónico en Correo electrónico de asistencia, en la pantalla Configuración general.

b2f84ff91b0e1396.png Verifica el certificado de firma SHA-1 que se configuró en Firebase console. ¿Coincide con el resultado del comando keytool en el primer paso? ¿Coincide con el resultado del comando ./gradlew signingReport cuando se ejecuta en el proyecto android/? Es posible que también debas incluir el certificado de firma SHA-256 en la consola.

b2f84ff91b0e1396.png Verifica el nombre del paquete y el ID del paquete de iOS que se configuraron en Firebase console. Debe estar configurado en com.google.codelab.photos.sharing.

b2f84ff91b0e1396.png Verifica la ubicación de los archivos de configuración que descargaste de Firebase console. En Android, el archivo debe estar copiado en android/app/google-service.json. En iOS, se debe agregar al módulo Runner.

b2f84ff91b0e1396.png Es posible que debas habilitar Google como proveedor de acceso para tu proyecto de Firebase. Abre Firebase console, navega hasta Autenticación y elige Método de acceso. Asegúrate de que Google esté habilitado.

Antes de implementar la primera llamada a la API de la Biblioteca de Google Fotos, analicemos la arquitectura de datos que utiliza la app de "Field Trippa".

Arquitectura de la app

  • Cada pantalla se implementa como una página independiente: 71b9a588fb1bbb41.png
  • El elemento PhotosLibraryApiModel describe el modelo de datos de la aplicación y abstrae las llamadas a la API de la Biblioteca de Google Fotos.
  • Las llamadas REST de HTTPS a la API de la Biblioteca se implementan en PhotosLibraryApiClient. Cada llamada que brinda esta clase toma un objeto *Request en el que se especifican los parámetros y las opciones para una llamada.
  • La API de la Biblioteca requiere que el usuario se autentique con OAuth2. El token de acceso que se necesita para incluirse en todas las llamadas a la API se configura directamente en el paquete google_sign_in, en el elemento PhotosLibraryApiClient.

Cómo implementar la llamada a la API para crear álbumes

Cada viaje se almacena como un álbum en Google Fotos. Cuando seleccionas el botón "CREATE A TRIP ALBUM", debes solicitarle al usuario el nombre del viaje y crear un álbum nuevo con este nombre.

b2f84ff91b0e1396.png En create_trip_page.dart, escribe la lógica que realiza una solicitud a la API de la Biblioteca para crear el álbum. Implementa el método _createTrip(...) al final del archivo para llamar al elemento PhotosLibraryApiModel con el nombre del viaje que introdujo el usuario.

lib/pages/create_trip_page.dart

Future<void> _createTrip(BuildContext context) async {
  // Display the loading indicator.
  setState(() => _isLoading = true);

  await ScopedModel.of<PhotosLibraryApiModel>(context)
      .createAlbum(tripNameFormController.text);

  // Hide the loading indicator.
  setState(() => _isLoading = false);
  Navigator.pop(context);
}

b2f84ff91b0e1396.png Implementa la llamada a la API de la Biblioteca que crea el álbum. En el modelo de la API, implementa el método createAlbum(...) que toma el título del álbum como parámetro. Realiza una llamada al elemento PhotosLibraryApiClient en el que se realiza la llamada REST real.

lib/model/photos_library_api_model.dart

Future<Album> createAlbum(String title) async {
  final album = await client.createAlbum(CreateAlbumRequest.fromTitle(title));
  updateAlbums();
  return album;
}

b2f84ff91b0e1396.png Implementa la llamada REST para crear el álbum en photos_library_api_client.dart. Recuerda que CreateAlbumRequest ya contiene la propiedad title que se requiere para esta llamada.

El siguiente código la codifica como JSON y agrega los encabezados de autenticación para autorizar la solicitud. Por último, muestra el álbum que creó la API.

lib/photos_library_api/photos_library_api_client.dart

Future<Album> createAlbum(CreateAlbumRequest request) async {
  final response = await http.post(
    Uri.parse('https://photoslibrary.googleapis.com/v1/albums'),
    body: jsonEncode(request),
    headers: await _authHeaders,
  );

  printError(response);

  return Album.fromJson(jsonDecode(response.body));
}

¡Pruébalo!

b2f84ff91b0e1396.png Implementa la app y selecciona "+ Create Trip".

2f0bec785bec1710.gif

Es posible que hayas notado que la lista de viajes muestra otros álbumes desde Google Fotos que no se crearon en tu app. (Si no tienes otros álbumes en Google Fotos y quieres ver este comportamiento, abre la app de Google Fotos y crea un álbum. Sin embargo, no es necesario para continuar en este codelab).

Recuerda que cada viaje se almacena como un álbum en Google Fotos. Sin embargo, no tiene sentido mostrar otros álbumes de Google Fotos que se hayan creado por otros medios. Field Trippa solo debería mostrar los viajes que se crearon en la app.

Puedes usar la API a fin de restringir la lista de viajes que aparecen en pantalla para mostrar solo los que se crean en la app.

b2f84ff91b0e1396.png Modifica el método listAlbums() (¡NO listSharedAlbums()!) en photos_library_api_client.dart. Este método realiza la llamada de REST para recuperar una lista de álbumes. Agrega el parámetro excludeNonAppCreatedData=true que restringe los datos que se muestran para excluir los álbumes que no se crearon en esta app.

lib/photos_library_api/photos_library_api_client.dart

Future<ListAlbumsResponse> listAlbums() async {
  final response = await http.get(
        Uri.parse('https://photoslibrary.googleapis.com/v1/albums?'
            'pageSize=50&excludeNonAppCreatedData=true'),
        headers: await _authHeaders);

       ...
}

¡Pruébalo!

En la primera página, solo se muestran los viajes que se crearon en la app.

c7c20b76dcbfbfea.png

El siguiente paso consiste en subir fotos a un viaje. Los datos se almacenan en la cuenta de Google Fotos de tu usuario, por lo que no tienes que preocuparte por el almacenamiento ni el procesamiento de los datos.

Cómo tomar una foto en Flutter

b2f84ff91b0e1396.png Primero, implementa el método _getImage(...) en el diálogo para contribuir fotos. Se llama a este método cuando el usuario hace clic en el botón "+ ADD PHOTO".

El siguiente código usa el paquete image_picker para tomar una foto, actualizar la IU y llamar al modelo de la API a fin de subir la imagen. (Lo implementarás en el siguiente paso). La llamada _getImage(...) almacena un token de carga que se necesita más adelante para crear la foto en Google Fotos.

lib/components/contribute_photo_dialog.dart

Future _getImage(BuildContext context) async {
  // Use the image_picker package to prompt the user for a photo from their
  // device.
  final pickedImage = await _imagePicker
      .getImage(
        source: ImageSource.camera,
      );
  final pickedFile = File(pickedImage.path);

  // Store the image that was selected.
  setState(() {
    _image = pickedFile;
    _isUploading = true;
  });

  // Make a request to upload the image to Google Photos once it was selected.
  final uploadToken = await ScopedModel.of<PhotosLibraryApiModel>(context)
      .uploadMediaItem(pickedFile);

  setState(() {
    // Once the upload process has completed, store the upload token.
    // This token is used together with the description to create the media
    // item later.
    _uploadToken = uploadToken;
    _isUploading = false;
  });
}

Cómo implementar llamadas a la API de la Biblioteca para subir la imagen a fin de obtener un token de carga

La carga de fotos y videos a la API de la Biblioteca se realiza en dos pasos:

  1. Sube los bytes de contenido multimedia para recibir un token de carga
  2. Crea un elemento multimedia en la biblioteca del usuario a partir del token de carga.

b2f84ff91b0e1396.png Implementa la solicitud de REST para subir contenido multimedia. Debes configurar algunos encabezados para especificar el tipo de solicitud de carga y el nombre de archivo. En el archivo photos_library_api_client.dart, implementa el método uploadMediaItem(...) en el que se sube el archivo, lo que muestra el token de carga que obtiene la llamada HTTP:

lib/photos_library_api/photos_library_api_client.dart

Future<String> uploadMediaItem(File image) async {
  // Get the filename of the image
  final filename = path.basename(image.path);

  // Set up the headers required for this request.
  final headers = <String, String>{};
  headers.addAll(await _authHeaders);
  headers['Content-type'] = 'application/octet-stream';
  headers['X-Goog-Upload-Protocol'] = 'raw';
  headers['X-Goog-Upload-File-Name'] = filename;

  // Make the HTTP request to upload the image. The file is sent in the body.
  final response = await http.post(
    Uri.parse('https://photoslibrary.googleapis.com/v1/uploads'),
    body: image.readAsBytesSync(),
    headers: await _authHeaders,
  );

  printError(response);

  return response.body;
}

Cómo crear un elemento multimedia a partir de un token de carga

A continuación, implementarás la creación de un elemento multimedia en la biblioteca del usuario a partir del token de carga.

Para crear un elemento multimedia, se requieren el token de carga, una descripción opcional (por ejemplo, la leyenda de la foto o el video) y el identificador opcional de un álbum. Field Trippa siempre agrega la foto subida directamente a un álbum de viajes.

b2f84ff91b0e1396.png Implementa la llamada al elemento photos_library_api_client que llama a mediaItems.batchCreate con el token de carga, la descripción y el ID del álbum. En el modelo de la API, implementa el método createMediaItem(...) que llama a la API de la Biblioteca. Este método muestra un elemento multimedia.

(Ya está implementado el elemento photos_library_client para esta llamada).

lib/model/photos_library_api_model.dart

Future<BatchCreateMediaItemsResponse> createMediaItem(
    String uploadToken, String albumId, String description) async {
  // Construct the request with the token, albumId and description.
  final request =
      BatchCreateMediaItemsRequest.inAlbum(uploadToken, albumId, description);

  // Make the API call to create the media item. The response contains a
  // media item.
  final response = await client.batchCreateMediaItems(request);

  // Print and return the response.
  print(response.newMediaItemResults[0].toJson());
  return response;
}

Pruébalo.

b2f84ff91b0e1396.png Abre la app y selecciona un viaje. Haz clic en contribute y selecciona una foto que ya hayas tomado. Introduce una descripción y selecciona upload. La imagen debería aparecer en el viaje después de unos segundos.

b2f84ff91b0e1396.png Abre el álbum en la app de Google Fotos. Verás la imagen nueva en el álbum de este viaje.

526ede994fcd5d8d.gif

Hasta ahora, implementaste la funcionalidad para crear un viaje y subir fotos con una descripción. En el backend, cada viaje se almacena como un álbum en Google Fotos.

A continuación, compartirás un viaje con otras personas que no usen tu aplicación.

Cada viaje está respaldado por un álbum de Google Fotos. Por lo tanto, puedes "compartir" un álbum a través de una URL y permitir que esté disponible para cualquier persona que tenga esta URL.

Cómo implementar la llamada para compartir un álbum

Los álbumes se comparten desde la página del viaje cuando se presiona el botón share en la parte superior del álbum.

b2f84ff91b0e1396.png Implementa la llamada asíncrona _shareAlbum(...) que llama al modelo para compartir el álbum y vuelve a cargar el álbum que se muestra. Cuando vuelves a cargar el álbum, se propaga la propiedad shareInfo, que contiene el elemento shareableUrl que le mostrarás al usuario en un diálogo más adelante.

lib/pages/trip_page.dart

Future<void> _shareAlbum(BuildContext context) async {
  // Show the loading indicator
  setState(() => _inSharingApiCall = true);

  const snackBar = SnackBar(
    duration: Duration(seconds: 3),
    content: Text('Sharing Album...'),
  );
  Scaffold.of(context).showSnackBar(snackBar);

  // Share the album and update the local model
  await ScopedModel.of<PhotosLibraryApiModel>(context).shareAlbum(album.id);
  final updatedAlbum =
      await ScopedModel.of<PhotosLibraryApiModel>(context).getAlbum(album.id);

  print('Album has been shared.');
  setState(() {
    album = updatedAlbum;
    // Hide the loading indicator
    _inSharingApiCall = false;
  });
}

b2f84ff91b0e1396.png Implementa el método _showShareableUrl(...) al que se llama cuando el usuario hace clic en el botón "SHARE WITH ANYONE" en la parte superior de la página. En primer lugar, verifica si el álbum ya se compartió y llama al método _showUrlDialog(...) una vez que se haya compartido.

lib/pages/trip_page.dart

Future<void> _showShareableUrl(BuildContext context) async {
  if (album.shareInfo == null || album.shareInfo.shareableUrl == null) {
    print('Not shared, sharing album first.');
    // Album is not shared yet, share it first, then display dialog
    await _shareAlbum(context);
    _showUrlDialog(context);
  } else {
    // Album is already shared, display dialog with URL
    _showUrlDialog(context);
  }
}

b2f84ff91b0e1396.png Implementa el método _showUrlDialog(...) que muestra el elemento shareableUrl en un diálogo.

lib/pages/trip_page.dart

void _showUrlDialog(BuildContext context) {
  print('This is the shareableUrl:\n${album.shareInfo.shareableUrl}');

  _showShareDialog(
      context,
      'Share this URL with anyone. '
      'Anyone with this URL can access all items.',
      album.shareInfo.shareableUrl);
}

¡Pruébalo!

La app solo muestra los viajes que no se compartieron todavía en la pantalla principal. No te preocupes, ya que los implementaremos en el siguiente paso. Por el momento, solo puedes crear un viaje nuevo si sales de la pantalla.

b2f84ff91b0e1396.png Abre la app y selecciona un viaje. Selecciona "SHARE WITH ANYONE" en la parte superior de la pantalla y abre en tu navegador la URL que se muestra. (Sugerencia: La URL también se muestra en el registro para que puedas copiarla con facilidad en tu computadora). En Android Studio, el registro se muestra en la pestaña "Run").

1d1a40c1078e4221.gif

En Google Fotos, los álbumes se pueden compartir mediante una URL a la que pueden acceder todas las personas que la tengan. A través de la API de la Biblioteca, también puedes compartir álbumes mediante tokens para compartir. Un token para compartir es una string que se utiliza en tu aplicación a fin de unir usuarios a un álbum compartido a través de la API.

El proceso para compartir un álbum con tu aplicación a través de la API de la Biblioteca es el siguiente:

  1. El usuario A accede a tu aplicación y autoriza la API de la Biblioteca.
  2. Crea el álbum.
  3. Comparte el álbum con su identificador.
  4. Transfiere el token para compartir a otro usuario.

El proceso para unirse es similar:

  1. El usuario B accede a tu aplicación y autoriza la API de la Biblioteca.
  2. Recupera el token para compartir del álbum al que debe unirse el usuario.
  3. Se une al álbum con el token para compartir.

Los álbumes compartidos aparecen en Google Fotos, en la pestaña "Compartidos".

Cómo mostrar el token para compartir

En el paso anterior, implementaste el método _shareAlbum(...) que comparte un álbum. La propiedad shareInfo también contiene el "token para compartir" que se mostrará en la pantalla.

b2f84ff91b0e1396.png En la página del viaje, implementa el método _showShareToken(...) al que se llama cuando el usuario presiona el botón "SHARE WITH FIELD TRIPPA" en la pantalla.

lib/pages/trip_page.dart

Future<void> _showShareToken(BuildContext context) async {
  if (album.shareInfo == null) {
    print('Not shared, sharing album first.');
    // Album is not shared yet, share it first, then display dialog
    await _shareAlbum(context);
    _showTokenDialog(context);
  } else {
    // Album is already shared, display dialog with token
    _showTokenDialog(context);
  }
}

Luego, implementa la visualización del "token para compartir" en el método _showTokenDialog(...). El token forma parte de la propiedad shareInfo de un álbum.

lib/pages/trip_page.dart

void _showTokenDialog(BuildContext context) {
  print('This is the shareToken:\n${album.shareInfo.shareToken}');
  _showShareDialog(
      context, 'Use this token to share', album.shareInfo.shareToken);
}

Cómo enumerar álbumes compartidos

Por el momento, la aplicación solo enumera los álbumes que son propiedad del usuario, pero no los álbumes compartidos.

En la pantalla "Álbumes" de la app de Google Fotos, solo se muestran los álbumes que el usuario creó o agregó, de manera explícita, a su biblioteca de Google Fotos. Solo estos álbumes se muestran cuando se llama a albums.list en la API de la Biblioteca. Sin embargo, en nuestra app, el usuario puede unirse a los álbumes compartidos de otros usuarios, que solo se muestran en la llamada para enumerar álbumes compartidos. Debes cambiar la manera en que se recuperan las listas de viajes (álbumes) de la API de la Biblioteca para incluir álbumes que sean propiedad del usuario y compartidos.

b2f84ff91b0e1396.png Los álbumes se cargan y se almacenan en caché en el modelo de la API. Cambia la implementación de updateAlbums() en el modelo para cargar álbumes y álbumes compartidos antes de almacenarlos como una lista.

Esta implementación usa varios objetos Future para enumerar los álbumes de forma asíncrona antes de combinarlos en la lista de álbumes almacenados en caché. Borra la implementación anterior y marca como comentario el código nuevo.

lib/model/photos_library_api_model.dart

void updateAlbums() async {
  // Reset the flag before loading new albums
  hasAlbums = false;
  // Clear all albums
  _albums.clear();
  // Skip if not signed in
  if (!isLoggedIn()) {
    return;
  }
  // Add albums from the user's Google Photos account
  // var ownedAlbums = await _loadAlbums();
  // if (ownedAlbums != null) {
  //   _albums.addAll(ownedAlbums);
  // }

  // Load albums from owned and shared albums
  final list = await Future.wait([_loadSharedAlbums(), _loadAlbums()]);

  _albums.addAll(list.expand((a) => a ?? []));

  notifyListeners();
  hasAlbums = true;
}

Cómo unirse a un álbum compartido

Puedes unir usuarios de tu aplicación a un álbum a través del token para compartir. En este codelab, se puede lograr mediante un diálogo de texto simple.

b2f84ff91b0e1396.png Implementa el método _joinTrip en la página para unirse al viaje que llama al modelo de la API con el token para compartir que introdujo el usuario. Primero, muestra el indicador de carga y realiza la llamada para unir el álbum compartido con la entrada del formulario de texto, antes de ocultar el indicador de carga y volver a la pantalla anterior.

lib/pages/join_trip_page.dart

Future<void> _joinTrip(BuildContext context) async {
  // Show loading indicator
  setState(() => _isLoading = true);

  // Call the API to join an album with the entered share token
  await ScopedModel.of<PhotosLibraryApiModel>(context)
      .joinSharedAlbum(shareTokenFormController.text);

  // Hide loading indicator
  setState(() => _isLoading = false);

  // Return to the previous screen
  Navigator.pop(context);
}

¡Pruébalo!

Necesitas un segundo dispositivo o emulador con otra cuenta de usuario para probar esta parte del codelab.

b2f84ff91b0e1396.png Crea y comparte un viaje en un mismo usuario, y selecciona la opción "SHARE IN FIELD TRIPPA" a fin de recuperar el token para compartir. Copia este token para compartir en el otro dispositivo o emulador, e introdúcelo mediante la opción "JOIN A TRIP ALBUM" en la página principal. (Sugerencia: Se comparte el portapapeles entre tus emuladores y tu computadora host).

8043086cc00eaa16.gif 55c1e75014d4d2a4.gif

Sugerencias sobre la implementación real

Cuando implementes el uso compartido en una aplicación real (en lugar de en un codelab), debes pensar con cuidado la manera en la que puedes usar los tokens para compartir a fin de unir usuarios a los álbumes. Considera la idea de almacenarlos en tu backend seguro y usar tus relaciones entre usuarios para crear álbumes y unirse a estos.

Por ejemplo, una aplicación para reuniones en un club de fútbol puede realizar un seguimiento de los asistentes a eventos programados específicos y solo unir los asistentes al álbum después de solicitárselos.

Antes de realizar cambios en la cuenta de Google Fotos de los usuarios, es importante notificárselos y solicitar su consentimiento. Para obtener más información, consulta los lineamientos sobre la UX de la API de la Biblioteca de Google Fotos.

Qué compilaste

  • Implementaste la funcionalidad de uso compartido en tu aplicación, que respalda Google Fotos.
  • Creaste tus propias experiencias para el uso compartido de fotos y videos en la parte superior de la API de la Biblioteca de Google Fotos, sin tener que preocuparte por la infraestructura ni el almacenamiento.
  • Usaste la funcionalidad de uso compartido que forma parte de la API de maneras interesantes y novedosas para compartir contenido directamente con tus usuarios.
  • Usaste algunas partes clave de la API de la Biblioteca:
  • Creaste álbumes nuevos y subiste fotos nuevas.
  • Enumeraste álbumes compartidos, que se limitan a los álbumes que se crearon en tu aplicación

Próximos pasos

Consulta la documentación para desarrolladores de las API de Google Fotos en https://developers.google.com/photos si deseas obtener más información sobre cómo compartir contenido multimedia y otras partes de la API de la Biblioteca. Por ejemplo, filtros inteligentes de contenido con tecnología de aprendizaje automático que te permiten encontrar las fotos y los videos correctos.

Cuando tengas todo listo para iniciar la integración, únete al Programa de Partners de Google Fotos.

Recuerda consultar los lineamientos sobre la UX y las prácticas técnicas recomendadas. A fin de ayudarte a comenzar, las bibliotecas cliente también están disponibles para algunos lenguajes.