SwiftUI ve GraphQL kullanan bir Instagram klonu – Giriş
Instagram klon uygulamasının nasıl oluşturulacağına ilişkin bir önceki yazımızda, XCode 11’de SwiftUI’nin çalışır durumda olması için her şeyi nasıl yapılandıracağınızı öğrendiniz ve GraphQL ile tamamen çalışan bir Sing Up görünümü oluşturdunuz.
Bugün bir oturum açma görünümünün nasıl oluşturulacağını ve kullanıcının oturumu nasıl kapatacağını öğreneceğiz.
Bir önceki yazıdaki projeye ihtiyacımız olacak, bu yüzden onu takip etmediyseniz, yapmanızı şiddetle tavsiye ederim.
Kemerlerinizi bağlayın ve başlayalım!
Daha iyi öğrenmek için iOS Instagram Clone projesini kaynak koduyla birlikte indirin.
Contents
Hızlı bir başlangıç mı istiyorsunuz?
Bu Uygulamayı Hub’ ımızdan klonlayın ve herhangi bir güçlük çekmeden kullanmaya başlayın!
Giriş görünümünü oluşturma
Login görünümümüz SignUp görünümümüze oldukça benzeyecek, hatta aslında daha basit olacak.
LogInUser Mutation’da sadece iki parametreye ihtiyacımız var: kullanıcı adı ve şifre:
Sorgular ve mutasyonlar seçtiğiniz Parse sürümüne bağlı olacaktır:
Parse 3.7.2:
mutation logInUser($kullanıcıadı: String!, $parola: String!){ kullanıcılar{ logIn(username: $kullanıcıadı, password: $parola){ sessionToken } } }
Parse 3.8:
mutasyon logInUser($kullanıcıadı: String!, $parola: String!){ logIn(username: $kullanıcıadı, password: $parola){ sessionToken } }
Parse 3.9:
mutasyon logInUser($kullanıcıadı: String!, $parola: String!){ logIn(username: $kullanıcıadı, password: $parola){ sessionToken } }
Bu yüzden kullanıcılarımız için sadece bunları sormamız gerekecek.
Yeni bir SwiftUI Görünümü ekleyerek başlayalım ve Dosya > Yeni > Dosya yolunu izleyerek SwiftUI Görünümümüzü seçelim
Bu görünüme LogInView.swift adını verelim ve projemizde açalım:
Ve daha önce öğrendiğiniz gibi, VStack’inizi ihtiyaç duyacağımız kontrollerle oluşturun:
- Kullanıcı adı için TextField
- Parola için SecureField
- Eylemi gerçekleştirmek için düğme
Tasarımı tutarlı tutmak için, kullanacağımız renkleri AppDelegate.swift dosyasına taşıdım, bu yüzden SwiftUI’yi de oraya import etmem gerekti:
import SwiftUI lightGreyColor = Color(red: 239.0/255.0, green: 243.0/255.0, blue: 244.0/255.0, opacity: 1.0) lightBlueColor = Renk(kırmızı: 36.0/255.0, yeşil: 158.0/255.0, mavi: 235.0/255.0, opaklık: 1.0)
SignUpView.swift ve LogInView.swift‘ten renk çizgilerini kaldırmayı unutmayın.
Ayrıca, kontrollerin tutarlılığını korumak için SignUp görünümümüzden kopyalayıp yapıştırdım ve e-posta TextField’ını kaldırdım ve TextField’ları yeni işlevleri yansıtacak şekilde değiştirdim. Kodum şu şekilde sonuçlandı:
struct LogInView: Görüntüle { @State var kullanıcı adı: String = "" @State var password: String = "" @State private var showingAlert = false var body: some View { VStack{ Text("Giriş Yap") .font(.largeTitle) .foregroundColor(lightBlueColor) .fontWeight(.semibold) .padding(.bottom, 20) TextField("Kullanıcı Adı", text: $kullanıcıadı) .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("Giriş Yapın!") .font(.headline) .foregroundColor(.white) .padding() .frame(genişlik: 220, yükseklik: 60) .background(lightBlueColor) .cornerRadius(15.0) } }.padding() } }
Bu basitti. Bakalım nasıl görünecek?
ContentView.swift dosyanızı bunun yerine bu görünümü gösterecek şekilde değiştirin:
struct ContentView : View { var body: some View { LogInView() } }
Düzgün görünüyor!
En üste logomuzu ekleyerek daha düzenli hale getirelim!
Logomuz projemize entegre edeceğimiz bir görselden oluşacak. Ben bunu kullandım.
Bu görseli projedeki Assets.xcassets klasörünüze sürükleyip bırakın:
Bu şekilde görünmelidir:
Şu andan itibaren kodumuza şu isimle referans verebiliriz: logo-social.
Back4App’a şimdi kaydolun ve Instagram Klon Uygulamanızı oluşturmaya başlayın.
Bizim Logomuz
Logomuz bu görselden oluşacak ancak sadece görseli oraya koymak amatör görünecektir. Onu parlatacağız: dairesel, sabit boyutlu, kenarlarında biraz kontur ve tabii ki damla gölge çünkü… damla gölge.
Tüm bunlar için kod şöyle görünür:
Image("logo-social") .resizable() .aspectRatio(contentMode: .fit) .frame(genişlik: 150, yükseklik: 150) .clipShape(Circle()) .overlay(Circle().stroke(Color.blue, lineWidth: 2)) .shadow(radius: 5) .padding(.bottom, 75)
Ve VStack’imizin en üstüne gider:
var body: some View { VStack{ Image("logo-social") .resizable() .aspectRatio(contentMode: .fit) .frame(genişlik: 150, yükseklik: 150) .clipShape(Circle()) .overlay(Circle().stroke(Color.blue, lineWidth: 2)) .shadow(radius: 5) .padding(.bottom, 75) Text("Giriş Yap") .font(.largeTitle) .foregroundColor(lightBlueColor) .fontWeight(.semibold) .padding(.bottom, 20) ...
Şimdi, ne kadar güzel değil mi?
SessionToken
Oturum açma işlemimiz bir sessionToken dizesi döndürecektir. İşlemlerimiz sırasında kullanılacağı için bu sessionToken’ı güvende tutmalıyız: sessionToken geçerli olduğu sürece uygulamamıza erişimimiz olacaktır. Silindiğinde veya geçersiz kılındığında, çağrılarımız reddedilecektir.
Bu doğrudan güvenlikle ilgili olduğundan, onu güvenli bir şekilde saklamamız gerekecektir. Bunu yapmak için doğru yer iOS’taki Anahtar Zinciridir.
Anahtar Zinciri ile ilgili tek şey, kullanımının zor ve sıkıcı olmasıdır, bu yüzden onu yönetmek için bu sarmalayıcıyı kullanmaya karar verdim. Hayatı çok daha kolay hale getiriyor ve zaten Cocoapods kullandığımız için çok mantıklı.
Podfile ‘ımızı düzenleyelim ve bunu pod’larımıza ekleyelim:
pod 'SwiftKeychainWrapper'
sonra Pod’larımızı şu komutla güncelleyelim
pod kurulumu
ve son olarak, xcworkspace projemizi yeniden açın.
Artık Anahtar Zinciri motorumuzu kullanmak için hazırız…
SessionToken’ı saklayın
Yeni podumuzun belgelerine göre, bir değeri anahtar zincirine kaydetmenin yolu şudur
KeychainWrapper.standard.set("SomeValue", forKey: "SomeKey")
ama buna biraz mantık da ekleyelim.
Başlamak için sarmalayıcımızı içe aktaralım:
import SwiftKeychainWrapper
İlk olarak, logInUser mutasyonumuzu çağırmamız gerekecek ve bu yanıt verdiğinde, varsa sessionToken’ı saklayacağız. Eğer yoksa, kullanıcıyı bir uyarı ile bilgilendirmemiz gerekir.
Şimdi, önceki makalemizde hatırlarsanız, yapısı da dahil olmak üzere kodlanmış bir uyarımız zaten var. Aşağıdaki kodu SingUpView.swift dosyamızdan kaldırarak ve AppDelegate . swift dosyamıza aktararak bunu yeniden kullanalım, böylece tüm görünümler buna erişebilir:
struct Message { var alertTitle: String = "" var alertText: String = "" } var myMessage = Message()
Şimdi, mantığımıza geri dönersek, yapmamız gereken ilk şey kullanıcının kullanıcı adı ve şifre metin kutularını doldurup doldurmadığını belirlemektir. Eğer doldurmadıysa, giriş işlemi için herhangi bir bilgi yoktur ve kullanıcıyı bu konuda bilgilendirmeliyiz.
Giriş düğmesi için eylem kodumuz bunu kontrol etmelidir. Bu metin alanlarına bağlı durum değişkenlerinin dize boyutunu kontrol eden bu kod parçasını buraya ekleyelim:
Button(action: { // Yazılan bir Parola olup olmadığını kontrol et if (self.password.count == 0 || self.username.count == 0){ // Eğer değilse, Uyarıyı göstermeliyiz myMessage.alertText = "Bir Kullanıcı Adı ve Parola sağlamalısınız." myMessage.alertTitle = "Oops..." self.showingAlert = true } else { // Eğer öyleyse, devam edebiliriz } }){ Text("Giriş Yapın!") .font(.headline) .foregroundColor(.white) .padding() .frame(genişlik: 220, yükseklik: 60) .background(lightBlueColor) .cornerRadius(15.0) } .alert(isPresented: $showingAlert) { Alert(title: Text(myMessage.alertTitle), message: Text(myMessage.alertText), dismissButton: .default(Text("OK")) }
ve test et…
Güzel!
Şimdi sessionToken’ı almak ve eğer alırsak Anahtar Zincirinde saklamak için GraphQL mutasyonumuzu çağırmalıyız.
Mutasyonları nasıl çağıracağınızı zaten öğrendiniz, o halde yapalım, ancak bu sefer sessionToken’ı alırsak, onu saklayacağız:
// TextField'larımızdan aldığımız parametreleri geçirerek LogInUser mutasyonunu gerçekleştirin apollo.perform(mutation: LogInUserMutation(username: self.username, password: self.password)){ result in // Başarılı bir sonucu hatadan ayırabilmek için sonucu değiştirelim switch sonuç { // Başarı durumunda case .success(let graphQLResult): // Sonucumuzu Parse çalışıyoruz if let sessionToken = graphQLResult.data?.users?.logIn.sessionToken { myMessage.alertTitle = "Yaşasın!" myMessage.alertText = "Kullanıcı oturum açtı!" self.showingAlert = true print ("Kullanıcı sessionToken " + sessionToken) // sessionToken'ı Anahtar Zincirimize yazın let _: Bool = KeychainWrapper.standard.set(sessionToken, forKey: "Back4Gram.sessionToken") } // ancak herhangi bir GraphQL hatası durumunda bu mesajı gösteriyoruz else if let errors = graphQLResult.errors { // GraphQL hataları myMessage.alertTitle = "Oops!" myMessage.alertText = "Bir GraphQL hatası aldık: " + errors.description self.showingAlert = true print(hatalar) } // Başarısızlık durumunda, bu mesajı sunarız case .failure(let error): // Ağ veya yanıt biçimi hataları myMessage.alertTitle = "Oops!" myMessage.alertText = "Bir hata aldık: " + error.localizedDescription self.showingAlert = true print(hata) } }
Hadi test edelim!
Güzel! Ama gerçekten çalıştığını nasıl bileceğiz?
Uygulamamızın Parse Dashboard’una gidebilir ve yeni bir Session nesnesi yazılıp yazılmadığını kontrol edebiliriz:
Tam isabet!
Ve madem buradayız…
Oturumu kapatmak için bir düğme eklemeye ne dersiniz? Sadece test etmek için, böylece her şeyin sorunsuz olduğunu biliriz:
Button(action: { // sessionToken deposu olup olmadığını kontrol edinStringsadece oturum açılmışsa oturumu kapatmalıdır. if (KeychainWrapper.standard.string(forKey: "Back4Gram.sessionToken") != nil) { print("SessionToken bulundu! Oturumu kapatabiliriz.") // LogOutUser mutasyonunu gerçekleştirin apollo.perform(mutation: LogOutUserMutation()){ içinde sonuç // Başarılı bir sonucu hatadan ayırabilmek için sonucu değiştirelim switch sonuç { // Başarı durumunda case .success(let graphQLResult): // Sonucumuzu Parse çalışıyoruz if let result = graphQLResult.data?.users?.logOut { eğer (sonuç) { myMessage.alertTitle = "Yaşasın!" myMessage.alertText = "Kullanıcı oturumu kapattı!" self.showingAlert = true // Saklanan sessionToken'ı temizleyin let _: Bool = KeychainWrapper.standard.set("", forKey: "Back4Gram.sessionToken") } else { myMessage.alertTitle = "Oops!" myMessage.alertText = "Kullanıcı oturumu kapatma işlemi False döndürdü." self.showingAlert = true } } // ancak herhangi bir GraphQL hatası durumunda bu mesajı sunuyoruz else if let errors = graphQLResult.errors { // GraphQL hataları myMessage.alertTitle = "Oops!" myMessage.alertText = "Bir GraphQL hatası aldık: " + errors.description self.showingAlert = true print(hatalar) } // Başarısızlık durumunda, bu mesajı sunarız case .failure(let error): // Ağ veya yanıt biçimi hataları myMessage.alertTitle = "Oops!" myMessage.alertText = "Bir hata aldık: " + error.localizedDescription self.showingAlert = true print(hata) } } } else { // Ağ veya yanıt biçimi hataları myMessage.alertTitle = "Oops!" myMessage.alertText = "Kullanıcı oturum açmış gibi görünmüyor." self.showingAlert = true } }){ Text("Oturumu Kapat") .font(.headline) .foregroundColor(.white) .padding() .frame(genişlik: 220, yükseklik: 60) .background(lightBlueColor) .cornerRadius(15.0) } .alert(isPresented: $showingAlert) { Alert(title: Text(myMessage.alertTitle), message: Text(myMessage.alertText), dismissButton: .default(Text("OK")) }
Bir kez daha test edelim!
Güzel!
Bu Oturumu Kapat düğmesini daha sonra başka bir yere taşıyacağız, ancak şimdilik akışımızın çalıştığını göstermek için işe yarıyor.
Peki ya çıkış yaptığımıza göre Session nesnemiz ne olacak?
Beklendiği gibi otomatik olarak gitti!
Sonuç
Tebrikler! Artık giriş ve çıkış işlevlerini uygulayabilirsiniz! Sadece bu da değil, farklı mutasyonları nasıl çağıracağınızı, sonuçları nasıl doğrulayacağınızı ve değerleri Anahtar Zinciri’nde nasıl saklayacağınızı öğrendiniz! Ne kadar da harika!
Bir sonraki bölümde, birden fazla görünümle çalışmaya ve ana görünümümüzü oluşturmaya başlayacağız!
Bizi izlemeye devam edin!
Referans
- Bu serinin 1. Bölümü Swift UI ve GraphQL kullanarak Instagram Clone.
- Bölüm 2 Swift UI ve GraphQL Kullanarak Instagram Girişi.
- Bölüm 3 Swift UI ve GraphQL Kullanarak Profil Görünümü.
- Bölüm 4 Instagram Klon Ana Sayfa Görünümü.
- Kaynak kodlu bir iOS Instagram Clone projesini indirin ve Back4App’ı kullanmaya başlayın.
Back4App’a şimdi kaydolun ve Instagram Clone Uygulamanızı oluşturmaya başlayın.
SwiftUI nedir?
SwiftUI, Apple platformlarındaki uygulamalar için kullanıcı arayüzleri oluşturmanın yeni bir yoludur. Geliştiricilerin Swift kodunu kullanarak kullanıcı arayüzünü belirlemesine olanak tanır.
sessionToken nedir?
Geliştirdiğimiz oturum açma işlemi bir sessionToken dizesi döndürecektir. Güvence altına alınması gerekir. sessionToken’ı geçerli tutabilirsek uygulamaya erişimimiz olur, aksi takdirde uygulamaya erişimimizi kaybederiz. Bu güvenlikle ilgilidir.
Anahtarlık Nedir?
sessionToken’ın uygulamanızın güvenliğiyle ilgili olduğunu biliyoruz. Bu nedenle güvenli bir yerde saklanması gerekir. Bu güvenli yere anahtarlık denir. Kullanımı biraz zor olabilir ve aynı zamanda sıkıcı da gelebilir.