استنساخ Instagram باستخدام SwiftUI و GraphQL – تسجيل الدخول
في منشورنا السابق حول كيفية إنشاء تطبيق مستنسخ من Instagram، تعلمت كيفية تهيئة كل شيء لتشغيل SwiftUI في XCode 11، وإنشاء طريقة عرض Sing Up تعمل بشكل كامل باستخدام GraphQL.
اليوم سنتعلم كيفية إنشاء طريقة عرض تسجيل الدخول وجعل المستخدم يسجل الخروج.
سنحتاج إلى المشروع من المنشور السابق، لذا إذا لم تكن قد تابعت ذلك المنشور، أقترح عليك بشدة أن تفعل ذلك.
اربطوا أحزمة الأمان وهيا بنا!
لتعلم أفضل، قم بتنزيل مشروع iOS Instagram Clone مع التعليمات البرمجية المصدرية.
Contents
هل تريد بداية سريعة؟
استنسخ هذا التطبيق من مركزنا وابدأ باستخدامه دون أي متاعب!
إنشاء طريقة عرض تسجيل الدخول
ستكون طريقة عرض تسجيل الدخول مشابهة تمامًا لطريقة عرض تسجيل الدخول، بل أبسط في الواقع.
في أو طفرة تسجيل الدخول أو طفرة المستخدم نحتاج فقط إلى معلمتين: اسم المستخدم وكلمة المرور:
ستعتمد الاستعلامات والطفرات على إصدار Parse الذي اخترته:
Parse 3.7.2:
طفرة logInUser($ اسم المستخدم: سلسلة!, $ كلمة المرور: سلسلة!) { المستخدمين{ تسجيل الدخول(اسم المستخدم: $username: $username، كلمة المرور: $password){ { رمز الجلسة } } }
Parse 3.8:
طفرة logInUser($ اسم المستخدم: سلسلة!, $ كلمة المرور: سلسلة!) { { تسجيل الدخول(اسم المستخدم: $ اسم المستخدم، كلمة المرور: $ كلمة المرور){ { رمز الجلسة } }
Parse 3.9:
طفرة logInUser($ اسم المستخدم: سلسلة!, $ كلمة المرور: سلسلة!) { { تسجيل الدخول(اسم المستخدم: $ اسم المستخدم، كلمة المرور: $ كلمة المرور){ { رمز الجلسة } }
لذا سنحتاج فقط أن نطلب ذلك فقط لمستخدمينا.
لنبدأ بإضافة طريقة عرض SwiftUI جديدة بالذهاب إلى ملف > جديد > ملف واختيار طريقة عرض SwiftUI الخاصة بنا
دعنا نسمي طريقة العرض هذه LogInView.swift ونضيفها مفتوحة في مشروعنا:
وكما تعلمت بالفعل، قم بإنشاء VStack الخاص بك مع عناصر التحكم التي سنحتاجها:
- حقل النص لاسم المستخدم
- حقل آمن لكلمة المرور
- زر لتنفيذ الإجراء
للحفاظ على اتساق التصميم، قمت بنقل الألوان التي سنستخدمها إلى AppDelegate.swift، لذا كان علي استيراد SwiftUI هناك أيضًا:
استيراد SwiftUI دع لون LightGreyColor = اللون (أحمر: 239.0/255.0، أخضر: 243.0/255.0، أزرق: 244.0/255.0، عتامة: 1.0) دعونا LightBlueColor = اللون(أحمر: 36.0/255.0، أخضر: 158.0/255.0، أزرق: 235.0/255.0، التعتيم: 1.0)
تذكر أن تزيل خطوط الألوان من SignUpView.swift و LogInView.swift.
أيضًا، من أجل الحفاظ على اتساق عناصر التحكم، قمت بنسخ ولصق من طريقة عرض SignUp وإزالة حقل نص البريد الإلكتروني وتغيير حقول النص TextFields لتعكس الوظائف الجديدة. انتهت شيفرتي على هذا النحو
هيكلة LogInView: عرض { @State var اسم المستخدم: سلسلة = "" @State var password: String = "" @الحالة متغير خاص إظهار تنبيه = خطأ متغير الجسم: عرض ما { VStack{ نص("تسجيل الدخول") .font(.largeTitle) .foregroundColor(lightBlueColor) .fontWeight(.semibold) .الحشو(.سفلي، 20) حقل النص("اسم المستخدم"، النص: اسم المستخدم $) .الحشو() .خلفية(لون رمادي فاتح) .cornerRadius (5.0) .الحشو(.سفلي، 20) حقل آمن("كلمة المرور"، النص: $ كلمة المرور) .الحشو() .خلفية(لون رمادي فاتح) .cornerRadius(5.0) .حشوة(.أسفل، 20) زر(إجراء: { }){ نص("تسجيل الدخول!") .font(.headline) .ForegroundColor(.white) .الحشو() .إطار(العرض: 220، الارتفاع: 60) .خلفية(لون أزرق فاتح) .cornerRadius(15.0) } }.padding() } }
كان هذا بسيطًا. لنرى كيف يبدو؟
قم بتغيير ContentView.swift الخاص بك لإظهار هذا العرض بدلاً من ذلك:
بنية ContentView : عرض { متغير الجسم: طريقة عرض ما { تسجيل الدخول إلى طريقة العرض() } }
يبدو أنيقًا!
لنجعلها أكثر أناقة بإضافة شعارنا في الأعلى!
سيتكون شعارنا من صورة سندمجها في مشروعنا. لقد استخدمت هذه الصورة.
اسحب هذه الصورة وأسقطها إلى مجلد Assets.xcassets في المشروع:
يجب أن تبدو هكذا:
من الآن فصاعدًا يمكننا الإشارة إليها في شفرتنا بهذا الاسم: شعار-اجتماعي.
سجِّل الآن في Back4App وابدأ في إنشاء تطبيقك المستنسخ من Instagram.
شعارنا
سيتألف شعارنا من تلك الصورة ولكن مجرد وضع الصورة هناك سيبدو هاوياً. سنجعله متألقاً: دائرياً، بحجم ثابت، مع بعض الخطوط على الحدود، وبالطبع، ظل مسقط بسبب… ظل مسقط.
الكود لكل ذلك يبدو هكذا
صورة("شعار-اجتماعي") قابل للتحجيم() .aspectRatio(وضع المحتوى: .fit) .إطار(العرض: 150، الارتفاع: 150) .clipShape(دائرة())) .overlay(Circle().stroke(Color.blue, lineWidth: 2)) .ظل(نصف القطر: 5) .الحشو(.سفلي، 75)
ويوضع في أعلى VStack الخاص بنا:
متغير الجسم: بعض منظر ما { VStack{ صورة("شعار-اجتماعي") قابل لتغيير الحجم() .aspectRatio(وضع المحتوى: .fit) .إطار(العرض: 150، الارتفاع: 150) .clipShape(دائرة())) .overlay(Circle().stroke(Color.blue, lineWidth: 2)) .ظل(نصف القطر: 5) .الحشو(.سفلي، 75) نص("تسجيل الدخول") .font(.largeTitle) .ForegroundColor(lightBlueColor) .fontWeight(.semibold) .padding(.bottom, 20) ...
أليس هذا جميلاً؟
رمز الجلسة
ستُعيد عملية تسجيل الدخول الخاصة بنا سلسلة رمز الجلسة. يجب أن نحافظ على رمز الجلسة هذا آمنًا حيث سيتم استخدامه أثناء عملياتنا: عندما يكون رمز الجلسة هذا صالحًا، سيكون لدينا حق الوصول إلى تطبيقنا. عندما يتم حذفه أو إبطاله، سيتم رفض مكالماتنا.
بما أن هذا مرتبط مباشرة بالأمان، سنحتاج إلى تخزينه بشكل آمن. المكان الصحيح للقيام بذلك هو سلسلة المفاتيح على نظام iOS.
الشيء الوحيد في سلسلة المفاتيح هو أن استخدامها صعب وممل، لذا قررت استخدام هذا الغلاف لإدارتها. إنه يجعل الحياة أسهل بكثير، وبما أننا نستخدم بالفعل Cocoapods، فمن المنطقي تمامًا.
دعونا نعدل ملف Podfile الخاص بنا ونضيف هذا إلى البودات الخاصة بنا:
جراب 'SwiftKeychainWrapper'
ثم لنقم بتحديث البودات الخاصة بنا باستخدام الأمر
تثبيت البودات
وأخيرًا، أعد فتح مشروع xcworkspace الخاص بنا.
نحن الآن جاهزون لاستخدام محرك سلسلة المفاتيح لـ
تخزين رمز الجلسة
وفقًا لوثائق جرابنا الجديد، فإن طريقة حفظ قيمة في سلسلة المفاتيح هي
KeychainWrapper.standard.set("SomeValue", forKey: "SomeKey")
ولكن دعنا نضيف بعض المنطق إليها أيضًا.
لنبدأ، دعنا نستورد الغلاف الخاص بنا:
استيراد SwiftKeyKeychainWrapper
أول شيء هو أنه سيتعين علينا استدعاء طفرة logInUser وعندما يستجيب ذلك، نقوم بتخزين رمز الجلسة إذا كان هناك واحد. إذا لم يكن كذلك، فعلينا إخطار المستخدم بتنبيه.
الآن، إذا كنت تتذكر في مقالنا السابق، لدينا بالفعل تنبيه مشفر بما في ذلك بنيته. دعنا نعيد استخدام ذلك عن طريق إزالة الشيفرة أدناه من SingUpView.swift وتمريرها إلى ملف AppDelegate.swift الخاص بنا حتى تتمكن جميع طرق العرض من الوصول إليه:
بنية الرسالة { var alertTitle: سلسلة = "" var alertText: سلسلة = "" } var myMessage = رسالة()
الآن، بالعودة إلى منطقنا، أول شيء علينا القيام به هو تحديد ما إذا كان المستخدم قد ملأ مربعي اسم المستخدم وكلمة المرور. إذا لم يكن كذلك، فلا توجد معلومات لعملية تسجيل الدخول ويجب علينا إخطار المستخدم بذلك.
يجب أن يتحقق رمز الإجراء الخاص بنا لزر تسجيل الدخول من ذلك. دعنا نضيف هذه القطعة من الشيفرة التي تتحقق من حجم سلسلة متغيرات الحالة المرتبطة بتلك الخانات النصية:
زر(الإجراء: { // تحقق مما إذا كانت هناك كلمة مرور مكتوبة إذا (self.password.count.count = = 0 || || self.username.count = = 0){ // إذا لم يكن كذلك، يجب إظهار التنبيه myMessage.alertText = "يجب عليك تقديم اسم مستخدم وكلمة مرور." myMessage.alertTitle = "عفوًا..." self.showAlert = صحيح } آخر { // إذا كان الأمر كذلك، يمكننا المتابعة } }){ نص("تسجيل الدخول!") .font(.headline) .ForegroundColor(.white) .الحشو() .إطار (العرض: 220، الارتفاع: 60) .خلفية(لون أزرق فاتح) .cornerRadius(15.0) } .تنبيه(isPresented: $showingAlert) { تنبيه(العنوان: نص(myMessage.alertTitle)، رسالة: نص (نص(myMessage.alertText)، زر الفصل: .افتراضي (نص("موافق"))) }
واختباره…
رائع!
الآن يجب علينا استدعاء طفرة GraphQL من أجل استرداد رمز الجلسة، وإذا حصلنا على أي منها، فسنخزنها في سلسلة المفاتيح.
لقد تعلمت بالفعل كيفية استدعاء الطفرات لذا دعنا نفعل ذلك، ولكن هذه المرة إذا حصلنا على رمز الجلسة، سنقوم بتخزينه:
// تنفيذ طفرة LogInUser، مع تمرير المعلمات التي حصلنا عليها للتو من TextFields apollo.perform(طفرة: LogInUserMutation(اسم المستخدم: username: self.username، كلمة المرور: self.password)){ النتيجة في // دعنا نبدل النتيجة حتى نتمكن من فصل النتيجة الناجحة عن الخطأ تبديل النتيجة { // في حالة النجاح حالة .نجاح(دعنا نبدل النتيجة GraphQLResult): // نحاول Parse النتيجة إذا دعنا ندع رمز الجلسة = graphQLResult.data.data?.users?.logIn.sessionToken { myMessage.alertTitle = "نعم!" myMessage.alertText = "سجل المستخدم الدخول!" self.showAlert = صحيح طباعة ("الرمز المميز لجلسة المستخدم " + رمز الجلسة" + رمز الجلسة) // اكتب رمز الجلسة إلى سلسلة المفاتيح الخاصة بنا دع _: Bool = KeychainWrapper.standard.set.set(رمز الجلسة، forKey: "Back4Gram.sessionToken") } // ولكن في حالة وجود أي أخطاء GraphQL نقدم تلك الرسالة وإلا إذا تركنا الأخطاء = أخطاء GraphQLResult.errors { // أخطاء GraphQL myMessage.alertTitle = "عفوًا!" myMessage.alertText = "لدينا خطأ GraphQL: " + errors.description.mistakes.mistakes.description ذاتي.showAlert = صحيح طباعة(أخطاء) } // في حالة الفشل، نقدم هذه الرسالة حالة .فشل(دع الخطأ): // أخطاء الشبكة أو أخطاء تنسيق الاستجابة myMessage.alertTitle = "عفوًا!" myMessage.alertText = "لدينا خطأ: " + error.error.localizedDescription ذاتي.showAlert = صحيح طباعة(خطأ) } }
لنختبرها!
رائع! ولكن كيف نعرف أنها نجحت بالفعل؟
يمكننا الانتقال إلى لوحة تحكم Parse Dashboard في تطبيقنا والتحقق مما إذا كان هناك كائن جلسة عمل جديدة مكتوبة:
مثل السحر!
وبما أننا هنا…
ماذا عن إضافة زر لتسجيل الخروج؟ فقط للاختبار حتى نعرف أن كل شيء سلس:
زر(إجراء: { // تحقق مما إذا كان هناك مخزن رمز الجلسة يجب تسجيل الخروج فقط في حالة تسجيل الدخول. إذا (إذا (KeychainWrapper.standard.string.string(forKey: "Back4Gram.sessionToken") != لا شيء) { { طباعة ("تم العثور على رمز الجلسة! يمكننا تسجيل الخروج.") // تنفيذ طفرة LogOutUser apollo.perform(طفرة: LogOutUutUserMutation())) { النتيجة في // لنبدل النتيجة حتى نتمكن من فصل النتيجة الناجحة عن الخطأ تبديل النتيجة { // في حالة النجاح حالة .نجاح(دعنا نبدل النتيجة GraphQLResult): // نحاول Parse النتيجة إذا تركنا النتيجة = graphQLResult.data?.users?.logOut { إذا (النتيجة) { myMessage.alertTitle = "نعم!" myMessage.alertText = "تم تسجيل خروج المستخدم!" ذاتي.showAlert = صحيح // مسح رمز الجلسة المخزن دع _: Bool = KeychainWrapper.standard.set("، forKey: "Back4Gram.sessionToken") غير ذلك {} { myMessage.alertTitle = "عفوًا!" myMessage.alertText = "تم إرجاع عملية تسجيل خروج المستخدم خطأ." ذاتي.showAlert = صحيح } } // ولكن في حالة وجود أي أخطاء في GraphQL نقدم تلك الرسالة وإلا إذا تركنا الأخطاء = أخطاء GraphQLResult.errors { // أخطاء GraphQL myMessage.alertTitle = "عفوًا!" myMessage.alertText = "لدينا خطأ GraphQL: " + errors.description.mistakes.mistakes.description ذاتي.showAlert = صحيح طباعة(أخطاء) } // في حالة الفشل، نقدم هذه الرسالة حالة .فشل(دع الخطأ): // أخطاء الشبكة أو أخطاء تنسيق الاستجابة myMessage.alertTitle = "عفوًا!" myMessage.alertText = "لدينا خطأ: " + error.error.localizedDescription ذاتي.showAlert = صحيح طباعة(خطأ) } } أخرى } } { // أخطاء في الشبكة أو تنسيق الاستجابة myMessage.alertTitle = "عفوًا!" myMessage.alertText = "يبدو أن المستخدم لم يقم بتسجيل الدخول." self.showAlert = صحيح } }){ نص("تسجيل الخروج") .font(.headline) .ForegroundColor(.white) .الحشو() .الإطار(العرض: 220، الارتفاع: 60) .خلفية(لون أزرق فاتح) .cornerRadius(15.0) } .تنبيه(isPresented: $showingAlert) { تنبيه(العنوان: نص(myMessage.alertTitle)، رسالة: نص (نص(myMessage.alertText)، زر الفصل: .افتراضي (نص("موافق"))) }
مرة أخرى، دعنا نختبرها!
رائع!
سنقوم بنقل زر تسجيل الخروج هذا إلى مكان آخر لاحقًا، ولكن في الوقت الحالي، فهو يعمل لإظهار أن تدفقنا يعمل.
ولكن ماذا عن كائن الجلسة الآن بعد أن سجلنا الخروج؟
اختفى تلقائيًا، كما هو متوقع!
خاتمة
تهانينا! لقد نفذت الآن وظائف تسجيل الدخول وتسجيل الخروج! ليس هذا فقط ولكنك تعلمت كيفية استدعاء طفرات مختلفة والتحقق من صحة النتائج وتخزين القيم في سلسلة المفاتيح! كم هذا رائع!
في الفصل التالي سنبدأ العمل مع طرق العرض المتعددة ونبدأ في بناء طريقة العرض الرئيسية!
ترقبوا ذلك!
المرجع
- الجزء 1 من هذه السلسلة هو Instagram Clone باستخدام Swift UI و GraphQL.
- الجزء 2 هو تسجيل الدخول إلى Instagram باستخدام Swift UI و GraphQL.
- الجزء 3 هو عرض الملف الشخصي باستخدام Swift UI و GraphQL.
- الجزء 4 هو Instagram Clone Home View.
- قم بتنزيل مشروع استنساخ Instagram iOS مع شفرة المصدر وابدأ في استخدام Back4App.
اشترك الآن في Back4App وابدأ في إنشاء تطبيق Instagram Clone الخاص بك.
ما هو SwiftUI؟
SwiftUI هي طريقة جديدة لإنشاء واجهات مستخدم للتطبيقات على منصات Apple. تتيح للمطورين تحديد واجهة المستخدم باستخدام شفرة Swift.
ما هو sessionToken؟
عملية تسجيل الدخول التي نطورها ستعيد سلسلة رموز جلسة. يجب تأمينها. إذا حافظنا على صلاحية رمز الجلسة، سنتمكن من الوصول إلى التطبيق، وإلا سنفقده. الأمر يتعلق بالأمان.
ما هي سلسلة المفاتيح؟
نعلم أن رمز الجلسة مرتبط بأمان تطبيقك. لذا، يجب تخزينه في مكان آمن. يُسمى هذا المكان الآمن “سلسلة المفاتيح”. قد يكون استخدامه صعبًا بعض الشيء، وقد يكون مملًا.