Erste Schritte mit AWS

Erstellen eine Flutter-Anwendung

Erstellen Sie eine einfache Flutter-Anwendung mit AWS Amplify

Modul 4: Hinzufügen der Funktion, Bilder zu speichern

In diesem Modul fügen Sie Speicherplatz hinzu und haben die Möglichkeit, ein Bild mit den Notizen in Ihrer App zu verknüpfen.

Einführung

Nun, da nur authentifizierte Benutzer die Anwendung betreten können, können wir dem Benutzer erlauben, Bilder zu machen und sie in einen privaten Ordner im Amazon S3-Bucket unserer Anwendung hochzuladen.

In diesem Modul fügen wir die Kategorie Speicher zu Ihrer Amplify-Anwendung hinzu, laden Bilder von der Kamera des Geräts hoch, laden dann alle mit einem einzelnen Benutzer verknüpften Fotos herunter und zeigen sie an.

Lerninhalte

  • Konfigurieren der Speicherkategorie
  • Hochladen von Dateien in Amazon S3
  • Dateien von Amazon S3 herunterladen
  • Anzeigen und Zwischenspeichern von Bildern aus einer URL

Wichtige Konzepte

Speicherung: Das Konzept der Speicherung besteht darin, Dateien an einem Ort zu speichern und diese Dateien bei Bedarf abzurufen. In diesem Fall das Speichern von Bildern auf Amazon S3 und das Herunterladen von Bildern von Amazon S3.

 Veranschlagte Zeit

20 Minuten

 Verwendete Services

