版本记录
版本号 | 时间 |
---|---|
V1.0 | 2020.11.13 星期五 |
前言
使用
Amazon Web Services(AWS)
为iOS应用构建后端,可以用来学习很多东西。下面我们就一起学习下如何使用Xcode Server
。
开始
首先我们看下主要内容:
了解如何使用
GraphQL
将Amazon Web Services(AWS)
与AWS Amplify
和Cognito
一起为iOS应用构建后端。内容来自翻译。
接着看下写作环境:
Swift 5, iOS 14, Xcode 12
下面就是正文啦
Amazon Web Services(AWS)
是一个云计算平台。为了支持云计算,亚马逊在全球拥有和运营数据中心。它“作为服务”提供各种基础架构和软件产品。例如,您可以使用Amazon EC2
在Amazon
数据中心内保留虚拟服务器。或者,您可以使用Amazon SageMaker
快速轻松地构建和部署机器学习模型。 AWS
提供了近200
种单独的服务,因此无论您对下一个项目有何需求,都可以找到!
在学习本教程的过程中,您将学习如何使用AWS Amplify将身份验证和数据库存储添加到名为Isolation Nation
的聊天应用程序中。
这是高级教程。在开始之前,您应该对Swift
和SwiftUI
有一个很好的了解。您还应该对GraphQL
和CocoaPods
有所了解。如果您需要先完成以上任何一项,请尝试以下教程:
现在开始!
Isolation Nation
是一款针对因COVID-19
而自我隔离的人的应用程序。 它使他们可以向当地社区的其他人寻求帮助。 Isolation Nation
的工作方式是向用户询问其邮政编码(相当于英国的邮政编码),并将其添加到其邮政编码区域(postcode area)
的线程thread
中。 例如,白金汉宫的完整邮政编码为SW1A 1AA
。 邮政编码区域(postcode area)
为SW1A
,它代表此处here显示的区域。
邮政编码在同一区域内的用户被添加到单个线程中。 然后,他们可以发送消息并回复同一区域中的其他人。
打开入门项目。 在Xcode
中打开IsolationNation
入门项目的工作区(不是项目)。
Introduction to the App
构建并运行项目。 该应用程序显示带有单线程项SW1A
的列表。 点击该项目。 该应用程序将导航到该位置的消息列表。
点击任何一条消息,以查看每条消息的答复列表。
该应用程序包含四个主屏幕:Home, Threads, Messages and Replies
。 在Xcode中,您可以在“项目”导航器中看到每个屏幕的分组。 您还可以查看每个屏幕的view model
。 这些不在他们的组中,因此更容易找到。
看一下该项目:
- AppDelegate设置登录用户。
-
SceneDelegate将
RootView
设置为SwiftUI
视图层次结构的根视图。 -
RootView检查是否存在已登录用户,如果存在,则加载
HomeScreen
。 -
HomeScreen加载
ThreadsScreen
。
Threads, Messages and Replies
屏幕均具有相似的结构。每个人都将其view model
用作ObservedObject
来填充其视图。
打开ThreadsScreenViewModel.swift
。视图模型view model
包含一个属性threadListState
,该属性发布包装在Loading
枚举中的ThreadModel
对象数组。在初始化程序之后,perform(action :)
定义一个API
。该API
允许视图将请求发送到视图模型以执行操作。这些动作的处理程序如下。
初次检查时,该应用可能看起来已经正常运行。但是请注意,fetchThreads()
是如何简单地返回一个硬编码列表的。本教程的目的是构建功能齐全的后端并删除所有硬编码数据。
注意:如果使用多个模拟器,则在
Isolation Nation
中测试功能将更加容易。我使用Control Room创建一个与每个用户同名的模拟器。
首先,您需要注册一个AWS
账户并将一些软件安装到您的计算机上。
Setting Up Your Environment
打开浏览器并转到the AWS Homepage。
如果您已经拥有一个AWS
账户,请登录。否则,请单击右上角的Create a AWS account
,然后注册free tier
。 AWS
创建您的帐户后,使用您刚创建的凭证以Root user
用户身份登录。
注意:您需要在注册时提供信用卡。 通过遵循本教程,您应该保持在免费限制之内。 但是,
AWS
可能会对您的产品使用收取少量费用。 完成本教程后,应删除创建的所有资源,以免产生任何其他费用。
现在该安装必备软件了。 打开终端。
首先,请确保您已安装Git
。 它已经预装在每个现代macOS
上,因此应该如此。 在您的终端中,键入以下内容:
git --version
确保您的Git
版本是2.14.1
或更高版本。 如果没有,您可以在这里here安装。
接下来,通过在终端中运行以下命令来检查是否安装了Node v10
或更高版本:
node --version
如果尚未安装,则可以在此处here安装。
最后,如果还没有,请在终端中运行以下命令来安装CocoaPods
:
sudo gem install cocoapods
接下来,您将安装并配置Amplify
。
AWS Amplify
Amplify
包含三个独立但相关的产品:
- 首先,有一个Command Line Interface (CLI),用于代表您的项目以编程方式创建和保留
AWS
资源。AWS
功能强大,但也很复杂。Amplify
使这个变的容易! - 其次,
Amplify
提供了针对几种流行编程环境(包括iOS)的库libraries
。 这些库为常见的应用程序开发用例提供了简化的API。 - 最后,
Amplify
提供了一组有限的UI components
,用于快速建立常见的用户流,例如身份验证。 这些组件当前不适用于iOS。
1. Installing and Configuring Amplify
要开始使用Amplify
,请在终端中键入以下内容以安装CLI
:
npm install -g @aws-amplify/cli amplify-app
-g
标志表示CLI
将在您的计算机上全局安装,而不仅仅是单个项目。
注意:这可能需要几分钟才能完成,有时似乎会挂起。 请耐心等待,它最终会完成。
安装CLI
后,必须对其进行配置,以使其链接到您的AWS
账户。 在终端中运行以下命令:
amplify configure
终端屏幕将要求您登录到您的AWS
账户,然后将打开一个新的浏览器选项卡。 根据CLI
的要求,按Enter
键继续。 按Enter
选择默认的AWS
区域并为Amplify IAM
用户键入用户名:
另一个浏览器选项卡将自动打开。 单击Next: Permissions ▸ Next: Tags ▸ Next: Review ▸ Create user
。
注意:在成功屏幕上,复制您的
Access Key ID
和Secret access key
,并将它们保存在安全的地方。 这很重要,因为关闭此选项卡后无法检索它们! 这些键将使CLI
充当您最近创建的角色。
单击Close
。
返回终端,按照说明添加access key ID
和secret access key
。
最后,创建一个配置文件名称:
恭喜你! 现在在您的计算机上设置了Amplify
。 接下来,将其添加到您的应用中。
2. Adding Amplify to Your App
在Xcode中,打开Podfile
。 在#Pods for IsolationHelp
注释和文件末尾end
之间,添加以下新依赖项:
pod 'Amplify'
pod 'Amplify/Tools'
接下来,在您的终端中,导航到项目目录的根目录。 键入以下内容以在项目中安装依赖项:
pod install --repo-update
Amplify
是主要依赖项。 它为您的应用提供了对所有Amplify API
的访问权限。 Amplify Tools
为Xcode
的构建过程增加了各种自动化,从而使Amplify
的工作更加轻松。
接下来,单击项目工作区中的IsolationNation
项目,然后单击IsolationNation target
。
在Build Phases
选项卡中,单击plus
按钮以添加另一个阶段。 选择New Run Script Phase
。
通过单击Run script
标题,将阶段命名为Amplify Tools
。 单击并将其拖动到Compile Sources
阶段上方。
将Shell
脚本更新为以下内容:
"${PODS_ROOT}/AmplifyTools/amplify-tools.sh"
为确保所有Amplify CLI
工具正常运行,请在终端中输入以下命令:
npm i --package-lock-only
注意:如果您使用
nvm
来管理节点版本,则前面的命令可能是不必要的。
建立您的专案。 构建完成后,项目导航器将具有一个名为AmplifyConfig
的新组。 该文件夹包含包含Amplify
的配置和资源标识符的文件。
接下来,在您的终端中,键入以下内容:
amplify init
按Enter
接受默认项目名称,然后选择None
作为默认编辑器。 当询问您是否要使用配置文件时,键入Y
,然后选择默认default
配置文件。
这将需要一些时间来完成,因为CLI
会为您创建AWS
资源。
接下来,在您的终端中输入以下内容:
amplify console
这将在浏览器中打开Amplify Console
。 如果您收到错误消息,指出您的项目不存在,请确保已选择北弗吉尼亚州(N. Virginia)
地区。
此时,您可能需要环顾控制台以熟悉它。 不过,由于您尚未向应用程序添加任何服务,因此目前看不到什么。
但是,您将把Isolation Nation
变成一个真正的应用程序! 第一步是增加对用户创建帐户和登录的支持。Amazon
为此提供了一项名为Cognito
的服务。 Cognito
有一个User Pool
,该池用作所有用户的目录。 您可以配置User Pool
,以允许用户使用用户名和密码,社交身份提供商(例如Google
或Facebook
)或企业安全系统(例如SAML
)登录。
Configuring AWS Cognito
首先,在Xcode
中打开Podfile
,并在两个现有依赖项之后添加以下依赖项:
pod 'AmplifyPlugins/AWSCognitoAuthPlugin'
接下来,通过在终端中运行以下命令来安装依赖项:
pod install --repo-update
最后,使用Amplify CLI
为您的项目配置Cognito
。 在项目根目录的终端窗口中键入以下命令:
amplify add auth
当CLI
提示您时,选择Default configuration ▸ Username ▸ No, I am done
(每种情况下都是默认选项),然后等待Amplify CLI
完成。
请务必注意,Amplify CLI
现在已在本地为您的项目配置了Cognito
,但尚未将该配置保存到云中。 您可以通过在终端中键入以下内容来确认这一点:
amplify status
这告诉您需要使用给定名称在Auth
类别中创建资源。 在终端中输入以下内容,并在出现提示时进行确认:
amplify push
当询问您是否要为新API
生成代码时,输入N
。
随着Amplify
为您创建AWS
资源,这可能需要几分钟的时间才能完成。
完成后,请返回浏览器中的Amplify Console
。 选择您的应用,然后选择Backend environments
选项卡。
现在,Authentication
类别将出现在您的后端中。
单击Authentication
链接。 然后,在Users
部分中,单击View in Cognito
按钮以查看Cognito User Pool
。
注意:如果
AWS
在屏幕上显示“Region not supported”
,请单击Switch to US East (Virginia)
。
接下来,在左侧菜单中选择App client settings
。 复制客户端ID
并将其保存在某处。 稍后您将需要它。
现在,您的所有设置均已完成。 接下来,是时候将代码添加到您的应用中以处理身份验证了。
Adding Authentication With Amazon Cognito
打开AppDelegate.swift
。 导入UIKit
之后,在文件顶部,为Amplify
添加导入:
import Amplify
import AmplifyPlugins
删除将userSession.loggedInUser
设置为“ Lizzie”
的行。
初始化authenticationService
后,立即添加以下内容:
do {
try Amplify.add(plugin: AWSCognitoAuthPlugin())
try Amplify.configure()
#if DEBUG
Amplify.Logging.logLevel = .debug
#else
Amplify.Logging.logLevel = .error
#endif
} catch {
print("Error initializing Amplify. \(error)")
}
此代码使用Cognito
身份验证插件配置Amplify
库。 然后,它为Amplify设置适当的日志级别。
构建并运行。
不好了! 现在,该应用程序显示一个永无休止的旋转器! 显然,您尚未完成。
1. Completing the Authentication Service
打开AuthenticationService.swift
。 在// MARK: Public API
标记中,您会看到存根函数,其名称类似于signIn(as:identifiedBy :)
和checkAuthSession()
。 现在是时候编写一些使用您的Cognito
后端的代码了。
首先,在文件顶部添加一个新的导入:
import Amplify
接下来,找到空的checkAuthSession()
并添加以下实现:
// 1
_ = Amplify.Auth.fetchAuthSession { [self] result in
switch result {
// 2
case .failure(let error):
logger.logError(error)
signOut()
// 3
case .success(let session):
if !session.isSignedIn {
setUserSessionData(nil)
return
}
// 4
guard let authUser = Amplify.Auth.getCurrentUser() else {
let authError = IsolationNationError.unexpctedAuthResponse
logger.logError(authError)
signOut()
return
}
setUserSessionData(authUser.username)
}
}
此代码的作用如下:
- 1) 向
Amplify
请求当前身份验证会话。 - 2) 如果有错误,请注销用户。
- 3) 成功后,确认用户已登录。
- 4) 如果用户已登录,则获取当前用户并在用户会话上设置详细信息。
构建并运行。 现在,加载旋转器已替换为登录屏幕。
接下来,添加登录代码。 删除signIn(as:identifiedBy:)
中的所有代码,并将其替换为以下内容:
return Future { promise in
// 1
_ = Amplify.Auth
.signIn(username: username, password: password) { [self] result in
switch result {
// 2
case .failure(let error):
logger.logError(error.localizedDescription)
promise(.failure(error))
// 3
case .success:
guard let authUser = Amplify.Auth.getCurrentUser() else {
let authError = IsolationNationError.unexpctedAuthResponse
logger.logError(authError)
signOut()
promise(.failure(authError))
return
}
// 4
setUserSessionData(authUser.username)
}
}
}
这是您正在做的:
- 1) 调用
Amplify
登录API
,并传递用户名和密码。 - 2) 检查并处理失败。
- 3) 成功后,获取当前登录用户。
- 4) 像以前一样,在用户会话中设置用户的详细信息。
通过此设置,用户可以登录到您的应用程序!
但是,只有一个问题:您没有任何现有用户,并且仍然没有注册的方法。 是时候解决这个问题了。
用以下内容替换signUp(as:identifiedBy:with :)
的正文:
return Future { promise in
// 1
let userAttributes = [AuthUserAttribute(.email, value: email)]
let options = AuthSignUpRequest.Options(userAttributes: userAttributes)
// 2
_ = Amplify.Auth.signUp(
username: username,
password: password,
options: options
) { [self] result in
DispatchQueue.main.async {
switch result {
case .failure(let error):
logger.logError(error.localizedDescription)
promise(.failure(error))
case .success(let amplifyResult):
// 3
if case .confirmUser = amplifyResult.nextStep {
promise(.success(.awaitingConfirmation(username, password)))
} else {
let error = IsolationNationError.unexpctedAuthResponse
logger.logError(error.localizedDescription)
promise(.failure(error))
}
}
}
}
}
在此代码中,您将执行以下操作:
- 1) 配置注册请求以期望通过电子邮件注册。
- 2) 使用
Amplify
执行注册。 您可以像前面的示例一样处理结果。 - 3) 如果注册成功,则返回
awaitingConfirmation
状态。Amplify
将通过电子邮件向用户发送代码,以确认所提供地址的所有权。
接下来,您需要允许用户确认其电子邮件地址。 用以下内容替换confirmSignUp(for:with:confirmedBy :)
的内容:
return Future { promise in
// 1
_ = Amplify.Auth.confirmSignUp(
for: username,
confirmationCode: confirmationCode
) { [self] result in
switch result {
case .failure(let error):
logger.logError(error.localizedDescription)
promise(.failure(error))
case .success:
// 2
_ = Amplify.Auth.signIn(
username: username,
password: password
) { result in
switch result {
case .failure(let error):
logger.logError(error.localizedDescription)
promise(.failure(error))
case .success:
// 3
checkAuthSession()
}
}
}
}
}
在此代码中,您验证用户:
- 1) 使用
Amplify
确认注册并以通常的方式处理响应。 - 2) 成功后,请登录用户。
- 3) 调用
checkAuthSession()
,它设置用户会话。
更新signOut()
以使用户退出Cognito
并清除其用户会话。 将用户会话(user session)
设置为nil
后,添加以下代码:
_ = Amplify.Auth.signOut { [self] result in
switch result {
case .failure(let error):
logger.logError(error)
default:
break
}
}
最后,打开AppDelegate.swift
。 在return true
之前,将以下内容添加到application(_:didFinishLaunchingWithOptions :)
的底部:
// Listen to auth changes
_ = Amplify.Hub.listen(to: .auth) { payload in
switch payload.eventName {
case HubPayload.EventName.Auth.sessionExpired:
authenticationService.checkAuthSession()
default:
break
}
}
默认情况下,从Cognito
返回的身份验证令牌会在一个小时后过期。 但是您可以扩展它而无需要求用户再次登录。 这就是这里发生的事情。
构建并运行。 这次,点击Sign Up
按钮,然后使用用户名,电子邮件地址和密码进行注册。
注意:大多数电子邮件提供商都会允许您为每个电子邮件地址添加无限数量的后缀。 例如,如果您的电子邮件地址为
example @ gmail.com
,example + lizzie @ gmail.com
也将路由到您的收件箱。 这是生成测试电子邮件地址的好方法。
注意:默认的
Cognito
用户池设置的密码策略为8个字符或更多。
AWS
将通过电子邮件将确认码发送到您提供的地址。 到达后,输入并点击Confirm
。
恭喜你! 您已成功登录该应用程序。现在,使用同一用户注销并重新登录,以验证您的代码是否正常运行。
接下来,确认您的用户现在出现在云中。 在浏览器中,转到以前的Cognito
选项卡。 单击左侧菜单中的Users and groups
选项。 从列表中选择您的用户(一个用户)。
找到sub field
并将其保存在某处。稍后您将需要它。
GraphQL, AppSync and DynamoDB
在您的应用程序中提供登录功能是一个好的开始。但是大多数产品还需要用户修改和保存数据的方法。对于许多现代应用程序,此数据需要其他用户访问。解决此问题的常见方法是将数据持久存储在云中某处服务器上存储的数据库中。
AWS
提供了许多不同的database services,每种服务都有其自身的优势和取舍。在本教程中,您将使用文档数据库DynamoDB。使用DynamoDB
,您无需预先定义架构。此功能可帮助您快速为您的应用制作原型或迭代新想法。
许多移动应用程序使用一种通用的架构模式,其中业务和安全逻辑驻留在后端服务器中。该应用程序通过GraphQL
或REST
等网络API
与服务器通信。服务器将保存,检索或更新数据库中的记录。
AppSync
是一项AWS
服务,可使用您的GraphQL schema
自动生成数据库和后端。您在GraphQL schema
中定义模型对象,然后AppSync
为后端生成代码。然后,它部署运行后端所需的服务。并创建保存数据所需的DynamoDB
表。
Adding a GraphQL API
返回Xcode
,打开Podfile
并添加以下依赖项:
pod 'AmplifyPlugins/AWSAPIPlugin'
AWSAPIPlugin
将对AppSync
的Amplify
库添加了支持。 通过从命令行运行以下命令来更新工作空间:
pod install --repo-update
您要添加的第一个模型对象是一个User
对象。 通常,Cognito
处理用户数据。 但是Cognito
的数据是个人专有的。 并且,在Isolation Nation
应用程序中,用户必须能够看到彼此的数据,例如用户名。 因此,此应用需要用户模型以及Cognito
数据。
1. Defining Your Schema
在Xcode
中,打开AmplifyConfig
组中的schema.graphql
。 将内容替换为以下内容:
# 1
type User
# 4
@model
{
# 2
id: ID!
username: String!
# 3
sub: String!
postcode: String
createdAt: AWSDateTime!
}
这是您正在做的事情:
- 1) 您声明一个
User
类型。 - 2) 您可以将用户类型的各种字段定义为
code: Type
元组。例如,id
字段的类型为ID
,而postcode
字段的类型为String
。!
运算符表示必须输入类型。 - 3)
sub
字段将包含Cognito的sub
记录。这是用户的唯一标识符。 - 4) 您使用
@model
指令注释user
类型。
如果您熟悉GraphQL
,则其中的大部分看起来都很简单。但是,AppSync
有一些独特之处。
AppSync
使用directives
来提供声明性API,该API可让您指定希望AppSync
配置每种类型或字段的方式。在此示例中,您指定您的用户类型是model
。这向AppSync
指示应为此类型创建DynamoDB
表。
注意:
AppSync
大量使用 GraphQL Directives。您可以在此处找到指令的完整列表。
早先在项目中添加Amplify Tools
作为依赖项时,Amplify
代表您创建了一个API。但是,这是在向项目添加身份验证之前。您的API
对您刚创建的Cognito
用户池一无所知。在继续之前,您需要修复该问题。
2. Generating the Database
在您的终端中,运行以下命令:
amplify api update
出现提示时,选择GraphQL ▸ Update auth settings ▸ Amazon Cognito User Pool
,然后选择N
。
接下来,打开amplifytools.xcconfig
。 通过添加代码来覆盖选项:
push=true
modelgen=true
profile=default
envName=dev
在这里,您指示Amplify Tools
脚本采取以下操作:
- 在运行时将更改推送到云。
- 在
Swift
中为您的@model
类型生成模型。 - 使用默认的
AWS
配置文件和之前创建的开发环境。
在Xcode中构建您的项目。 如果您打开Report
导航器,则会看到Amplify Tools
脚本现在正在代表您生成Swift
模型。
此构建将花费很长时间! 这是因为脚本还正在运行amplify push
,以在云中生成所有必需的资源。
构建完成后,打开“项目”导航器。 确认已将新组添加到您的项目中,并且该组包含为User
模型生成的模型文件。
在浏览器中,返回到Amplify Console
并重新加载页面。 选择Backend environments
,然后单击API
链接。
在“ API”页面上,请注意“数据源”部分下添加了UserTable
。 单击View in AppSync
按钮。
在AppSync
页面上,打开Run a query
,然后单击Run a query
按钮。
这将打开一个GraphQL Playground
,允许您针对GraphQL API
运行实时查询和变异。 单击Login with User Pools
按钮,然后使用您先前复制的Client ID
和为用户创建的凭据登录。 按Login
。
3. Writing Data
接下来,您将创建一个User
模型。 首先,如果Explorer
窗格已打开,请单击“ X”
将其关闭。现在,在最左侧的窗格中,添加以下代码,将用户名用作username
,并将先前复制的sub
用作id
和sub
字段:
mutation CreateUserMutation {
createUser(input:{
id: "389b0b66-f0e3-4907-9b4e-01ac4146bb0b"
username: "Lizzie",
sub: "389b0b66-f0e3-4907-9b4e-01ac4146bb0b",
}) {
id
username
sub
createdAt
}
}
不幸的是,您无法在GraphQL
代码中添加注释。 以下行号是指以下屏幕截图中的行号。
- 在第
1
行,您定义了一个名为CreateUserMutation
的命名突变。 - 在第
2-5
行中,您运行GraphQL schema
中AppSync
生成的createUser
变异。 变异采用一个称为input
的单个参数。 此参数包含您要创建的username and sub
。 - 第
6-9
行定义了对改变的响应。 您指定id
,username
,
sub
和createdAt
应该在响应中返回。 这些是已创建用户的所有字段。
现在,按下橙色的Play
按钮以运行改变并创建您的用户。
您的改变将发送到您的AppSync GraphQL
服务器,并且响应将显示在中间列中。
接下来,在左侧菜单中选择Data Sources
。 然后为您的UserTable
选择DynamoDB Resource
。
您的浏览器将打开一个新tab
。 您将看到新的DynamoDB
数据库表。 选择Items tab
。
Items tab
显示单个记录。 这是您刚创建的用户。 现在,单击记录ID
链接以为您的用户打开数据库记录。
恭喜你! 您刚刚在DynamoDB
中成功创建了第一个数据库记录。
Reading and Writing AppSync Data From Swift
在Playground
中运行GraphQL
改变很有趣-但没有从您的应用程序中运行它们有趣!
切换回Xcode
并打开AppDelegate.swift
。 在调用Amplify.configure()
之前,添加以下行:
try Amplify.add(plugin: AWSAPIPlugin(modelRegistration: AmplifyModels()))
这告诉Amplify
库通过API
插件添加对AppSync
的支持,并注册从GraphQL
模式创建的模型。 当前,这只是您的User
模型。
Reading Data From AppSync
此时,UserSession
对象只是代表用户名的字符串。 在下一部分中,您将更新应用,以从User
模型中检索用户数据。 您将使用AppSync
读取DynamoDB
数据库。 这将需要大量的重构,因此在本节介绍的过程中,如果您看到Xcode错误,请不要担心。
打开UserSession.swift
并更新loggingInUser
的两个类型声明。 从String?
更改为User?
:
public final class UserSession: ObservableObject {
@Published var loaded = false
// Here
@Published var loggedInUser: User? {
didSet {
loaded = true
}
}
init() {}
// Here
init(loggedInUser: User?) {
self.loggedInUser = loggedInUser
}
}
接下来,打开AuthenticationService.swift
。 在setUserSessionData(_ :)
之后添加以下方法:
private func fetchUserModel(id: String) -> Future<User, Error> {
// 1
return Future { promise in
// 2
_ = Amplify.API.query(request: .get(User.self, byId: id)) { [self] event in
// 3
switch event {
case .failure(let error):
logger.logError(error.localizedDescription)
promise(.failure(error))
return
case .success(let result):
// 4
switch result {
case .failure(let resultError):
logger.logError(resultError.localizedDescription)
promise(.failure(resultError))
return
case .success(let user):
// 5
guard let user = user else {
let error = IsolationNationError.unexpectedGraphQLData
logger.logError(error.localizedDescription)
promise(.failure(error))
return
}
promise(.success(user))
}
}
}
}
}
乍一看可能看起来有些吓人,但实际上并没有太多:
- 1) 首先,此函数返回一个
Future
,它向成功完成回调中提供User
。 - 2) 您使用
Amplify API
来运行查询。 该查询将通过其ID
检索User
对象。 - 3) 该API将事件监听器关闭作为其最终参数。 您使用网络请求的结果发出调用,该请求可以成功也可以失败。 失败时,在返回失败之前记录错误。
- 4) 如果网络请求成功,则检查基础的
GraphQL
结果类型。 这仍然可能导致失败,例如无效请求,因此必须再次检查错误。 - 5) 如果一切成功,则确认您已收到
ID
的有效用户。 如果是这样,则将其退回。
现在,更新setUserSessionData(_ :)
以使用一个User
而不是一个String
:
private func setUserSessionData(_ user: User?) {
DispatchQueue.main.async {
if let user = user {
self.userSession.loggedInUser = user
} else {
self.userSession.loggedInUser = nil
}
}
}
然后,在checkAuthSession()
中,将对setUserSessionData(authUser.username)
的调用替换为以下内容:
let sub = authUser.userId
cancellable = fetchUserModel(id: sub)
.sink(receiveCompletion: { completion in
switch completion {
case .failure(let error):
logger.logError(error)
signOut()
case .finished: ()
}
}, receiveValue: { user in
setUserSessionData(user)
})
此代码调用您刚刚编写的fetchUserModel(id :)
方法。 成功后,它将设置与用户的用户会话。
同样,在signIn(as:identifiedBy :)
中,将对setUserSessionData(_ :)
的调用替换为以下内容:
cancellable = self.fetchUserModel(id: authUser.userId)
.sink(receiveCompletion: { completion in
switch completion {
case .failure(let error):
signOut()
promise(.failure(error))
case .finished: ()
}
}, receiveValue: { user in
setUserSessionData(user)
promise(.success(.signedIn))
})
最后,打开RootView.swift
。 在第62
行中更新HomeScreenViewModel
初始化程序以使用新的UserModel
:
model: HomeScreenViewModel(
userID: loggedInUser.sub,
username: loggedInUser.username)
构建并运行。 如果您尚未登录,请立即登录。 确认该应用程序仍将您带到Locations
屏幕。
用户界面中没有任何变化。 但是您的应用程序现在正在使用AppSync
从DynamoDB
数据库中查询正确的用户User
模型!
注意:如果您感到好奇,可以通过嗅探应用程序中的
HTTP
流量来证明您正在从数据库中检索用户。 您可以使用像 Charles Proxy这样的工具。
Creating Data in DynamoDB
之前,您通过在GraphQL playground
上运行一个改变在DynamoDB
中创建了一个新的User
记录。 您为您的一位用户硬编码了信息。 显然,这不是一个好的长期解决方案! 相反,您应该使用Amplify.API
。 您现在就进行更改。
打开AuthenticationService.swift
并在confirmSignUp(for:with:confirmedBy :)
中找到成功处理程序。 删除对checkAuthSession()
的调用,并将其替换为以下内容:
// 1
guard let authUser = Amplify.Auth.getCurrentUser() else {
let authError = IsolationNationError.unexpctedAuthResponse
logger.logError(authError)
promise(.failure(IsolationNationError.unexpctedAuthResponse))
signOut()
return
}
// 2
let sub = authUser.userId
let user = User(
id: sub,
username: username,
sub: sub,
postcode: nil,
createdAt: Temporal.DateTime.now()
)
// 3
_ = Amplify.API.mutate(request: .create(user)) { event in
switch event {
// 4
case .failure(let error):
signOut()
promise(.failure(error))
case .success(let result):
switch result {
case .failure(let error):
signOut()
promise(.failure(error))
case .success(let user):
// 5
setUserSessionData(user)
promise(.success(.signedIn))
}
}
}
这是您的代码的作用:
- 1) 首先,您可以从
Amplify Auth API
获取当前用户。 如果没有用户登录,则返回错误并退出。 - 2) 您创建一个新的
User
模型对象,为您的用户设置username
。 您可以将Cognito
的id
和sub
都设置为userId
。 - 3) 然后,通过使用
create
请求类型调用Amplify.API.mutate API
,将此用户模型记录写入DynamoDB
。 - 4) 如前面的示例一样,您可以从网络层处理失败,然后从
GraphQL
层处理故障。 - 5) 最后,将用户会话设置为新创建的用户并返回成功的登录。
在不同的模拟器上构建并运行该应用程序。 注册为新用户。 通过刷新浏览器的DynamoDB
选项卡中的表,确认新用户记录出现在DynamoDB
中。
您可以参考Amplify Framework Documentation,以了解有关通过Amplify
可用的AWS
服务的更多信息。 或查看本教程的第2部分, Using AWS as a Back End: The Data Store & Analytics。 在其中,您将学习如何使用DataStore API通过实时更新和用户分析来构建其余的Isolation Nation
聊天应用程序。
注意:不要忘记删除您创建的
AWS
资源以避免收费。
后记
本篇主要讲述了
Xcode Server
的安装和配置,感兴趣的给个赞或者关注~~~