I have an app that uses AWS Cognito to authenticate a user. The authentication works well. The app also saves items to DataStore with AWS Amplify. I installed Amplify with Swift Package Manager as a package called amplify-ios
. When I added the package I specified "Up to Next Major Version", 1.0.0 < 2.0.0.
In fact, the app DOES NOT sync the date saved to DataStore with AppSync. It saves them locally only. I triple checked my AWS console: the DynamoDB table for the data exists but it's empty. No data saved, whatsoever!
What do I do wrong? Does this Amplify library work with AppSync? If not, what shall I use instead?
My code:
ToDoStore.swift:
import Foundation
import Combine
import SwiftUI
import Amplify
class ToDoStore: ObservableObject {
@Published private(set) var todos: [Todo] = []
init() {
self.getAllTodosFromDataStore()
}
func getAllTodosFromDataStore() {
Amplify.DataStore.query(Todo.self) { (result) in
switch result {
case .success(let todos):
DispatchQueue.main.async {
print("Got \(todos.count) Todos from DataStore initially")
self.todos = todos
}
case .failure(let error):
print("Error getting Todos from DataStore: \(error.localizedDescription)")
}
}
}
func deleteTodoFromDataStore(for indexSet: IndexSet) {
let todosToDelete = indexSet.map { self.todos[$0] }
self.todos.remove(atOffsets: indexSet)
for todo in todosToDelete {
Amplify.DataStore.delete(todo) { (result) in
switch result {
case .success():
print("Deleted Todo from DataStore")
case .failure(let error):
print("Error deleting Todo From DataStore: \(error)")
}
}
}
}
private func addTodoToArray(_ todo: Todo) {
if !self.todos.contains(todo) {
self.todos.append(todo)
}
}
private func deleteTodoFromArray(_ todo: Todo) {
if let index = self.todos.firstIndex(of: todo) {
self.todos.remove(at: index)
}
}
private func updateTodoInArray(_ todo: Todo) {
print("update?")
}
}
AWSDataStoreApp.swift:
import SwiftUI
import Amplify
import AWSCognitoAuthPlugin
import AWSDataStorePlugin
import Foundation
@main
struct AWSDataStoreTestApp: App {
@ObservedObject var sessionManager = SessionManager()
init() {
configureAmplify()
sessionManager.getCurrentAuthUser()
}
var body: some Scene {
WindowGroup {
switch sessionManager.authState {
case .login:
LoginView()
.environmentObject(sessionManager)
case .resetPassword:
ResetPasswordView()
.environmentObject(sessionManager)
case .signUp:
SignUpView()
.environmentObject(sessionManager)
case .confirmCode(let username):
ConfirmationView(username: username)
.environmentObject(sessionManager)
case .session(let user):
SessionView(user: user)
.environmentObject(sessionManager)
}
}
}
private func configureAmplify() {
do {
try Amplify.add(plugin: AWSCognitoAuthPlugin())
try Amplify.add(plugin: AWSDataStorePlugin(modelRegistration: AmplifyModels()))
try Amplify.configure()
print("Amplify configured sucessfully")
} catch {
print("Could not intstall Amplify", error)
}
}
}
SessionView.swift:
import SwiftUI
import Amplify
import CoreLocation
struct SessionView: View {
@EnvironmentObject var sessionManager: SessionManager
@ObservedObject var todoStore = ToDoStore()
let user: AuthUser
var body: some View {
TodoListView()
.onAppear(perform: {
todoStore.getAllTodosFromDataStore()
})
.environmentObject(sessionManager)
}
}
struct TodoListView: View {
@EnvironmentObject var sessionManager: SessionManager
@State private var todos: [Todo] = []
var body: some View {
NavigationView {
VStack {
List(todos) { todo in
Text(todo.name)
}
.onAppear {
// Query the DynamoDB table for Todo items
Amplify.DataStore.query(Todo.self) { result in
switch result {
case .success(let todos):
// Update the todos state with the retrieved Todo items
self.todos = todos
case .failure(let error):
print("Error retrieving Todo items: \(error)")
}
}
}
NavigationLink(destination: AddTodoView()
.environmentObject(sessionManager),
label: {
Text("Add todo")
.padding()
.foregroundColor(.white)
.background(Color.green)
.cornerRadius(10)
.font(
.system(size: 20))
})
}
}
}
}
struct AddTodoView: View {
@EnvironmentObject var sessionManager: SessionManager
@State var name = ""
var body: some View {
VStack {
TextField("Name", text: $name)
Button(action: {
// create todo
let todo = Todo(name: name, ownerId: sessionManager.getUser().userId)
Amplify.DataStore.save(todo) { result in
switch result {
case .success(let success):
// Update the todos state with the retrieved Todo items
print(success)
print("Saved")
case .failure(let error):
print("Error retrieving Todo items: \(error)")
}
}
}, label: {
Text("Submit")
})
}
}
}
The app shows the items added to the DataStore, everything works, but DOES NOT SYNC. The resources seem to be added to the project correctly. The authentication via Cognito works, but not the DataStore sync.
% amplify status
Current Environment: dev
┌──────────┬──────────────────────────────────┬───────────┬───────────────────┐
│ Category │ Resource name │ Operation │ Provider plugin │
├──────────┼──────────────────────────────────┼───────────┼───────────────────┤
│ Auth │ awsdatastoretest058f3478058f3478 │ No Change │ awscloudformation │
├──────────┼──────────────────────────────────┼───────────┼───────────────────┤
│ Api │ awsdatastoretest │ No Change │ awscloudformation │
Dependency manager: Swift PM Swift version: Apple Swift version 5.7 (swiftlang-5.7.0.127.4 clang-1400.0.29.50) Target: arm64-apple-darwin21.6.0 Amplify CLI version: 10.5.2 Xcode version: 14.0.1 (14A400)
I made a fresh project. I installed amplify from scratch. I checked similar posts end ensured that my app is connected to the Internet (it is). I tried everything. Nothing works.
I described the issue also at https://github.com/aws-amplify/amplify-swift/issues/2632.
It appeared that I missed to add a separate plugin that is essential to start syncing local DataStore on the phone and the backend at AWS. Thus, the answer is to add to my main App swift file the following:
try Amplify.add(plugin: AWSAPIPlugin())
Thus, the whole function that I call from my app init() looks like this:
private func configureAmplify() {
do {
try Amplify.add(plugin: AWSCognitoAuthPlugin())
try Amplify.add(plugin: AWSAPIPlugin())
try Amplify.add(plugin: AWSDataStorePlugin(modelRegistration: AmplifyModels()))
try Amplify.add(plugin: AWSS3StoragePlugin())
try Amplify.configure()
print("Amplify configured sucessfully")
} catch {
print("Could not intstall Amplify", error)
}
}