Implementierung

  • Erstellen Sie den Speicher-Service

    Fügen Sie den Speicher-Service zum Amplify-Projekt hinzu, indem Sie den folgenden Befehl im Terminal im Stammverzeichnis des Projekts eingeben:

    amplify add storage

    Wie bei jeder anderen Kategorie werden Sie auch bei der Amplify CLI Fragen zur Konfiguration Ihres Speicher-Service gestellt. Wir werden die Eingabetaste verwenden, um die meisten Fragen mit der Standardantwort zu beantworten:

    ➜  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

    Wenn Sie gefragt werden, welche Art von Zugriff authentifizierte Benutzer haben sollen, drücken Sie die Taste a, um Erstellen/Aktualisieren, Lesen und Löschen auszuwählen:

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

    Fahren Sie dann mit der Eingabe der Standardantworten fort, bis die Speicherressource vollständig konfiguriert ist:

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

    Jetzt müssen wir die konfigurierte Speicherressource an unsere Backups senden, damit wir synchron bleiben. Führen Sie den folgenden Befehl aus:

    amplify push

    Amplify CLI wird einen Statusbericht über die stattfindenden Änderungen liefern:

    ✔ 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)

    Es zeigt, dass die Kategorie Speicher gerade erstellt wird und Auth keine Änderungen gegenüber unserem Setup im vorherigen Modul aufweist.

    Sobald die Konfiguration unserer Storage-Ressource im Backend abgeschlossen ist, werden wir eine erfolgreiche Ausgabe sehen:

    ✔ All resources are updated in the cloud
  • Installieren der Abhängigkeit

    Öffnen Sie anschließend die Datei pubspec.yaml im Visual Studio-Code, um das Storage-Plugin als Abhängigkeit hinzuzufügen:

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

    Speichern Sie jetzt die Datei, damit Visual Studio Code das Plugin Amplify Auth Cognito installiert. Sie können auch $ flutter pub get vom Terminal ausführen, wenn die Abhängigkeit nicht auf save installiert ist.

    Sie sollten folgende Ausgabe erhalten:

    exit code 0
  • Konfigurieren des Plugins

    Navigieren Sie nun zurück zu main.dart, damit Storage als Plugin auf unserer Instance von Amplify hinzugefügt werden kann:

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

    Führen Sie die App aus Sie sollten in den Protokollen immer noch die Erfolgsmeldung sehen, die anzeigt, dass Amplify immer noch richtig konfiguriert ist und das Speicher-Plugin einschließt.

    flutter: Successfully configured Amplify 🎉
  • Funktionalität implementieren

    Um unseren Code organisiert zu halten, erstellen wir eine separate Datei namens storage_service.dart, die die Logik für das Hoch- und Herunterladen von Dateien kapselt. Fügen Sie den folgenden Code hinzu:

    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. Wir beginnen mit der Initialisierung eines StreamControllers, der die Bild-URLs verwaltet, die von Amazon S3 abgerufen werden.
    2. Diese Funktion startet den Prozess des Abrufs der Bilder, die in GalleryPage angezeigt werden sollen.
    3. Da wir nur Fotos zeigen möchten, die der Benutzer hochgeladen hat, geben wir die Zugriffsebene als StorageAccessLevel.private an, um sicherzustellen, dass die privaten Fotos unserer Benutzer privat bleiben.
    4. Als nächstes bitten wir Storage, alle relevanten Fotos mit den S3ListOptions aufzulisten.
    5. Wenn das Listenergebnis erfolgreich ist, benötigen wir die tatsächliche Download-URL jedes Fotos, da das Listenergebnis nur eine Liste der Schlüssel und nicht die tatsächliche URL des Fotos enthält.
    6. Wir verwenden .map, um über jeden Artikel im Listenergebnis zu interagieren und asynchron die Download-URL jedes Elements zurückzugeben.
    7. Schließlich senden wir die Liste der URLs einfach den zu beobachtenden Stream hinunter.
    8. Sollten auf dem Weg dorthin Fehler auftreten, werden wir einfach einen Fehler ausdrucken.

    Um sicherzustellen, dass die App die Bilder herunterladen kann, müssen wir auf iOS die App Transport Security in Info.plist aktualisieren (ios > Runner > Info.plist):

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

    Der Versuch, Bild-URLs von S3 aufzulisten, ist sinnlos, wenn Sie nichts hochgeladen haben, also fügen wir eine Funktion zum Hochladen von Bildern hinzu:

    // 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. Dabei handelt es sich um eine asynchrone Funktion, die einen von der Kamera bereitgestellten Bildpfad aufnimmt.
    2. Um sicherzustellen, dass das Foto einen eindeutigen Schlüssel hat, werden wir einen Zeitstempel als Schlüssel verwenden.
    3. Wie bei der Implementierung von getImages angegeben, müssen wir die Zugriffsebene als StorageAccessLevel.private angeben, damit der Benutzer Bilder in seinen eigenen Ordner im S3-Bucket hochladen kann.
    4. Dann laden wir einfach die Datei unter Angabe ihres Schlüssels hoch und laden die Dateioptionen hoch.
      Zuletzt rufen wir getImages an, um die neueste Liste der Bildurls zu erhalten und sie per Stream weiterzuleiten.
    5. Wir haben die gesamte Kodierung abgeschlossen, die erforderlich ist, damit unser Hoch- und Herunterladen funktioniert. Jetzt müssen wir alles miteinander verbinden und testen.

    Beginnen wir damit, GalleryPage so zu aktualisieren, dass ein StreamController als Argument genommen wird, damit er die aus dem Speicher abgerufenen Bild-URLs beobachten kann.

    ... // 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

    Als Nächstes aktualisieren Sie _galleryGrid, um einen StreamBuilder statt nur den GridView.builder zurückzugeben:

    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. Der StreamBuilder wird den imageUrlsController verwenden, der von StorageService übergeben wird, um Snapshots unserer Daten bereitzustellen.
    2. Die UI erfordert, dass der Snapshot Daten enthält, um alle für den Benutzer relevanten Informationen anzuzeigen.
    3. Wir müssen auch feststellen, ob die Daten tatsächlich Objekte enthalten. Wenn dies der Fall ist, fahren wir mit dem Build der GridView fort.
    4. Anstelle einer fest kodierten Zahl können wir unsere GridView-Größe jetzt auf der Länge der Daten in unserem Snapshot basieren lassen.
    5. Wenn der Snapshot keine Elemente enthält, werden wir einen Text anzeigen, der darauf hinweist, dass es nichts zu zeigen gibt.

    Im Moment zeigen wir noch einen Platzhalter für jedes Element in der Tabelle. Wir müssen jedes Bild von der vom Stream bereitgestellten URL herunterladen. Um das einfacher zu machen, fügen wir in pubspec.yaml eine neue Abhängigkeit hinzu:

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

    Diese Bibliothek stellt ein Widget zur Verfügung, das ein Bild herunterladen und zwischenspeichern kann, indem es einfach eine URL erhält. Speichern Sie die Änderungen und navigieren Sie zurück zu GalleryPage, damit wir den Platzhalter ersetzen können:

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

    Der Platzhalter wurde durch CachedNetworkImage ersetzt, dem die URL aus dem Snapshot übergeben und durch den itemBuilder indiziert wird. Während das Bild geladen wird, zeigt das Widget einen CircularProgressIndicator an.

    Jetzt können wir GalleryPage und CameraPage mit dem StorageService in _CameraFlowState verbinden. Beginnen Sie mit der Erstellung einer Eigenschaft zum Halten einer Instance von StorageService:

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

    Als Nächstes initialisieren Sie _storageService in der initState-Methode:

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

    Unmittelbar nach der Initialisierung von StorageService rufen wir getImages auf, damit alle hochgeladenen Bilder abgerufen werden.

    Übergeben wir nun den StreamController an die GalleryPage:

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

    Aktualisieren Sie schließlich die Funktionalität von didProvideImagePath der CameraPage, sobald ein Bild aufgenommen wurde:

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

    Das war's! Wir sind bereit, mit unserer App Fotos zu machen und sie auf S3 hochzuladen.

    Erstellen Sie die App und führen Sie sie aus, um sie auszuprobieren!

    EndofModule4-gif

Fazit

Prima! Die Kernfunktionalität der App wurde implementiert und der Benutzer kann Bilder aufnehmen, die in einem privaten Bereich des S3-Buckets der App gespeichert werden.

Im nächsten Modul werden wir die Analytik hinzufügen.

War das Modul hilfreich?

Vielen Dank
Bitte teilen Sie uns mit, was Ihnen gefallen hat.
Schließen
Es tut uns Leid Sie zu enttäuschen
Ist etwas veraltet, verwirrend oder ungenau? Bitte helfen Sie uns, dieses Tutorial zu verbessern, indem Sie Feedback geben.
Schließen

Analytik hinzufügen