요렇게 프로젝트 만들어주면 된다!
Crashlytics나 DynamicLinks 같은 기능들은 첨 알았다!
나머지는 비우고 등록해줘도 됨
구글 인포 plist받아주고! (이 때 이름 그대로 유지하는 게 중요함)
그리고 프로젝트에 드래그해서 추가
닉은 CocoaPod을 사용했는데
나는 SPM을 사용해볼거
패키지 설치할 때 엄청 많은 리스트들이 뜨는데 추후에 추가해줄 수도 있으니까 필요해보이는 것만 우선 체크하고 사용합시다
그리고 초기화 코드가 필요함
import SwiftUI
import FirebaseCore
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
FirebaseApp.configure()
return true
}
}
@main
struct YourApp: App {
// register app delegate for Firebase setup
@UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
var body: some Scene {
WindowGroup {
NavigationView {
ContentView()
}
}
}
}
AppDelegate연결해줄 수도 있고
AppDelegate 없이 그냥 init구문안에서 FirebaseApp.configure()해도 된다!
Firebase의 Authentication탭을 들어간다
사용 설정 on으로 바꾼다
엑코로와서 Targets의 Signing 추가!
이렇게 하고 파이어베이스 콘솔로 돌아와서 애플 로그인 저장!
이 코드 복사해줘야함
그러고 나서 엑코에서 swift파일 하나 만들어주자!
싱글톤 객체 하나 instance로 만들어주고 아까 복사한 코드 붙여넣기!
이 두개 복사해서 똑같이 붙여넣어준다
AuthenticationService 임포트 해주고 Delegate 프로토콜 채택!
그리고 한군데 피나던 곳 UIKit쪽에서 쓰는 거라서 코멘트 아웃!
그리고 여기 3번에 메소드 두개 복사!
코드 밑에 추가해줌
Auth 임포트해주고
이 부분은 안 쓸거라 지워주고
이 두메소드가 컴플리션임 하나는 성공했을 때 다른 하나는 실패했을 때
요 줄은 didCompleteWith 메소드에 따로 추가해줌
오케이! 여기까지 하면 우선은 끝!
signOut같은 건 나중에 추가하자
온보딩뷰로 돌아와서
Button에 금방 작성한 메소드 추가해줌!
요호오오오오옹
캬~
로그인 실패했을 때 (혹은 캔슬했을 때) 알럿이 뜨게 만들어 줍시다
온보딩뷰에서 알럿 추가는 해줬는데
SignInWithApple에서 값이 넘겨져서 와야겠죠
다시 온보딩뷰로 돌아와서
로그인하다 캔슬했을 때 알럿 뜨는 거 확인!
엑코로 돌아와서 reversed_Client_id 구글info.plist에 있는 거 복사하고
앱 info섹션에 URL Types로 추가해준다
GoogleSignIn sdk를 추가해줘야함
이런 SDK 사용하게 되면 specific한 UI를 바로 가져올 수 있음
요런 걸 구현해줘야할 텐데 버튼 만드는 것부터 차근차근 해봅시다
닉 유튭보고 이렇게 만들어주다가 MainActor나오는 거보고 다시 Udemy로 돌아옴.
근데 이거
요부분에서 에러 나서 다시 유튭으로... ㅋㅋ
SignInGoogle 메소드 만들어주려면 뷰컨트롤러가 필요한데
Utilites로 topViewController찾는 메소드 만들어줌
호우... 이거 유튜브껄로 첨부터 들어야겠음
AuthenticationManager 만들어줬다!
캬~
리팩토링
import Foundation
import GoogleSignIn
import GoogleSignInSwift
struct GoogleSignInResultModel {
let idToken: String
let accessToken: String
}
final class SignInGoogleHelper {
@MainActor
func signIn() async throws -> GoogleSignInResultModel {
guard let topVC = Utilities.shared.topViewController() else {
throw URLError(.cannotFindHost)
}
let gidSignInResult = try await GIDSignIn.sharedInstance.signIn(withPresenting: topVC)
guard let idToken: String = gidSignInResult.user.idToken?.tokenString else {
throw URLError(.badServerResponse)
}
let accessToken: String = gidSignInResult.user.accessToken.tokenString
let tokens = GoogleSignInResultModel(idToken: idToken, accessToken: accessToken)
return tokens
}
}
이렇게 기본으로 제공하는 걸로 애플로그인 버튼을 만들 수도 있지만 못하는 게 많아서 커스텀해서 쓰던 이전것을 사용해야함!
AuthenticationManager랑
SignInHelper들이랑
AuthenticationViewModel 복사해서 사용하면 된다..!
그리고 버튼들 로직 안에 try await viewModel.signIn 후에 원하는 로직 사용하면 됨
테스트모드로
Storage도 만들어주고!
import Foundation
import FirebaseStorage //holds images and videos
import UIKit
class ImageManager {
//MARK: - Properties
static let instance = ImageManager()
private var REF_STOR = Storage.storage()
//MARK: - Public Functions
// Functions we call from other places in the app
func uploadProfileImage(userID: String, image: UIImage) {
// Get the path where we will save the image
let path = getProfileImagePath(userID: userID)
// Save image to path
uploadImage(path: path, image: image) { _ in }
}
//MARK: - Private Functions
// Functions we call from this file only
private func getProfileImagePath(userID: String) -> StorageReference {
let userPath = "users/\(userID)/profile"
let storatePath = REF_STOR.reference(withPath: userPath)
return storatePath
}
private func uploadImage(path: StorageReference, image: UIImage, handler: @escaping (_ success: Bool) -> ()) {
var compression: CGFloat = 1.0 // Loops down by 0.05
let maxFileSize: Int = 240 * 240 // Maximum file size that we want to save
let maxCompression: CGFloat = 0.05 // Maximum compression we ever allow
// Get image data
guard var originalData = image.jpegData(compressionQuality: compression) else {
print("Error getting data from image")
handler(false)
return
}
// Check maximum file size
while (originalData.count > maxFileSize) && (compression > maxCompression) {
compression -= 0.05
if let comperssedData = image.jpegData(compressionQuality: compression) {
originalData = comperssedData
}
print(compression)
}
// Get image data
guard let finalData = image.jpegData(compressionQuality: compression) else {
print("Error getting data from image")
handler(false)
return
}
// Get photo metadata
let metadata = StorageMetadata()
metadata.contentType = "image/jpeg"
// Save data to path
path.putData(finalData, metadata: metadata) { (_, error) in
if let error = error {
// Error
print("Error uploading image. \(error)")
handler(false)
return
} else {
// Success
print("Success uploading image")
handler(true)
return
}
}
}
}
Image를 업로드하는 ImageManager를 싱글톤으로 만들어줌
그리고 적당한 파일크기가 될때까지 compression을 줄여주는 로직도 만들어줌!
loginUserToApp
userInfo에 대한 정보를 가져올 때 UserDefaults로 저장되게끔 해줌
키 같은 경우 하드코딩 하는 것보다는 따로 빼서 관리해주는 게 편하겠죠
핸들러가 True가 되고 나서 실행되게끔 하려고 DispatchQueue에 딜레이를 줌
프로필을 만드는 과정에서 방금작성해줬던 메소드들의 성공 실패에 따라 결과가 달라지게 해주고
dismiss() 도 딜레이를 줬다!
근데 지금 onboardingView도 켜져있는 상황이잖음
.fullScreenCover에서 onDismiss일 때 처리를 해줍시다
그니까 fullScreenCover로 띄웠던 뷰가 Dismiss될 때 로직이 일어나게됨
마지막으로
콘텐트뷰에 있던 기존의 currentUserID를 UserDefaults로 저장된 값으로 바꿔줍니다