SwiftUIとGraphQLを使ったInstagramクローン – ログイン
Instagramのクローンアプリを作成する方法についての前回の投稿では、XCode 11でSwiftUIを起動して実行するためにすべてを設定する方法を学び、GraphQLを使って完全に動作するSing Upビューを作成しました。
今日は、ログインビューを作成し、ユーザーをログアウトさせる方法を学びます。
前の投稿のプロジェクトが必要になるので、もしその投稿を追ってないなら、追ってみることを強くお勧めします。
シートベルトを締めて、さあ出発だ!
よりよく学ぶために、iOSのInstagramクローンプロジェクトをソースコード付きでダウンロードしよう。
Contents
すぐに始めたいですか?
私たちのハブからこのアプリをクローンして、何の苦労もなく使い始めましょう!
ログイン・ビューの作成
ログイン・ビューは、サインアップ・ビューとよく似ています。
logInUser Mutationでは、ユーザー名とパスワードの2つのパラメータが必要なだけです:
クエリと変異は、選択した Parse のバージョンによって異なります:
Parse 3.7.2:
ミューテーション logInUser($username: String!, $password: String!){ users{ logIn(ユーザー名: $ユーザー名, パスワード: $パスワード){ { logIn(username: $ユーザー名, password: $パスワード) セッション・トークン } } }
Parse 3.8:
mutation logInUser($username: String!, $password: String!){. logIn(username: $ユーザー名, password: $パスワード){。 sessionToken } }
Parse 3.9:
mutation logInUser($username: String!, $password: String!){. logIn(username: $ユーザー名, password: $パスワード){。 sessionToken } }
なので、ユーザーのためにこれらを尋ねる必要があるだけです。
ファイル > 新規 > ファイルで新しいSwiftUIビューを追加し、SwiftUIビューを選択することから始めましょう。
このビューをLogInView.swiftと名付け、プロジェクトに追加して開きましょう:
そして、すでに学んだように、必要なコントロールでVStackを作成します:
- ユーザー名用のテキストフィールド
- パスワード用のSecureField
- アクションを実行するためのボタン
デザインの一貫性を保つために、使用する色をAppDelegate.swiftに移したので、SwiftUIもインポートする必要がありました:
インポートSwiftUI let lightGreyColor = Color(red: 239.0/255.0, green: 243.0/255.0, blue: 244.0/255.0, opacity: 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ビューからコピー&ペーストし、EメールTextFieldを削除し、新しい機能を反映するためにTextFieldsを変更しました。私のコードはこのようになりました:
struct LogInView:ビュー 状態 var username: String = "" 状態 var パスワード: 文字列 = "" 状態 private var showingAlert = false var body: あるビュー {. VStack{ テキスト("ログイン") .font(.largeTitle) .foregroundColor(lightBlueColor) .fontWeight(.semibold) .padding(.bottom, 20) テキストフィールド("ユーザー名", 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:{ }){ テキスト("ログイン!") .font(.headline) .foregroundColor(.white) .padding() .frame(width: 220, height: 60) .background(lightBlueColor) .cornerRadius(15.0) } }.padding() } }
これは簡単だった。どう見えるかな?
ContentView.swiftをそのビューを表示するように変更してみましょう:
構造体 ContentView : View { {. var body: あるView {。 LogInView() } }
すっきりしましたね!
上部にロゴを追加して、よりすっきりさせましょう!
ロゴはプロジェクトに組み込む画像で構成します。私はこれを使いました。
この画像をプロジェクトの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: あるビュー {. 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) ...
さて、美しいでしょう?
sessionToken
ログイン処理はsessionToken文字列を返します。sessionTokenが有効な間は、アプリケーションにアクセスできます。そのsessionTokenが有効な間、私たちはアプリケーションにアクセスできます。そのsessionTokenが削除されたり無効になったりすると、私たちの呼び出しは拒否されます。
これはセキュリティに直接関係するので、安全に保存する必要があります。そのための適切な場所は、iOSのキーチェーンだ。
キーチェーンについてひとつだけ言えることは、使うのが難しくて退屈だということだ。Cocoapodsをすでに使っているので、このラッパーはとても理にかなっている。
Podfileを編集して、これをPodに追加しよう:
ポッド 'SwiftKeychainWrapper'
そして、次のコマンドでPodを更新しましょう。
ポッドインストール
でPodを更新し、最後にxcworkspaceプロジェクトを開き直します。
これで、Keychainエンジンを使用する準備ができました。
sessionTokenを保存する
新しいポッドのドキュメントによると、キーチェーンに値を保存する方法は以下の通りです
KeychainWrapper.standard.set("SomeValue", forKey: "SomeKey")
ですが、これにロジックも追加してみましょう。
手始めに、ラッパーをインポートしましょう:
インポート SwiftKeychainWrapper
まず最初に、logInUserミューテーションを呼び出す必要があり、それが応答するとき、sessionTokenがあればそれを保存します。もしなければ、アラートでユーザーに通知する必要があります。
さて、前回の記事を覚えているのであれば、私たちはすでにアラートの構造を含めてコード化しています。以下のコードをSingUpView.swiftから削除し、AppDelegate.swiftに渡すことで、すべてのビューがアクセスできるようになります:
構造体 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 { // ユーザ名とパスワードを入力してください。 // もしそうなら、次に進む } }){ テキスト("ログイン!") .font(.headline) .foregroundColor(.white) .padding() .frame(width: 220, height: 60) .background(lightBlueColor) .cornerRadius(15.0) } .alert(isPresented: $showingAlert) { { アラート(タイトル: $showingAlert) アラート(title:Text(myMessage.alertTitle), message:テキスト(myMessage.alertText), dismissButton: .default(Text("OK"))) }
そして、それをテストする…
ナイス!
さて、セッショントークンを取得し、もし取得したらKeychainに保存するために、GraphQLミューテーションを呼び出さなければなりません。
ミューテーションを呼び出す方法はすでに学んだので、それを実行しましょう:
// 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 ("ユーザーセッショントークン " + sessionToken) // セッション・トークンをキーチェーンに書き込む let _:Bool = KeychainWrapper.standard.set(sessionToken, forKey: "Back4Gram.sessionToken") } // ただし、GraphQLエラーが発生した場合は、そのメッセージを表示する else if let errors = graphQLResult.errors { // グラフQLエラー。 // 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ダッシュボードに行き、新しいSessionオブジェクトが書き込まれているかどうか確認しましょう:
見事です!
そして、せっかくなので
ログアウトのボタンを追加するのはどうでしょうか?テスト用なので、すべてがスムーズであることを確認しましょう:
Button(action:{ // ログインしている場合のみログアウトします。 if (KeychainWrapper.standard.string(forKey: "Back4Gram.sessionToken") != nil) { // ログインしている場合のみログアウトする。 print("セッション・トークンが見つかりました!ログアウトできます。") // LogOutUser変異を実行する apollo.perform(mutation: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 // 保存されているセッション・トークンをクリアする let _:Bool = KeychainWrapper.standard.set("", forKey: "Back4Gram.sessionToken") } else { {. myMessage.alertTitle = "おっと!" myMessage.alertText = "ユーザー・ログアウト操作がFalseを返しました。" self.showingAlert = true } } // ただし、GraphQLエラーが発生した場合は、そのメッセージを表示します。 else if let errors = graphQLResult.errors { // グラフQLエラー。 // 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) { { アラート(タイトル: $showingAlert) アラート(title:Text(myMessage.alertTitle), message:テキスト(myMessage.alertText), dismissButton: .default(Text("OK"))) }
もう一度、テストしてみよう!
素晴らしい!
ログアウトボタンは、後で別の場所に移動する予定ですが、今のところ、フローが機能していることを示すために機能しています。
しかし、ログアウトしたSessionオブジェクトはどうでしょうか?
予想通り、自動的に消えてしまいました!
結論
おめでとうございます!これでログインとログアウトの機能が実装できました!それだけでなく、さまざまな変異を呼び出し、結果を検証し、Keychainに値を保存する方法を学びました!なんて素晴らしいんでしょう!
次の章では、複数のビューを扱い、メインビューを作り始めます!
ご期待ください!
参考
- このシリーズのパート1は、Swift UIとGraphQLを使ったInstagramクローンです。
- パート2は、Swift UIとGraphQLを使ったInstagramログインです。
- パート3は、Swift UIとGraphQLを使ったProfile Viewです。
- パート4は、Instagramクローンのホームビューです。
- ソースコード付きのiOS Instagramクローンプロジェクトをダウンロードして、Back4Appを使い始めましょう。
今すぐBack4Appにサインアップして、 Instagramクローンアプリの開発を始めましょう。
SwiftUIとは何ですか?
SwiftUIは、Appleプラットフォーム上のアプリケーションのユーザーインターフェースを作成するための新しい方法です。開発者はSwiftコードを使ってUIを決定できます。
sessionTokenとは何ですか?
開発中のログインプロセスは、sessionToken文字列を返します。これはセキュリティ保護が必要です。sessionTokenを有効な状態に維持できればアプリケーションへのアクセスが可能になりますが、そうでない場合はアクセスできなくなります。これはセキュリティに関係します。
キーチェーンとは何ですか?
sessionToken はアプリのセキュリティに関係していることはご存じの通りです。そのため、安全な場所に保存する必要があります。その安全な場所はキーチェーンと呼ばれます。しかし、使い方が少し難しく、退屈に感じることもあるかもしれません。