Erste Schritte mit AWS

Erstellen einer iOS-Anwendung

Erstellen Sie eine einfache iOS-Anwendung mit AWS Amplify

Modul 5: 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 die Notizen-App funktioniert, wollen wir die Möglichkeit hinzufügen, jeder Notiz ein Bild zuzuordnen. In diesem Modul werden Sie die Amplify CLI und Bibliotheken verwenden, um einen Speicher-Service zu erstellen, der Amazon S3 nutzt. Schließlich werden Sie die iOS-Anwendung aktualisieren, um das Hochladen, Abrufen und Rendern von Bildern zu ermöglichen.

Lerninhalte

  • Erstellen eines Speicher-Services
  • Aktualisieren Ihrer IOS-App: die Logik zum Hoch- und Herunterladen von Bildern
  • Aktualisieren Ihrer IOS-App: die Benutzeroberfläche

Wichtige Konzepte

Speicher-Service – Das Speichern und Abfragen von Dateien wie Bildern und Videos ist eine allgemeine Anforderung für die meisten Anwendungen. Eine Möglichkeit, dies zu tun, besteht darin, die Datei Base64 zu kodieren und als String zu senden, um sie in der Datenbank zu speichern. Dies bringt Nachteile mit sich, wie z. B. dass die kodierte Datei größer ist als die ursprüngliche Binärdatei, dass die Operation rechenintensiv ist und dass die Kodierung und Dekodierung komplizierter wird. Eine weitere Option ist ein speziell für die Dateiablage entwickelter und optimierter Service. Speicherdienste wie Amazon S3 existieren, um dies so einfach, performant und kostengünstig wie möglich zu machen.

 Veranschlagte Zeit

10 Minuten

 Verwendete Services

