使用AWS Amplify进行iOS应用程序开发入门(第3部分)

总结

使用iOS应用程序通过AppSync实现将数据存储到DynamoDB的部分,并使用GraphQL进行实现。
此外,使用Cognito进行身份验证部分,并使用AWS Amplify进行AppSync的构建。

前提条件

AWS Amplify入门iOS应用开发(第一部分)和AWS Amplify入门iOS应用开发(第二部分)已经完成。
我们将使用在第一部分创建的Xcode项目。

使用AWS Amplify构建AppSync。

# Xcodeのルートプロジェクトに移動
$ cd ~/Downloads/amplify-learn

# AppSyncを作成(実際に作成されるのは「amplify push」後)
$ amplify add api
# Please select from one of the below mentioned services
# →GraphQLを選択
# Provide API name
# →amplifylearnを選択(名前は任意)
# Choose an authorization type for the API
# →Amazon Cognito User Poolを選択
# Do you have an annotated GraphQL schema?
# →Noを選択
# Do you want a guided schema creation?
# yesを選択
# What best describes your project
# →Single object with fields (e.g., “Todo” with ID, name,description)を選択
# Do you want to edit the schema now? 
# →Noを選択

# AppSyncを作成するようにクラウド側に命令
$ amplify push
# Are you sure you want to continue?
# →yを選択
# Do you want to generate code for your newly created GraphQL API
# →yを選択
# Enter the file name pattern of graphql queries, mutations and subscriptions(graphql/**/*.graphql)
# →デフォルトのままEnterキーを押す
# Do you want to generate/update all possible GraphQL operations - queries, mutations and subscriptions
# →yを選択
# Enter the file name for the generated code (API.swift)
# →デフォルトのままEnterキーを押す

本文介绍了上述命令的基本内容。
本次将使用GraphQL在云端进行数据交互。
对GraphQL的详细解释将在本次讨论中省略。

首先,在运行`amplify add api`命令时,GraphQL的模式定义将保存在`~/Downloads/amplify-learn/amplify/backend/api/amplifylearn/schema.graphql`文件中。

type Todo @model {
  id: ID!
  name: String!
  description: String
}

@model指令表示将数据保存到DynamoDB,因此只需进行上述模式定义,执行amplify push后,DynamoDB表将自动创建。(有关指令说明,请参阅这里的“使用GraphQL转换器”部分)

通过运行$ amplify push,将会启动CloudFormation并创建AppSync。
您将被问到一些问题,但“Do you want to generate code for your newly created GraphQL API”是最重要的问题。
通过回答yes来自动创建在iOS中使用AppSync的函数。
首先,在graphql目录下会创建包含突变、查询和订阅定义的文件。

mutations_graphql_—_amplify-learn.png

根据此文件,在Swift代码中自动生成且保存至API.swift的代码,可以方便地执行GraphQL的突变、查询和订阅,从而实现对GraphQL的简单操作。

而且,我们可以看到在awsconfig.json中添加了AppSync项目,并记录了GraphQL的终端节点。

"AppSync": {
        "Default": {
            "ApiUrl": "https://vf5rq526ubhxxxxxxxxxxxx.appsync-api.ap-northeast-1.amazonaws.com/graphql",
            "Region": "ap-northeast-1",
            "AuthMode": "AMAZON_COGNITO_USER_POOLS"
        }
    }

使用AppSync将数据存储到DynamoDB的实现部分

安装要使用的 iOS SDK。

请修改Podfile文件如下。

target 'amplify-learn' do
  use_frameworks!

  # Pods for amplify-learn
  pod 'AWSMobileClient', '~> 2.7.0'
  pod 'AWSAuthUI', '~> 2.7.0'
  pod 'AWSUserPoolsSignIn', '~> 2.7.0' 
  pod 'AWSS3', '~> 2.7.0'
  pod 'AWSAppSync', ' ~> 2.6.24' # AppSync用のSDKを追加
end
# Xcodeプロジェクトのルートに移動
$ cd ~/Downloads/amplify-learn

# 必要なSDKを追加
$ pod install --repo-update

最后,将API.swift包含到Xcode项目中。

amplify-learn.xcworkspaceを開く
プロジェクト直下にAPI.swiftをドラッグ&ドロップする
Copy items if neededのチェックを外し、Create groupsを選択し、「Finish」をクリックする

进行AppSync的设置

将以下代码添加到AppDelegeta.swift文件中。
进行AppSync的初始设置。
本次设置使用Cognito用户池。
注意:以下代码是摘录,所以请不要删除未提及的行。


func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    let databaseURL = URL(fileURLWithPath:NSTemporaryDirectory()).appendingPathComponent("database_name")

    do {
        // Initialize the AWS AppSync configuration
        let appSyncConfig = try AWSAppSyncClientConfiguration(appSyncClientInfo: AWSAppSyncClientInfo(),
          userPoolsAuthProvider: {
            class MyCognitoUserPoolsAuthProvider : AWSCognitoUserPoolsAuthProviderAsync {
                func getLatestAuthToken(_ callback: @escaping (String?, Error?) -> Void) {
                    AWSMobileClient.sharedInstance().getTokens { (tokens, error) in
                        if error != nil {
                            callback(nil, error)
                        } else {
                            callback(tokens?.idToken?.tokenString, nil)
                        }
                    }
                }
            }
            return MyCognitoUserPoolsAuthProvider()}(),
          databaseURL:databaseURL)

        // Initialize the AWS AppSync client
        appSyncClient = try AWSAppSyncClient(appSyncConfig: appSyncConfig)
    } catch {
        print("Error initializing appsync client. \(error)")
    }
}

