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.

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

screen-shot-2019-08-26-at-11-08-58

Bu görünüme LogInView.swift adını verelim ve projemizde açalım:

screen-shot-2019-08-28-at-10-54-07

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()
    }
}

screen-shot-2019-08-28-at-11-16-13

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:

screen-shot-2019-08-28-at-13-25-54

Bu şekilde görünmelidir:

screen-shot-2019-08-28-at-13-27-30

Ş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)
...

screen-shot-2019-08-28-at-13-33-41

Ş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…

screen-shot-2019-09-02-at-10-22-15

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!

screen-shot-2019-09-02-at-13-11-02

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:

screen-shot-2019-09-02-at-13-11-34

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!

screen-shot-2019-09-02-at-13-51-50

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?

screen-shot-2019-09-02-at-14-04-31

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

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.


Leave a reply

Your email address will not be published.