Implementierung

  • Erstellen Sie den Speicher-Service

    Um Bildspeicherfunktionen hinzuzufügen, verwenden wir die Amplify-Speicherkategorie:

    amplify add storage
    
    ? Please select from one of the below mentioned services: accept the default Content (Images, audio, video, etc.) and press enter
    ? Please provide a friendly name for your resource that will be used to label this category in the project: type image and press enter
    ? Please provide bucket name: accept the default and press enter
    ? Who should have access: accept the default Auth users only and press enter
    ? What kind of access do you want for Authenticated users? select all three options create/update, read, delete using the space and arrows keys, then press enter
    ? Do you want to add a Lambda Trigger for your S3 Bucket? accept the default No and press enter

    Nach einer Weile sollten Sie Folgendes sehen:

    Successfully added resource image locally
  • Bereitstellen des Speicher-Service

    Um den soeben von uns bereitgestellten Speicher-Service bereitzustellen, gehen Sie zu Ihrem Terminal und führen Sie den Befehl aus:

    amplify push

    Drücken Sie Y zum Bestätigen und nach einer Weile sollten Sie Folgendes sehen:

    ✔ Successfully pulled backend environment amplify from the cloud.
  • Hinzufügen von Amplify-Speicher-Bibliotheken zum Xcode-Projekt

    Bevor wir zum Code übergehen, fügen Sie die Amplify-Speicher-Bibliothek zu den Abhängigkeiten Ihres Projekts hinzu. Öffnen Sie die Podfile-Datei und fügen Sie die Zeile mit AmplifyPlugins/AWSS3StoragePlugin hinzu oder kopieren Sie die gesamte Datei

    # you need at least version 13.0 for this tutorial, more recent versions are valid too
    platform :ios, '13.0'
    
    target 'getting started' do
      # Comment the next line if you don't want to use dynamic frameworks
      use_frameworks!
    
      # Pods for getting started
      pod 'Amplify', '~> 1.0'                             # required amplify dependency
      pod 'Amplify/Tools', '~> 1.0'                       # allows to call amplify CLI from within Xcode
    
      pod 'AmplifyPlugins/AWSCognitoAuthPlugin', '~> 1.0' # support for Cognito user authentication
      pod 'AmplifyPlugins/AWSAPIPlugin', '~> 1.0'         # support for GraphQL API
      pod 'AmplifyPlugins/AWSS3StoragePlugin', '~> 1.0'   # support for Amazon S3 storage
    
    end

    Führen Sie den Befehl in einem Terminal aus:

    pod install

    Die Ausführung des Befehls dauert einige Augenblicke. Sie sollten dies sehen (die tatsächlichen Versionsnummern können variieren):

    Analyzing dependencies
    Downloading dependencies
    Installing AWSS3 (2.14.2)
    Installing AmplifyPlugins 1.0.4
    Generating Pods project
    Integrating client project
    Pod installation complete! There are 5 dependencies from the Podfile and 12 total pods installed.
  • Speicher-Plugin zur Laufzeit initialisieren

    Zurück zu Xcode, öffnen Sie Backend.swift und fügen Sie eine Zeile in die Amplify Backend-Initialisierungssequenz in der Methode private init() hinzu. Der vollständige Codeblock sollte wie folgt aussehen:

    // initialize amplify
    do {
       try Amplify.add(plugin: AWSCognitoAuthPlugin())
       try Amplify.add(plugin: AWSAPIPlugin(modelRegistration: AmplifyModels()))
       try Amplify.add(plugin: AWSS3StoragePlugin())
       try Amplify.configure()
       print("Initialized Amplify");
    } catch {
       print("Could not initialize Amplify: \(error)")
    }
  • Hinzufügen von Image-CRUD-Methoden zur Backend-Klasse

    Backend.swift öffnen. Fügen Sie an beliebiger Stelle in der Backend-Klasse die folgenden Methoden hinzu:

    // MARK: - Image Storage
    
    func storeImage(name: String, image: Data) {
    
    //        let options = StorageUploadDataRequest.Options(accessLevel: .private)
        let _ = Amplify.Storage.uploadData(key: name, data: image,// options: options,
            progressListener: { progress in
                // optionlly update a progress bar here
            }, resultListener: { event in
                switch event {
                case .success(let data):
                    print("Image upload completed: \(data)")
                case .failure(let storageError):
                    print("Image upload failed: \(storageError.errorDescription). \(storageError.recoverySuggestion)")
            }
        })
    }
    
    func retrieveImage(name: String, completed: @escaping (Data) -> Void) {
        let _ = Amplify.Storage.downloadData(key: name,
            progressListener: { progress in
                // in case you want to monitor progress
            }, resultListener: { (event) in
                switch event {
                case let .success(data):
                    print("Image \(name) loaded")
                    completed(data)
                case let .failure(storageError):
                    print("Can not download image: \(storageError.errorDescription). \(storageError.recoverySuggestion)")
                }
            }
        )
    }
    
    func deleteImage(name: String) {
        let _ = Amplify.Storage.remove(key: name,
            resultListener: { (event) in
                switch event {
                case let .success(data):
                    print("Image \(data) deleted")
                case let .failure(storageError):
                    print("Can not delete image: \(storageError.errorDescription). \(storageError.recoverySuggestion)")
                }
            }
        )
    }
  • Bild laden, wenn Daten von der API abgerufen werden

    Nun, da wir unsere Backend-Funktionen zur Verfügung haben, laden wir die Bilder, wenn der API-Aufruf zurückkehrt. Die zentrale Stelle zum Hinzufügen dieses Verhaltens ist, wenn die Anwendung eine Hinweis-Benutzeroberfläche aus den von der API zurückgegebenen Hinweisdaten konstruiert.

    Öffnen Sie ContentView.swift und aktualisieren Sie den Initialisierer der Notiz (fügen Sie die Zeilen 8 bis 17 hinzu):

    // add a publishable's object property
    @Published var image : Image?
    
    // update init's code
    convenience init(from data: NoteData) {
        self.init(id: data.id, name: data.name, description: data.description, image: data.image)
    
        if let name = self.imageName {
            // asynchronously download the image
            Backend.shared.retrieveImage(name: name) { (data) in
                // update the UI on the main thread
                DispatchQueue.main.async() {
                    let uim = UIImage(data: data)
                    self.image = Image(uiImage: uim!)
                }
            }
        }
        // store API object for easy retrieval later
        self._data = data
    }

    Wenn ein Bildname in der Instance von Note vorhanden ist, ruft der Code retrieveImage auf. Dies ist eine asynchrone Funktion. Es ist eine Funktion erforderlich, die beim Herunterladen des Bildes aufgerufen wird. Die Funktion erstellt ein Image-UI-Objekt und weist es der Instance von Note zu. Beachten Sie, dass diese Zuordnung eine Aktualisierung der Benutzeroberfläche auslöst und daher im Hauptthread der Anwendung mit DispatchQueue.main.async geschieht.

  • Hinzufügen von UI-Code zum Erfassen eines Bildes

    Zunächst fügen wir generischen Code zur Unterstützung der Bilderfassung hinzu. Dieser Code kann in vielen Anwendungen wiederverwendet werden; er zeigt einen Bildauswahlschalter, mit dem der Benutzer ein Bild aus seiner Bildbibliothek auswählen kann.

    Erstellen Sie in Xcode die neue Swift-Datei (⌘N, wählen Sie dann Swift). Benennen Sie die Datei CaptureImageView.swift und fügen Sie diesen Code hinzu:

    import Foundation
    import UIKit
    import SwiftUI
    
    struct CaptureImageView {
    
      /// MARK: - Properties
      @Binding var isShown: Bool
      @Binding var image: UIImage?
    
      func makeCoordinator() -> Coordinator {
        return Coordinator(isShown: $isShown, image: $image)
      }
    }
    
    class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
      @Binding var isCoordinatorShown: Bool
      @Binding var imageInCoordinator: UIImage?
      init(isShown: Binding<Bool>, image: Binding<UIImage?>) {
        _isCoordinatorShown = isShown
        _imageInCoordinator = image
      }
      func imagePickerController(_ picker: UIImagePickerController,
                    didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
         guard let unwrapImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage else { return }
         imageInCoordinator = unwrapImage
         isCoordinatorShown = false
      }
      func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
         isCoordinatorShown = false
      }
    }
    
    extension CaptureImageView: UIViewControllerRepresentable {
        func makeUIViewController(context: UIViewControllerRepresentableContext<CaptureImageView>) -> UIImagePickerController {
            let picker = UIImagePickerController()
            picker.delegate = context.coordinator
    
            // picker.sourceType = .camera // on real devices, you can capture image from the camera
            // see https://medium.com/better-programming/how-to-pick-an-image-from-camera-or-photo-library-in-swiftui-a596a0a2ece
    
            return picker
        }
    
        func updateUIViewController(_ uiViewController: UIImagePickerController,
                                    context: UIViewControllerRepresentableContext<CaptureImageView>) {
    
        }
    }
  • Bild speichern, wenn Notizen erstellt werden

    Rufen wir die Speichermethoden aus dem Backend auf, wenn eine Notiz erstellt wird. Öffnen Sie ContentView.swift und ändern Sie die AddNoteView, um eine ImagePicker-Komponente hinzuzufügen:

    // at the start of the Content View struct 
    @State var image : UIImage? // replace the previous declaration of image
    @State var showCaptureImageView = false
    
    // in the view, replace the existing PICTURE section
    Section(header: Text("PICTURE")) {
        VStack {
            Button(action: {
                self.showCaptureImageView.toggle()
            }) {
                Text("Choose photo")
            }.sheet(isPresented: $showCaptureImageView) {
                CaptureImageView(isShown: self.$showCaptureImageView, image: self.$image)
            }
            if (image != nil ) {
                HStack {
                    Spacer()
                    Image(uiImage: image!)
                        .resizable()
                        .frame(width: 250, height: 200)
                        .clipShape(Circle())
                        .overlay(Circle().stroke(Color.white, lineWidth: 4))
                        .shadow(radius: 10)
                    Spacer()
                }
            }
        }
    }

    Ändern Sie den Abschnitt Notiz erstellen, um sowohl das Bild als auch die Notiz zu speichern:

    Section {
        Button(action: {
            self.isPresented = false
    
            let note = Note(id : UUID().uuidString,
                            name: self.$name.wrappedValue,
                            description: self.$description.wrappedValue)
    
            if let i = self.image  {
                note.imageName = UUID().uuidString
                note.image = Image(uiImage: i)
    
                // asynchronously store the image (and assume it will work)
                Backend.shared.storeImage(name: note.imageName!, image: (i.pngData())!)
            }
    
            // asynchronously store the note (and assume it will succeed)
            Backend.shared.createNote(note: note)
    
            // add the new note in our userdata, this will refresh UI
            withAnimation { self.userData.notes.append(note) }
        }) {
            Text("Create this note")
        }
    }
  • Erstellen und testen

    Um zu überprüfen, ob alles wie erwartet funktioniert, bauen und betreiben Sie das Projekt. Klicken Sie auf das Menü Produkt und wählen Sie Ausführen oder geben Sie ⌘R ein. Es sollte kein Fehler vorliegen.

    Angenommen, Sie sind noch angemeldet, startet die App auf der Liste mit einer Notiz. Verwenden Sie erneut das +-Zeichen, um eine Notiz zu erstellen. Fügen Sie diesmal ein aus dem lokalen Bildspeicher ausgewähltes Bild hinzu.

    Hier ist der vollständige Ablauf.

    iOSTutorial-Module5-step1
    iOSTutorial-Module5-step2
    iOSTutorial-Module5-step3
    iOSTutorial-Module5-step4
    iOSTutorial-Module5-step5