接下来在ViewController.swift中添加AppSync配置。
请注意以下代码也是一个摘要,所以请不要删除没有提到的行。


import AWSAppSync

class ViewController: UIViewController {
    var appSyncClient: AWSAppSyncClient?

    override func viewDidLoad() {
        super.viewDidLoad()
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        appSyncClient = appDelegate.appSyncClient
     }
}

实现向DynamoDB添加记录的部分

请在ViewController.swift中添加以下函数来实现向DynamoDB中添加记录的部分。


func runMutation(){
        let mutationInput = CreateTodoInput(name: "Use AppSync", description:"Realtime and Offline")
        appSyncClient?.perform(mutation: CreateTodoMutation(input: mutationInput)) { (result, error) in
            if let error = error as? AWSAppSyncClientError {
                print("Error occurred: \(error.localizedDescription )")
            }
            if let resultError = result?.errors {
                print("Error saving the item on server: \(resultError)")
                return
            }
        }
    }

我会简单解释一下上述代码。
CreateTodoInput(name: “Use AppSync”, description:”Realtime and Offline”)
CreateTodoInput是在API.swift文件中定义的一个函数,它是自动生成的一个结构体。
通过使用这个函数,我们可以创建输入参数。
在这个例子中,我们决定创建一个名为“Use AppSync”,描述为“Realtime and Offline”的TODO。

如果appSyncClient不为空,就执行appSyncClient.perform(mutation: CreateTodoMutation(input: mutationInput))这个方法,当执行完后会回调闭包(result, error)。这里也一样,CreateTodoMutation是在API.swift中定义的一个类。当执行appSyncClient.perform方法时,会调用设置在AppSync的createTodo上的resolver,并将数据添加到DynamoDB中。(参见下图)

AWS_AppSync_Console.png
AWS_AppSync_Console.png

让我们将按钮放置并配置为运行runMutation函数。
在Main.storyboard中添加一个名为“向Dynamo添加数据”的按钮,并向ViewController.swift添加一个动作连接。
连接类型为Action,名称设置为pushDataToDynamo。
函数应该类似以下内容。

@IBAction func pushDataToDynamo(_ sender: Any) {
    runMutation()
}

当您点击”向Dynamo添加数据”按钮时,您会发现数据已成功添加到DynamoDB中。页面的布局如下图所示。

iPhone_XR_-_12_1.png

获取DynamoDB数据的实现部分

请按照向 Dynamo 添加数据的步骤,进行添加按钮和修改代码。
在Main.storyboard中添加一个名为“从 Dynamo 获取数据”的按钮,并将其连接到ViewController.swift上的动作。
连接应该是动作,名称设置为getDynamoData。
此外,请添加runQuery函数。

@IBAction func getDynamoData(_ sender: Any) {
    runQuery()
}

func runQuery(){
    appSyncClient?.fetch(query: ListTodosQuery()) {(result, error) in
        if error != nil {
            print(error?.localizedDescription ?? "")
            return
        }
        result?.data?.listTodos?.items!.forEach { print(($0?.name)! + " " + ($0?.description)!) }
    }
}

关于runQuery函数,简单解释一下。
runMutation函数具有相似的结构,但在result?.data?.listTodos?.items!.forEach { print(($0?.name)! + ” ” + ($0?.description)!) }部分,我们编写了一个操作,它将获取的记录的name和description显示在控制台上。

当您启动模拟器并单击“从Dynamo获取数据”按钮时,您会发现数据会显示在控制台上(见下图)。

ViewController_swift.png
DynamoDB_·_AWS_Console.png
iPhone_XR_-_12_1.png

订阅DynamoDB记录添加的部分的实现

实现在 DynamoDB 收到新数据时能够接收该数据的订阅功能。由于可以只接收新添加的数据而不是所有数据,所以可以用于实现发布包括更新信息在内的功能。

依旧进行按钮添加和代码修改。
在Main.storyboard中添加”开始订阅”按钮,并为ViewController.swift添加一个连接。
连接为Action类型,名为startSubscribe。
同时,请添加subscribe函数。

@IBAction func startSubscribe(_ sender: Any) {
    subscribe()
}

var discard: Cancellable?
func subscribe() {
    do {
        discard = try appSyncClient?.subscribe(subscription: OnCreateTodoSubscription(), resultHandler: { (result, transaction, error) in
            if let result = result {
                print(result.data!.onCreateTodo!.name + " " + result.data!.onCreateTodo!.description!)
            } else if let error = error {
                print(error.localizedDescription)
            }
        })
    } catch {
        print("Error starting subscription.")
    }
}

订阅功能与之前的功能具有相同的结构,但订阅的不同之处在于它会在后台持续运行。

iPhone_XR_-_12_1.png

总结

我使用AppSync来解释了如何对DynamoDB进行操作。但是,我省略了关于AppSync和GraphQL的详细说明,所以整篇文章可能不太容易理解。关于AppSync和GraphQL,由于我自己也没有完全理解,我计划在另一篇文章中进行详细解释。

通过AWS Amplify进行iOS应用开发的入门已经在本文中结束。
感谢您的阅读。

bannerAds