Démarrer avec AWS

Créer une application Flutter

Créer une application Flutter simple avec AWS Amplify

Module 4 : Ajout de la capacité de stocker des images

Dans ce module, vous apprendrez à augmenter la capacité de stockage et à associer une image avec les notes dans votre application.

Introduction

À présent que seuls les utilisateurs authentifiés peuvent accéder à l'application, nous pouvons autoriser l'utilisateur à prendre des photos et à les charger dans un dossier privé du compartiment Amazon S3 de notre application.

Dans ce module, nous allons ajouter la catégorie Storage à l'application Amplify, charger des images provenant de l'appareil photo de l'appareil, puis télécharger et afficher toutes les photos associées à un utilisateur individuel.

Ce que vous apprendrez

  • Configuration de la catégorie Storage
  • Chargement de fichiers dans Amazon S3
  • Téléchargement de fichiers depuis Amazon S3
  • Affichage et placement des images en cache depuis une URL

Concepts clés

Storage - Le concept de Storage consiste à être en mesure de stocker des fichiers sur un emplacement et de les récupérer si nécessaire. Dans ce cas, nous allons stocker des images sur Amazon S3 et en télécharger.

 Durée

20 minutes

 Services utilisés

Implémentation

  • Création du service Storage

    Ajoutez le service Storage à votre projet Amplify en exécutant la commande suivante dans le terminal se trouvant dans le répertoire principal de votre projet :

    amplify add storage

    Tout comme les autres catégories, l'interface de ligne de commande Amplify va vous poser une série de questions sur la manière dont vous souhaitez configurer votre service Storage. Nous allons utiliser la touche Entrée pour saisir la réponse par défaut à la plupart des questions :

    ➜  photo_gallery git:(master) amplify add storage
    ? Please select from one of the below mentioned services: Content (Images, audio
    , video, etc.)
    
    ? Please provide a friendly name for your resource that will be used to label th
    is category in the project: s33daafe54
    ? Please provide bucket name: photogalleryf3fb7bda3f5d47939322aa3899275aab
    ? Who should have access: Auth users only

    Lorsqu'il vous est demandé de quel type d'accès les utilisateurs authentifiés doivent disposer, appuyez sur la touche a pour sélectionner créer/mettre à jour, lire et supprimer :

    ? What kind of access do you want for Authenticated users? create/update, read,
    delete

    Continuez ensuite à saisir les réponses par défaut jusqu'à ce que la ressource Storage soit entièrement configurée :

    ? Do you want to add a Lambda Trigger for your S3 Bucket? No
    Successfully added resource s33daafe54 locally

    Nous devons ensuite envoyer la ressource Storage configurée à notre backend afin de conserver la synchronisation. Exécutez la commande suivante :

    amplify push

    L'interface de ligne de commande d'Amplify va fournir un rapport d'état des changements qui ont lieu :

    ✔ Successfully pulled backend environment dev from the cloud.
    
    Current Environment: dev
    
    | Category | Resource name        | Operation | Provider plugin   |
    | -------- | -------------------- | --------- | ----------------- |
    | Storage  | s33daafe54           | Create    | awscloudformation |
    | Auth     | photogallery42b5391b | No Change | awscloudformation |
    ? Are you sure you want to continue? (y/n)

    Elle montre que la catégorie Storage est en cours de création et que Auth ne comporte aucun changement de notre configuration effectuée dans le module précédent.

    Une fois que la configuration de la ressource Storage est terminée dans le backend, nous verrons une sortie le confirmant :

    ✔ All resources are updated in the cloud
  • Installation de la dépendance

    Ouvrez ensuite le fichier pubspec.yaml dans Visual Studio Code pour ajouter le module d'extension Storage en tant que dépendance :

    ... # amplify_auth_cognito: '<1.0.0'
    
    amplify_storage_s3: '<1.0.0'
    
    ... # dev_dependencies:

    Enregistrez à présent le fichier afin que Visual Studio Code installe le module d'extension Amplify Auth Cognito. Vous pouvez également exécuter $ flutter pub get depuis le terminal si la dépendance ne s'installe pas lors de l'enregistrement.

    Vous devriez obtenir la sortie suivante :

    exit code 0
  • Configuration du module d'extension

    Revenez à présent à main.dart afin que Storage puisse être ajouté en tant que module d'extension dans notre instance d'Amplify :

    ... // void _configureAmplify() async {
    
    _amplify.addPlugin(
        authPlugins: [AmplifyAuthCognito()],
        storagePlugins: [AmplifyStorageS3()]);
    
    ... // try {

    Exécutez l'application. Vous devriez toujours voir le message de confirmation dans les journaux, indiquant qu'Amplify est toujours correctement configuré et comprend le module d'extension Storage.

    flutter: Successfully configured Amplify 🎉
  • Implémentation de la fonctionnalité

    Afin que notre code reste organisé, créons un fichier séparé appelé storage_service.dart, qui va encapsuler la logique de chargement et de téléchargement des fichiers. Ajoutez le code suivant :

    import 'dart:async';
    import 'package:amplify_core/amplify_core.dart';
    import 'package:amplify_storage_s3/amplify_storage_s3.dart';
    
    class StorageService {
      // 1
      final imageUrlsController = StreamController<List<String>>();
    
      // 2
      void getImages() async {
        try {
          // 3
          final listOptions =
              S3ListOptions(accessLevel: StorageAccessLevel.private);
          // 4
          final result = await Amplify.Storage.list(options: listOptions);
    
          // 5
          final getUrlOptions =
              GetUrlOptions(accessLevel: StorageAccessLevel.private);
          // 6
          final List<String> imageUrls =
              await Future.wait(result.items.map((item) async {
            final urlResult =
                await Amplify.Storage.getUrl(key: item.key, options: getUrlOptions);
            return urlResult.url;
          }));
    
          // 7
          imageUrlsController.add(imageUrls);
        
        // 8
        } catch (e) {
          print('Storage List error - $e');
        }
      }
    }
    1. Nous commençons par initialiser un contrôleur StreamController qui va gérer les URL des images récupérées dans Amazon S3.
    2. Cette fonction va lancer le processus de récupération des images devant être affichées dans GalleryPage.
    3. Étant donné que nous voulons uniquement afficher les photos que l'utilisateur a chargées, nous spécifions le niveau d'accès comme StorageAccessLevel.private, afin de nous assurer que les photos privées de nos utilisateurs le restent.
    4. Nous demandons ensuite à Storage de répertorier toutes les photos pertinentes étant donné les options S3ListOptions.
    5. Si le résultat de la liste est probant, nous devons obtenir la véritable URL de téléchargement de chaque photo car le résultat de la liste contient uniquement une liste de clés et non la véritable URL de la photo.
    6. Nous utilisons .map pour itérer sur chaque élément du résultat de la liste et renvoyer l'URL de téléchargement de chaque élément de manière asynchrone.
    7. Enfin, nous envoyons simplement la liste des URL dans le flux afin qu'elle soit étudiée.
    8. Si nous rencontrons une erreur, il nous suffit de l'imprimer.

    Sur iOS, afin de vérifier que l'application peut télécharger les images, nous devons mettre à jour la fonctionnalité App Transport Security dans Info.plist (ios > Runner > Info.plist) :

    ... <!-- <string>Need to take pictures</string> -->
    
    <key>NSAppTransportSecurity</key>
    <dict>
       <key>NSAllowsArbitraryLoads</key>
       <true/>
    </dict>
    
    ... <!-- </dict> -->

    Il est inutile de tenter de répertorier les URL des images depuis S3 si vous n'avez rien chargé, donc ajoutons une fonction pour charger des images :

    // 1
    void uploadImageAtPath(String imagePath) async {
     final imageFile = File(imagePath);
     // 2
     final imageKey = '${DateTime.now().millisecondsSinceEpoch}.jpg';
    
     try {
       // 3
       final options = S3UploadFileOptions(
           accessLevel: StorageAccessLevel.private);
    
       // 4
       await Amplify.Storage.uploadFile(
           local: imageFile, key: imageKey, options: options);
    
       // 5
       getImages();
     } catch (e) {
       print('upload error - $e');
     }
    }
    1. Il s'agit d'une fonction asynchrone qui prend le chemin de l'image fourni par l'appareil photo.
    2. Afin de nous assurer que la photo possède une clé unique, nous allons utiliser un horodatage comme clé.
    3. Comme indiqué lors de l'implémentation de getImages, nous devons spécifier le niveau d'accès comme StorageAccessLevel.private afin que l'utilisateur charge les images dans son propre dossier dans le compartiment S3.
    4. Il nous suffit ensuite de simplement charger le fichier en spécifiant sa clé et les options de chargement du fichier.
      Enfin, nous appelons getImages pour obtenir la liste la plus récente des URL des images et les envoyer dans le flux descendant.
    5. Nous avons terminé le code nécessaire pour que les opérations de chargement et de téléchargement fonctionnent. Nous devons à présent tout connecter et effectuer des tests.

    Commençons par mettre à jour GalleryPage pour prendre un contrôleur StreamController comme argument afin qu'il puisse observer les URL des images récupérées depuis le service Storage.

    ... // class GalleryPage extends StatelessWidget {
    
    final StreamController<List<String>> imageUrlsController;
    
    ... // final VoidCallback shouldLogOut;
    ... // final VoidCallback shouldShowCamera;
    
    GalleryPage(
       {Key key,
       this.imageUrlsController,
       this.shouldLogOut,
       this.shouldShowCamera})
        : super(key: key);
    
    ... // @override

    Ensuite, mettez à jour _galleryGrid pour renvoyer un générateur StreamBuilder à la place du seul GridView.builder :

    Widget _galleryGrid() {
     return StreamBuilder(
         // 1
         stream: imageUrlsController.stream,
         builder: (context, snapshot) {
           // 2
           if (snapshot.hasData) {
             // 3
             if (snapshot.data.length != 0) {
               return GridView.builder(
                   gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                       crossAxisCount: 2),
                   // 4
                   itemCount: snapshot.data.length,
                   itemBuilder: (context, index) {
                     return CachedNetworkImage(
                       imageUrl: snapshot.data[index],
                       fit: BoxFit.cover,
                       placeholder: (context, url) => Container(
                           alignment: Alignment.center,
                           child: CircularProgressIndicator()),
                     );
                   });
             } else {
               // 5
               return Center(child: Text('No images to display.'));
             }
           } else {
             // 6
             return Center(child: CircularProgressIndicator());
           }
         });
    }
    1. Le générateur StreamBuilder va utiliser le contrôleur imageUrlsController qui sera transmis du service StorageService pour fournir des instantanés de nos données.
    2. L'interface utilisateur exige que l'instantané possède des données afin d'afficher quelque chose de pertinent à l'utilisateur.
    3. Nous devons également déterminer si les données possèdent effectivement des éléments. Dans l'affirmative, nous poursuivons la génération de la vue GridView.
    4. Au lieu d'utiliser un chiffre codé en dur, nous pouvons maintenant faire en sorte que la taille de notre vue GridView soit basée sur la longueur des données de notre instantané.
    5. Si l'instantané ne comporte aucun élément, nous afficherons un texte indiquant qu'il n'y a rien à afficher.

    Pour le moment, nous affichons toujours un espace réservé pour chaque élément de la grille. Nous allons devoir télécharger chaque image depuis l'URL fournie par le flux. Pour nous simplifier la tâche, ajoutons une nouvelle dépendance dans pubspec.yaml :

    ... # amplify_storage_s3: '<1.0.0'
    
    cached_network_image: ^2.3.3
    
    ... # dev_dependencies:

    Cette bibliothèque fournit un widget pouvant télécharger et mettre en cache une image en recevant simplement une URL. Enregistrez les changements et revenez à GalleryPage afin que nous puissions remplacer l'espace réservé :

    ... // itemBuilder: (context, index) {
    
    return CachedNetworkImage(
      imageUrl: snapshot.data[index],
      fit: BoxFit.cover,
      placeholder: (context, url) => Container(
          alignment: Alignment.center,
          child: CircularProgressIndicator()),
    );
    
    ... // itemBuilder closing });

    L'espace réservé a été remplacé par l'image CachedNetworkImage, qui a transmis l'URL depuis l'instantané et l'a indexée via le générateur itemBuilder. Pendant que l'image charge, le widget va afficher un indicateur CircularProgressIndicator.

    Nous pouvons maintenant connecter GalleryPage et CameraPage au service StorageService dans _CameraFlowState. Commencez par créer une propriété pour contenir une instance du service StorageService :

    ... // bool _shouldShowCamera = false;
    
    StorageService _storageService;
    
    ... // List<MaterialPage> get _pages {

    Ensuite, initialisez _storageService dans la méthode initState :

    ... // _getCamera();
    
    _storageService = StorageService();
    _storageService.getImages();
    
    ... // initState closing }

    Immédiatement après avoir initialisé le service StorageService, nous appelons getImages afin que toutes les images chargées soient récupérées.

    Transmettons maintenant le contrôleur StreamController à GalleryPage :

    ... // child: GalleryPage(
        
    imageUrlsController: _storageService.imageUrlsController,
    
    ... // shouldLogOut: widget.shouldLogOut,

    Enfin, mettez à jour la fonctionnalité de didProvideImagePath de la page CameraPage une fois une photo prise :

    ... // this._toggleCameraOpen(false);
    
    this._storageService.uploadImageAtPath(imagePath);
    
    ... // didProvideImagePath closing }

    Et voilà ! Nous sommes prêts à commencer à prendre des photos avec notre application et à les charger dans S3.

    Créez et exécutez ce code pour l'essayer !

    EndofModule4-gif

Conclusion

Félicitations ! La fonctionnalité de base de l'application a été implémentée et l'utilisateur peut prendre des photos, qui seront stockées dans une section privée du compartiment S3 de l'application.

Dans le module suivant, vous allez ajouter des analyses.

Ce module vous a-t-il été utile ?

Merci
Merci de nous indiquer ce que vous avez aimé.
Fermer
Nous sommes désolés de vous décevoir.
Quelque chose est-il obsolète, déroutant ou inexact ? Aidez-nous à améliorer ce didacticiel en fournissant des commentaires.
Fermer

Ajouter le service Analytics