使用 SwiftUI 和 GraphQL 克隆 Instagram – 登入
在上一篇关于如何创建Instagram 克隆应用程序的文章中,你了解了如何在 XCode 11 中配置 SwiftUI 启动和运行的一切,并使用 GraphQL 创建了一个完全可用的 Sing Up 视图。
今天,我们将学习如何创建登录视图并让用户注销。
我们需要使用上一篇文章中的项目,所以如果你没有关注那篇文章,我强烈建议你关注一下。
系好安全带,我们出发吧!
为了更好地学习,请下载带源代码的iOS Instagram 克隆项目。
Contents
你想快速入门吗?
从我们的中枢克隆这个应用程序,然后开始使用它,不会有任何麻烦!
创建登录视图
我们的登录视图与注册视图非常相似,甚至更简单。
在登录或登录用户突变中,我们只需要两个参数:用户名和密码:
查询和突变将取决于你选择的 Parse 版本:
Parse 3.7.2:
突变 logInUser($username: String!, $password: String!){ 用户{ 登录(用户名:$username,密码:$password){ 会话令牌 } } }
Parse 3.8:
突变 logInUser($username: String!, $password: String!){ 登录(用户名:$username,密码:$password){ 会话令牌 } }
Parse 3.9:
突变 logInUser($username: String!, $password: String!){ 登录(用户名:$username,密码:$password){ 会话令牌 } }
所以我们只需要向用户询问这些信息。
首先,让我们添加一个新的 SwiftUI 视图,访问文件 > 新建 > 文件,然后选择我们的 SwiftUI 视图
将此视图命名为LogInView.swift,并在项目中打开它:
正如您已经学习过的那样,用我们需要的控件创建 VStack:
- 用户名文本字段
- 密码安全字段
- 用于执行操作的按钮
为了保持设计的一致性,我将我们将要使用的颜色移到了 AppDelegate.swift 中,因此我还必须在这里导入 SwiftUI:
导入 SwiftUI let lightGreyColor = Color(红色:239.0/255.0,绿色:243.0/255.0,蓝色:244.0/255.0,不透明度:1.0) let lightBlueColor = Color(red: 36.0/255.0, green: 158.0/255.0, blue: 235.0/255.0, opacity: 1.0)
记住要删除SignUpView.swift和LogInView.swift 中的颜色线。
此外,为了保持控件的一致性,我复制并粘贴了 SignUp 视图中的内容,删除了电子邮件 TextField,并更改了 TextFields 以反映新的功能。我的代码最终是这样的
struct LogInView:View { @State var username: String = "" @State var password: String = "" @State private var showingAlert = false var body: some View { VStack{ Text("Log In") .font(.largeTitle) .foregroundColor(lightBlueColor) .fontWeight(.semibold) .padding(.bottom, 20) TextField("Username", text: $username) .padding() .background(lightGreyColor) .cornerRadius(5.0) .padding(.bottom, 20) SecureField("Password", text: $password) .padding() .background(lightGreyColor) .cornerRadius(5.0) .padding(.bottom, 20) Button(action:{ }){ Text("Log In!") .font(.headline) .foregroundColor(.white) .padding() .frame(width: 220, height: 60) .background(lightBlueColor) .cornerRadius(15.0) } .padding() } }
这很简单。看看效果如何?
更改 ContentView.swift 以显示该视图:
struct ContentView : View { var body: some View { 登录视图 } }
看起来很整洁!
让我们在顶部添加徽标,使其更加整洁!
我们的徽标由一张图片组成,我们将把这张图片整合到我们的项目中。我使用了这张图片。
将图片拖放到项目中的 Assets.xcassets 文件夹中:
看起来应该是这样的:
从现在起,我们可以在代码中引用它,并将其命名为:logo-social。
现在就注册 Back4App, 开始创建您的 Instagram 克隆应用程序。
我们的徽标
我们的徽标将由该图片组成,但简单地将图片放在那里会显得很业余。我们要让它熠熠生辉:圆形,大小固定,在边框上有一些描边,当然还有阴影,因为……阴影。
代码如下
图像("Logo-social") .resizable() .aspectRatio(contentMode: .fit) .frame(width: 150, height: 150) .clipShape(Circle()) .overlay(Circle().stroke(Color.blue, lineWidth: 2)) .shadow(radius: 5) .padding(.bottom, 75)
然后将其放在 VStack 的顶部:
var body: some View { VStack{ 图片("logo-social") .resizable() .aspectRatio(contentMode: .fit) .frame(width: 150, height: 150) .clipShape(Circle()) .overlay(Circle().stroke(Color.blue, lineWidth: 2)) .shadow(radius: 5) .padding(.bottom, 75) 文本("登录) .font(.largeTitle) .foregroundColor(lightBlueColor) .fontWeight(.semibold) .padding(.bottom, 20) ...
现在,是不是很漂亮?
会话令牌
我们的登录过程将返回一个会话令牌字符串。我们必须保证会话令牌的安全,因为它将在我们的操作过程中使用:当会话令牌有效时,我们就可以访问我们的应用程序。当它被删除或失效时,我们的调用将被拒绝。
由于这与安全直接相关,我们需要安全地存储它。这样做的正确位置是 iOS 的钥匙串。
钥匙串的一个缺点是使用起来既麻烦又无聊,因此我决定使用这个封装器来管理它。它让生活变得简单多了,而且由于我们已经在使用Cocoapods,所以它是完全合理的。
让我们编辑Podfile并将其添加到 pod 中:
pod "SwiftKeychainWrapper
然后使用以下命令更新 Pod
pod install
更新 Pod,最后重新打开xcworkspace项目。
现在,我们可以使用钥匙串引擎…
存储会话令牌
根据我们新 pod 的文档,将值保存到钥匙串的方法是
KeychainWrapper.standard.set("SomeValue", forKey: "SomeKey")
但我们也要为它添加一些逻辑。
首先,让我们导入包装器:
导入 SwiftKeychainWrapper
首先,我们必须调用我们的logInUser变量,当该变量响应时,如果有会话令牌,我们就存储它。如果没有,我们必须发出警报通知用户。
现在,如果你还记得上一篇文章,我们已经编写了一个警报,包括其结构。让我们从SingUpView.swift中移除下面的代码,并将其传递给AppDelegate.swift文件,以便所有视图都能访问它,从而重复使用该代码:
struct Message { var alertTitle:字符串 = "" var alertText:字符串 = "" } var myMessage = Message()
现在,回到我们的逻辑,我们要做的第一件事就是确定用户是否填写了用户名和密码文本框。如果没有,则登录过程中没有任何信息,我们必须通知用户。
我们的登录按钮操作代码应检查这一点。让我们添加这段代码,检查与这些文本框链接的状态变量的字符串大小:
Button(action:{ // 检查是否输入了密码 if (self.password.count == 0 || self.username.count == 0){ // 如果没有,我们必须显示警报 myMessage.alertText = "您必须提供用户名和密码"。 myMessage.alertTitle = "哎呀......" self.showingAlert = true } else { // 如果是,我们可以继续 } }){ Text("Log In!") .font(.headline) .foregroundColor(.white) .padding() .frame(width: 220, height: 60) .background(lightBlueColor) .cornerRadius(15.0) } .alert(isPresented: $showingAlert) { 警报(title:Text(myMessage.alertTitle), message:Text(myMessage.alertText), dismissButton: .default(Text("OK")) }
并进行测试…
很好
现在,我们必须调用 GraphQL 突变,以检索会话令牌,如果有的话,将其存储到钥匙串中。
我们已经学习了如何调用突变,所以现在就开始调用,但这次如果我们获得了 sessionToken,就会将其存储起来:
// 执行 LogInUser 突变,传递我们刚刚从 TextFields 获取的参数 apollo.perform(mutation:LogInUserMutation(username: self.username, password: self.password)){ result in // 让我们切换结果,以便将成功与错误区分开来 switch result { // 在成功的情况下 case .success(let graphQLResult): // 我们尝试Parse结果 if let sessionToken = graphQLResult.data.users.logIn.sessionToken { 我的消息。 myMessage.alertTitle = "耶!" myMessage.alertText = "用户已登录!" self.showingAlert = true print ("User sessionToken " + sessionToken) // 将会话令牌写入我们的钥匙串 让 _:Bool = KeychainWrapper.standard.set(sessionToken, forKey: "Back4Gram.sessionToken") } // 但如果出现任何 GraphQL 错误,我们会显示该消息 else if let errors = graphQLResult.errors { // GraphQL 错误 myMessage.alertTitle = "哎呀!" myMessage.alertText = "我们有一个 GraphQL 错误:" + errors.description self.showingAlert = true print(errors) } // 如果出现故障,我们将显示该信息 case .failure(let error): // 网络或响应格式错误 myMessage.alertTitle = "哎呀!" myMessage.alertText = "我们出错了:" + error.localizedDescription self.showingAlert = true print(error) } }
我们来测试一下!
真不错但我们怎么知道它真的成功了呢?
我们可以进入应用程序的 Parse 控制面板,检查是否写入了新的会话对象:
就像开了挂一样!
既然来了…
添加一个注销按钮如何?只是为了测试,让我们知道一切都很顺利:
Button(action:{ // 检查是否存在会话令牌存储空间Stringhould only log out if logged in. if (KeychainWrapper.standard.string(forKey: "Back4Gram.sessionToken") != nil) { print("Found sessionToken! We can logout.") // 执行注销用户突变 apollo.perform(mutation.LogOutUserMutation)LogOutUserMutation()){ result in // 让我们切换结果,以便将成功与错误区分开来 switch result { // 在成功的情况下 case .success(let graphQLResult): // 我们尝试Parse结果 if let result = graphQLResult.data.users.logOut { if (result) { myMessage.alertTitle = "耶!" myMessage.alertText = "用户已注销!" self.showingAlert = true // 清除存储的会话令牌 让 _:Bool = KeychainWrapper.standard.set("", forKey: "Back4Gram.sessionToken") } else { myMessage.alertTitle = "哎呀!" myMessage.alertText = "用户注销操作返回错误"。 self.showingAlert = true } } // 但如果出现任何 GraphQL 错误,我们将显示该消息 else if let errors = graphQLResult.errors { // GraphQL 错误 myMessage.alertTitle = "哎呀!" myMessage.alertText = "我们有一个 GraphQL 错误:" + errors.description self.showingAlert = true print(errors) } // 如果出现故障,我们将显示该信息 case .failure(let error): // 网络或响应格式错误 myMessage.alertTitle = "哎呀!" myMessage.alertText = "我们出错了:" + error.localizedDescription self.showingAlert = true print(error) } } } else { // 网络或响应格式错误 myMessage.alertTitle = "哎呀!" myMessage.alertText = "用户似乎未登录。" self.showingAlert = true } }){ 文本("注销登录") .font(.headline) .foregroundColor(.white) .padding() .frame(width: 220, height: 60) .background(lightBlueColor) .cornerRadius(15.0) } .alert(isPresented: $showingAlert) { 警报(title:Text(myMessage.alertTitle), message:Text(myMessage.alertText), dismissButton: .default(Text("OK")) }
再次测试一下!
很好!
我们稍后将把注销按钮移到其他地方,但现在,它可以显示我们的流程正在运行。
但是,我们注销后,我们的会话对象怎么样了?
如预期一样,自动消失了!
结论
恭喜你!你现在已经实现了登录和注销功能!不仅如此,你还学会了如何调用不同的突变、验证结果并将值存储到钥匙串中!真是太棒了!
在下一章中,我们将开始使用多视图,并开始构建主视图!
敬请期待!
参考资料
- 本系列的第 1 部分是使用 Swift UI 和 GraphQL 克隆 Instagram。
- 第 2 部分是使用 Swift UI 和 GraphQL 登录 Instagram。
- 第 3 部分是使用 Swift UI 和 GraphQL 查看个人资料。
- 第 4 部分是Instagram 克隆主页视图。
- 下载带有源代码的iOS Instagram克隆项目并开始使用Back4App。
现在就注册Back4App, 开始创建你的Instagram克隆应用程序。
什麼是 SwiftUI?
SwiftUI 是一種為 Apple 平台上的應用程式創建使用者介面的新方法。它允許開發者使用 Swift 程式碼來確定 UI。
什麼是 sessionToken?
我們正在開發的登入流程將會傳回一個 sessionToken 字串。它需要得到保護。如果我們能夠保持 sessionToken 有效,我們將擁有對應用程式的存取權限;否則,我們將失去對應用程式的存取權。這關係到安全性。
什麼是鑰匙圈?
我們知道 sessionToken 與應用程式的安全性息息相關。因此,它需要儲存在一個安全的地方。這個安全的地方叫做鑰匙圈。使用起來可能有點棘手,也可能覺得很無聊。