Fazit

Sie haben mit AWS Amplify eine iOS-Anwendung erstellt! Sie haben Ihrer Anwendung eine Authentifizierung hinzugefügt, mit der Benutzer sich anmelden, einloggen und ihr Konto verwalten können. Die Anwendung verfügt außerdem über eine skalierbare GraphQL-API, die mit einer Amazon DynamoDB-Datenbank konfiguriert ist und es Benutzern ermöglicht, Notizen zu erstellen und zu löschen. Sie haben auch einen Dateispeicher mit Amazon S3 hinzugefügt, der es Benutzern ermöglicht, Bilder hochzuladen und in ihrer Anwendung anzusehen.

Im letzten Abschnitt finden Sie Anweisungen zur Wiederverwendung oder zum Löschen des soeben erstellten Backends.

  • Teilen Sie Ihr Backend zwischen mehreren Projekten

    Amplify macht es einfach, ein einziges Backend für mehrere Frontend-Anwendungen gemeinsam zu nutzen.

    Navigieren Sie in einem Terminal zu Ihrem anderen Projektverzeichnis und führen Sie den folgenden Befehl aus:

    mkdir other-project
    cd other-project
    
    amplify pull
    
    ? Do you want to use an AWS profile? accept the default Yes and press enter
    ? Please choose the profile you want to use select the profile you want to use and press enter
    ? Which app are you working on? select the backend you want to share and press enter
    ? Choose your default editor: select you prefered text editor and press enter
    ? Choose the type of app that you're building select the operating system for your new project and press enter
    ? Do you plan on modifying this backend? most of the time, select No and press enter. All backend modifications can be done from the original iOS project.

    Nach einigen Sekunden sehen Sie die folgende Meldung:

    Added backend environment config object to your project.
    Run 'amplify pull' to sync upstream changes.

    Sie können die beiden Konfigurationsdateien sehen, die herausgezogen wurden. Wenn Sie auf die Frage "Planen Sie eine Änderung dieses Backends?" mit "Ja" antworten, sehen Sie auch ein Amplify Backend.

    ➜  other-project git:(master) ✗ ls -al
    total 24
    drwxr-xr-x   5 stormacq  admin   160 Jul 10 10:28 .
    drwxr-xr-x  19 stormacq  admin   608 Jul 10 10:27 ..
    -rw-r--r--   1 stormacq  admin   315 Jul 10 10:28 .gitignore
    -rw-r--r--   1 stormacq  admin  3421 Jul 10 10:28 amplifyconfiguration.json
    -rw-r--r--   1 stormacq  admin  1897 Jul 10 10:28 awsconfiguration.json
  • Löschen Sie Ihr Backend

    Wenn Sie ein Backend für einen Test oder einen Prototyp oder einfach nur zu Lernzwecken erstellen, möchten Sie, genau wie beim Befolgen dieses Tutorials, die erstellten Cloud-Ressourcen löschen.

    Obwohl die Nutzung dieser Ressourcen im Rahmen dieses Tutorials in das kostenlose Kontingent fällt, ist es eine bewährte Methode, ungenutzte Ressourcen in der Cloud zu bereinigen.

    Um Ihr Amplify-Projekt zu bereinigen, führen Sie in einem Terminal den folgenden Befehl aus:

    amplify delete

    Nach einer Weile sehen Sie die untenstehende Meldung, die bestätigt, dass alle Cloud-Ressourcen gelöscht wurden.

    ✔ Project deleted in the cloud
    Project deleted locally.

Vielen Dank, dass Sie dieses Tutorial bis zum Ende verfolgt haben. Bitte teilen Sie uns Ihr Feedback mit, indem Sie das untenstehende Tool oder eine Pull-Anfrage zu unserem Github-Repository verwenden.

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

Herzlichen Glückwunsch!

Sie haben eine Webanwendung auf AWS erstellt! Als großen nächsten Schritt sollten Sie tiefer in spezifische AWS-Technologien eintauchen und Ihre Anwendung auf die nächste Stufe bringen.