From c86fd0c2d1fc7a3cb43c61d640dbf4f5c4b6c40c Mon Sep 17 00:00:00 2001 From: Nick Sarno <44950578+SwiftfulThinking@users.noreply.github.com> Date: Mon, 22 Apr 2024 20:38:08 -0400 Subject: [PATCH 1/2] Update README.md --- README.md | 148 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 127 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 61594a9..ff1c19d 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ Convenience methods to manage Firebase Authentication in Swift projects. - ✅ Sign In With Apple - ✅ Sign In With Google +- ✅ Sign In With Phone ```swift Task { @@ -22,41 +23,61 @@ Task { } ``` -## Usage +Sample project: https://github.com/SwiftfulThinking/SwiftfulFirebasePackagesExample -Import the package to your project. +## Setup + +
+ Details (Click to expand) +
+ +### 1. Import the package to your project. * File -> Swift Packages -> Add Package Dependency * Add URL for this repository: https://github.com/SwiftfulThinking/SwiftfulFirebaseAuth.git -#### Import the package to your file. +### 2. Import the package to your file. ```swift import SwiftfulFirebaseAuth ``` -#### Create one instance of AuthManager for your application. +### 3. Create one instance of AuthManager for your application. ```swift let authManager = AuthManager(configuration: .firebase) + +// Use Mock configuration to avoid running Firebase while developing (ex. for SwiftUI Previews). +let authManager = AuthManager(configuration: .mock) ``` +### 4. Configure your Firebase project. +Add the Firebase SDK to your application and configure() the SDK on launch. -#### Use Mock configuration to avoid running Firebase while developing (ex. for SwiftUI Previews). ```swift -let authManager = AuthManager(configuration: .mock) +@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate +``` +```swift +func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + FirebaseApp.configure() + return true +} ``` -#### Configure your Firebase project. -Add the Firebase SDK to your application and configure() the SDK on launch. +
-##### Sign In With Apple -1. Enable Apple as a Sign-In Method in Firebase Authentication console. -2. Add Sign in with Apple Signing Capability to your Xcode project. +## Sign In With Apple -https://firebase.google.com/docs/auth/ios/apple +
+ Details (Click to expand) +
+Firebase docs: https://firebase.google.com/docs/auth/ios/apple -```swift -try await authManager.signInApple() -``` +### 1. Enable Apple as a Sign-In Method in Firebase Authentication console. +* Firebase Console -> Authentication -> Sign-in method -> Add new provider + +### 2. Add Sign in with Apple Signing Capability to your Xcode project. +* Xcode Project Navigator -> Target -> Signing & Capabilities -> + Capability -> Sign in with Apple (requires Apple Developer Account) + +### 3. Add Apple Button (optional) ```swift SignInWithAppleButtonView( type: .signUp, @@ -66,19 +87,85 @@ SignInWithAppleButtonView( .frame(height: 50) ``` -##### Sign In With Google -1. Enable Apple as a Sign-In Method in Firebase Authentication console & update the info.plist file. -2. Add custom URL scheme (URL Types -> REVERSED_CLIENT_ID) +### 4. Sign in -https://firebase.google.com/docs/auth/ios/google-signin +```swift +try await authManager.signInApple() +``` +
+ + +## Sign In With Google + +
+ Details (Click to expand) +
+ +Firebase docs: https://firebase.google.com/docs/auth/ios/google-signin +### 1. Enable Google as a Sign-In Method in Firebase Authentication console. +* Firebase Console -> Authentication -> Sign-in method -> Add new provider +### 2. Update you app's the info.plist file. +* Firebase Console -> Project Settings -> Your apps -> GoogleService-Info.plist + +### 3. Add custom URL scheme (URL Types -> REVERSED_CLIENT_ID) +* GoogleService-Info.plist -> REVERSED_CLIENT_ID +* Xcode Project Navigator -> Target -> Info -> URL Types -> add REVERSED_CLIENT_ID as URL Schemes value + +### 4. Add Google Button (optional) +```swift +SignInWithGoogleButtonView( + type: .signUp, + style: .black, + cornerRadius: 10 +) +.frame(height: 50) +``` + +### 5. Sign in ```swift let clientId = FirebaseApp.app()?.options.clientId try await authManager.signInGoogle(GIDClientID: clientId) ``` + +
+ +## Sign In With Phone + +
+ Details (Click to expand) +
+ +Firebase docs: https://firebase.google.com/docs/auth/ios/phone-auth + +### 1. Enable Phone Number as a Sign-In Method in Firebase Authentication console. +* Firebase Console -> Authentication -> Sign-in method -> Add new provider + +### 2. Enable APNs notifications (silent push notifications). +* Create an APNs Authentication Key in [Apple Developer Member Center](https://developer.apple.com/membercenter/index.action) (requires Apple Developer Account) +* Certificates, Identifiers & Profiles -> New Key for Apple Push Notifications service (APNs) -> download .p8 file + +### 3. Upload APNs key to Firebase. +* Firebase Console -> Project Settings -> Cloud Messaging -> APNs Authentication Key + +### 4. Enable reCAPTCHA verification (optional?). +* Firebase Console -> Project Settings -> Encoded App ID +* Xcode Project Navigator -> Target -> Info -> URL Types -> add Encoded App ID as URL Schemes value + +### 5. Get the user's phone number +* This SDK does NOT format phone numbers or provide UI for this. You must provide a string in the correct format. +* Phone numbers have to be correctly formatted, such as "+1 650-555-3434" for US numbers. +* See [Firebase Docs](https://firebase.google.com/docs/auth/ios/phone-auth) for details about phone number implementation +* Possible resources for phone number formatting: + - https://stackoverflow.com/questions/32364055/formatting-phone-number-in-swift + - https://github.com/iziz/libPhoneNumber-iOS + - https://github.com/MojtabaHs/iPhoneNumberField + +### 6. Add Google Button (optional) + ```swift -SignInWithGoogleButtonView( +SignInWithPhoneButtonView( type: .signUp, style: .black, cornerRadius: 10 @@ -86,6 +173,24 @@ SignInWithGoogleButtonView( .frame(height: 50) ``` +### 7. Send verification code to user's phone. + +```swift +try await authManager.signInPhone_Start(phoneNumber: phoneNumber) +``` + +### 8. Verify code and sign in +```swift +try await authManager.signInPhone_Verify(code: code) +``` + +
+ +## Already Signed In + +
+ Details (Click to expand) +
#### Synchronously get user's authentication info. ```swift @@ -106,7 +211,6 @@ Task { } ``` - #### Sign out or delete user's authentication. ```swift try authManager.signOut() @@ -115,5 +219,7 @@ try authManager.signOut() try await authManager.deleteAuthentication() ``` +
+ ## Want to contribute? Open a PR! New Sign-In Methods must use Swift Concurrency (async/await). From 9b6cace87d5a65531fac009ce3bb5dbc911dc4b3 Mon Sep 17 00:00:00 2001 From: Nick Date: Mon, 22 Apr 2024 21:03:56 -0400 Subject: [PATCH 2/2] [Feature] Add SignInWithPhoneButtonView --- Package.swift | 2 +- README.md | 16 ++--- .../ASAuthorizationAppleIDButton+EXT.swift | 60 ++++++++++++++++ .../Core/SignInWithAppleButtonView.swift | 6 -- .../Core/SignInWithGoogleButtonView.swift | 62 +++------------- .../Core/SignInWithPhoneButtonView.swift | 70 +++++++++++++++++++ .../GoogleRed.colorset/Contents.json | 20 ++++++ 7 files changed, 163 insertions(+), 73 deletions(-) create mode 100644 Sources/SwiftfulFirebaseAuth/Core/ASAuthorizationAppleIDButton+EXT.swift create mode 100644 Sources/SwiftfulFirebaseAuth/Core/SignInWithPhoneButtonView.swift create mode 100644 Sources/SwiftfulFirebaseAuth/Support/Assets.xcassets/GoogleRed.colorset/Contents.json diff --git a/Package.swift b/Package.swift index 3b5bc6c..7e88719 100644 --- a/Package.swift +++ b/Package.swift @@ -30,7 +30,7 @@ let package = Package( .product(name: "GoogleSignInSwift", package: "GoogleSignIn-iOS") ], resources: [ - .process("Assets") + .process("Support/Assets") ] ), .testTarget( diff --git a/README.md b/README.md index ff1c19d..f20e913 100644 --- a/README.md +++ b/README.md @@ -79,12 +79,8 @@ Firebase docs: https://firebase.google.com/docs/auth/ios/apple ### 3. Add Apple Button (optional) ```swift -SignInWithAppleButtonView( - type: .signUp, - style: .black, - cornerRadius: 10 -) -.frame(height: 50) +SignInWithAppleButtonView() + .frame(height: 50) ``` ### 4. Sign in @@ -115,12 +111,8 @@ Firebase docs: https://firebase.google.com/docs/auth/ios/google-signin ### 4. Add Google Button (optional) ```swift -SignInWithGoogleButtonView( - type: .signUp, - style: .black, - cornerRadius: 10 -) -.frame(height: 50) +SignInWithGoogleButtonView() + .frame(height: 50) ``` ### 5. Sign in diff --git a/Sources/SwiftfulFirebaseAuth/Core/ASAuthorizationAppleIDButton+EXT.swift b/Sources/SwiftfulFirebaseAuth/Core/ASAuthorizationAppleIDButton+EXT.swift new file mode 100644 index 0000000..e635853 --- /dev/null +++ b/Sources/SwiftfulFirebaseAuth/Core/ASAuthorizationAppleIDButton+EXT.swift @@ -0,0 +1,60 @@ +// +// ASAuthorizationAppleIDButton.swift +// +// +// Created by Nick Sarno on 4/22/24. +// + +import Foundation +import SwiftUI +import AuthenticationServices + +extension ASAuthorizationAppleIDButton.Style { + var backgroundColor: Color { + switch self { + case .white: + return .white + case .whiteOutline: + return .white + default: + return .black + } + } + + var foregroundColor: Color { + switch self { + case .white: + return .black + case .whiteOutline: + return .black + default: + return .white + } + } + + var borderColor: Color { + switch self { + case .white: + return .white + case .whiteOutline: + return .black + default: + return .black + } + } +} + +extension ASAuthorizationAppleIDButton.ButtonType { + var buttonText: String { + switch self { + case .signIn: + return "Sign in with" + case .continue: + return "Continue with" + case .signUp: + return "Sign up with" + default: + return "Sign in with" + } + } +} diff --git a/Sources/SwiftfulFirebaseAuth/Core/SignInWithAppleButtonView.swift b/Sources/SwiftfulFirebaseAuth/Core/SignInWithAppleButtonView.swift index a18ad8d..13046ef 100644 --- a/Sources/SwiftfulFirebaseAuth/Core/SignInWithAppleButtonView.swift +++ b/Sources/SwiftfulFirebaseAuth/Core/SignInWithAppleButtonView.swift @@ -63,12 +63,6 @@ private struct SignInWithAppleButtonViewRepresentable: UIViewRepresentable { style: .white, cornerRadius: 30) .frame(height: 50) .background(Color.red) - - SignInWithGoogleButtonView( - type: .signIn, - style: .white, cornerRadius: 30) - .frame(height: 50) - .background(Color.red) } .padding(40) } diff --git a/Sources/SwiftfulFirebaseAuth/Core/SignInWithGoogleButtonView.swift b/Sources/SwiftfulFirebaseAuth/Core/SignInWithGoogleButtonView.swift index c54a394..03afae8 100644 --- a/Sources/SwiftfulFirebaseAuth/Core/SignInWithGoogleButtonView.swift +++ b/Sources/SwiftfulFirebaseAuth/Core/SignInWithGoogleButtonView.swift @@ -9,54 +9,8 @@ import Foundation import SwiftUI import AuthenticationServices -fileprivate extension ASAuthorizationAppleIDButton.Style { - var backgroundColor: Color { - switch self { - case .white: - return .white - case .whiteOutline: - return .white - default: - return .black - } - } - - var foregroundColor: Color { - switch self { - case .white: - return .black - case .whiteOutline: - return .black - default: - return .white - } - } - - var borderColor: Color { - switch self { - case .white: - return .white - case .whiteOutline: - return .black - default: - return .black - } - } -} - -fileprivate extension ASAuthorizationAppleIDButton.ButtonType { - var buttonText: String { - switch self { - case .signIn: - return "Sign in with" - case .continue: - return "Continue with" - case .signUp: - return "Sign up with" - default: - return "Sign in with" - } - } +public extension Color { + static let googleRed = Color("GoogleRed", bundle: Bundle.module) } public struct SignInWithGoogleButtonView: View { @@ -66,7 +20,7 @@ public struct SignInWithGoogleButtonView: View { private var borderColor: Color private var buttonText: String private var cornerRadius: CGFloat - + public init( type: ASAuthorizationAppleIDButton.ButtonType = .signIn, style: ASAuthorizationAppleIDButton.Style = .black, @@ -81,8 +35,8 @@ public struct SignInWithGoogleButtonView: View { public init( type: ASAuthorizationAppleIDButton.ButtonType = .signIn, - backgroundColor: Color = .black, - borderColor: Color = .black, + backgroundColor: Color = .googleRed, + borderColor: Color = .googleRed, foregroundColor: Color = .white, cornerRadius: CGFloat = 10 ) { @@ -102,14 +56,14 @@ public struct SignInWithGoogleButtonView: View { .fill(backgroundColor) .padding(0.8) - HStack(spacing: 6) { + HStack(spacing: 8) { Image("GoogleIcon", bundle: .module) .resizable() .scaledToFit() .frame(width: 16, height: 16) Text("\(buttonText) Google") - .font(.system(size: 20)) + .font(.system(size: 21)) .fontWeight(.medium) } .foregroundColor(foregroundColor) @@ -120,7 +74,7 @@ public struct SignInWithGoogleButtonView: View { } #Preview("SignInWithGoogleButtonView") { - SignInWithGoogleButtonView() + SignInWithGoogleButtonView(backgroundColor: .googleRed) .frame(height: 60) .padding() } diff --git a/Sources/SwiftfulFirebaseAuth/Core/SignInWithPhoneButtonView.swift b/Sources/SwiftfulFirebaseAuth/Core/SignInWithPhoneButtonView.swift new file mode 100644 index 0000000..37e2a3a --- /dev/null +++ b/Sources/SwiftfulFirebaseAuth/Core/SignInWithPhoneButtonView.swift @@ -0,0 +1,70 @@ +// +// SignInWithPhoneButtonView.swift +// +// +// Created by Nick Sarno on 4/22/24. +// + +import SwiftUI +import SwiftUI +import AuthenticationServices + +public struct SignInWithPhoneButtonView: View { + + private var backgroundColor: Color + private var foregroundColor: Color + private var borderColor: Color + private var buttonText: String + private var cornerRadius: CGFloat + + public init( + type: ASAuthorizationAppleIDButton.ButtonType = .signIn, + style: ASAuthorizationAppleIDButton.Style = .black, + cornerRadius: CGFloat = 10 + ) { + self.cornerRadius = cornerRadius + self.backgroundColor = style.backgroundColor + self.foregroundColor = style.foregroundColor + self.borderColor = style.borderColor + self.buttonText = type.buttonText + } + + public var body: some View { + ZStack { + RoundedRectangle(cornerRadius: cornerRadius) + .fill(borderColor) + + RoundedRectangle(cornerRadius: cornerRadius) + .fill(backgroundColor) + .padding(0.8) + + HStack(spacing: 8) { + Image(systemName: "phone.fill") + .resizable() + .scaledToFit() + .frame(width: 16, height: 16) + + Text("\(buttonText) Phone") + .font(.system(size: 21)) + .fontWeight(.medium) + } + .foregroundColor(foregroundColor) + } + .padding(.vertical, 1) + .disabled(true) + } +} + +#Preview("SignInWithGoogleButtonView") { + VStack { + SignInWithAppleButtonView() + .frame(height: 60) + .padding() + SignInWithGoogleButtonView() + .frame(height: 60) + .padding() + SignInWithPhoneButtonView() + .frame(height: 60) + .padding() + } +} diff --git a/Sources/SwiftfulFirebaseAuth/Support/Assets.xcassets/GoogleRed.colorset/Contents.json b/Sources/SwiftfulFirebaseAuth/Support/Assets.xcassets/GoogleRed.colorset/Contents.json new file mode 100644 index 0000000..142de37 --- /dev/null +++ b/Sources/SwiftfulFirebaseAuth/Support/Assets.xcassets/GoogleRed.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x35", + "green" : "0x43", + "red" : "0xEA" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +}