diff --git a/Examples/Examples.xcodeproj/project.pbxproj b/Examples/Examples.xcodeproj/project.pbxproj index 9eaca694..a0146207 100644 --- a/Examples/Examples.xcodeproj/project.pbxproj +++ b/Examples/Examples.xcodeproj/project.pbxproj @@ -28,6 +28,8 @@ 7956406A2955AFBD0088A06F /* ErrorText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 795640692955AFBD0088A06F /* ErrorText.swift */; }; 7956406D2955B3500088A06F /* SwiftUINavigation in Frameworks */ = {isa = PBXBuildFile; productRef = 7956406C2955B3500088A06F /* SwiftUINavigation */; }; 795640702955B5190088A06F /* IdentifiedCollections in Frameworks */ = {isa = PBXBuildFile; productRef = 7956406F2955B5190088A06F /* IdentifiedCollections */; }; + 795FA98B2DF353AF00F67AFF /* SignInWithFacebook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 795FA98A2DF353AC00F67AFF /* SignInWithFacebook.swift */; }; + 795FA98E2DF354B000F67AFF /* FacebookLogin in Frameworks */ = {isa = PBXBuildFile; productRef = 795FA98D2DF354B000F67AFF /* FacebookLogin */; }; 796298992AEBBA77000AA957 /* MFAFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 796298982AEBBA77000AA957 /* MFAFlow.swift */; }; 7962989D2AEBC6F9000AA957 /* SVGView in Frameworks */ = {isa = PBXBuildFile; productRef = 7962989C2AEBC6F9000AA957 /* SVGView */; }; 79719ECE2ADF26C400737804 /* Supabase in Frameworks */ = {isa = PBXBuildFile; productRef = 79719ECD2ADF26C400737804 /* Supabase */; }; @@ -102,6 +104,7 @@ 795640652955AE9C0088A06F /* TodoListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TodoListView.swift; sourceTree = ""; }; 795640672955AEB30088A06F /* Models.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Models.swift; sourceTree = ""; }; 795640692955AFBD0088A06F /* ErrorText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorText.swift; sourceTree = ""; }; + 795FA98A2DF353AC00F67AFF /* SignInWithFacebook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInWithFacebook.swift; sourceTree = ""; }; 796298982AEBBA77000AA957 /* MFAFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MFAFlow.swift; sourceTree = ""; }; 7962989A2AEBBD9F000AA957 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 797D66492B46A1D8007592ED /* Dependencies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Dependencies.swift; sourceTree = ""; }; @@ -158,6 +161,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 795FA98E2DF354B000F67AFF /* FacebookLogin in Frameworks */, 79BE42A12D942EFD00B9DDF4 /* Clerk in Frameworks */, 79E2B5582B97890F0042CD21 /* GoogleSignIn in Frameworks */, 795640702955B5190088A06F /* IdentifiedCollections in Frameworks */, @@ -270,6 +274,7 @@ 79AF04822B2CE3BD008761AD /* Auth */ = { isa = PBXGroup; children = ( + 795FA98A2DF353AC00F67AFF /* SignInWithFacebook.swift */, 799EE6A22C877BF900FD9DD7 /* SignInWithPhone.swift */, 7956405F2954AE140088A06F /* AuthController.swift */, 79AF04802B2CE261008761AD /* AuthView.swift */, @@ -376,6 +381,7 @@ 79E2B5572B97890F0042CD21 /* GoogleSignIn */, 79E2B5592B97890F0042CD21 /* GoogleSignInSwift */, 79BE42A02D942EFD00B9DDF4 /* Clerk */, + 795FA98D2DF354B000F67AFF /* FacebookLogin */, ); productName = Examples; productReference = 793895C62954ABFF0044F2B8 /* Examples.app */; @@ -458,6 +464,7 @@ 7962989B2AEBC6F9000AA957 /* XCRemoteSwiftPackageReference "SVGView" */, 79E2B5562B97890F0042CD21 /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */, 79BE429F2D942EFD00B9DDF4 /* XCRemoteSwiftPackageReference "clerk-ios" */, + 795FA98C2DF354B000F67AFF /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */, ); productRefGroup = 793895C72954ABFF0044F2B8 /* Products */; projectDirPath = ""; @@ -510,6 +517,7 @@ 799EE6A32C877BFB00FD9DD7 /* SignInWithPhone.swift in Sources */, 79AF04862B2CE586008761AD /* Debug.swift in Sources */, 79AF04842B2CE408008761AD /* AuthWithMagicLink.swift in Sources */, + 795FA98B2DF353AF00F67AFF /* SignInWithFacebook.swift in Sources */, 79401F352BC708C8004C9C0F /* UIViewControllerWrapper.swift in Sources */, 79401F332BC6FEAE004C9C0F /* SignInWithOAuth.swift in Sources */, 79B1C80E2BAC017C00D991AA /* AnyJSONView.swift in Sources */, @@ -991,6 +999,14 @@ minimumVersion = 1.0.0; }; }; + 795FA98C2DF354B000F67AFF /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/facebook/facebook-ios-sdk"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 14.1.0; + }; + }; 7962989B2AEBC6F9000AA957 /* XCRemoteSwiftPackageReference "SVGView" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/exyte/SVGView"; @@ -1028,6 +1044,11 @@ package = 7956406E2955B5190088A06F /* XCRemoteSwiftPackageReference "swift-identified-collections" */; productName = IdentifiedCollections; }; + 795FA98D2DF354B000F67AFF /* FacebookLogin */ = { + isa = XCSwiftPackageProductDependency; + package = 795FA98C2DF354B000F67AFF /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */; + productName = FacebookLogin; + }; 7962989C2AEBC6F9000AA957 /* SVGView */ = { isa = XCSwiftPackageProductDependency; package = 7962989B2AEBC6F9000AA957 /* XCRemoteSwiftPackageReference "SVGView" */; diff --git a/Examples/Examples/Auth/AuthView.swift b/Examples/Examples/Auth/AuthView.swift index 88830900..806f1d98 100644 --- a/Examples/Examples/Auth/AuthView.swift +++ b/Examples/Examples/Auth/AuthView.swift @@ -13,6 +13,7 @@ struct AuthView: View { case magicLink case signInWithPhone case signInWithApple + case signInWithFacebook case signInWithOAuth #if canImport(UIKit) case signInWithOAuthUsingUIKit @@ -26,6 +27,7 @@ struct AuthView: View { case .magicLink: "Auth with Magic Link" case .signInWithPhone: "Sign in with Phone" case .signInWithApple: "Sign in with Apple" + case .signInWithFacebook: "Sign in with Facebook" case .signInWithOAuth: "Sign in with OAuth flow" #if canImport(UIKit) case .signInWithOAuthUsingUIKit: "Sign in with OAuth flow (UIKit)" @@ -61,6 +63,7 @@ extension AuthView.Option: View { case .magicLink: AuthWithMagicLink() case .signInWithPhone: SignInWithPhone() case .signInWithApple: SignInWithApple() + case .signInWithFacebook: SignInWithFacebook() case .signInWithOAuth: SignInWithOAuth() #if canImport(UIKit) case .signInWithOAuthUsingUIKit: UIViewControllerWrapper(SignInWithOAuthViewController()) diff --git a/Examples/Examples/Auth/SignInWithFacebook.swift b/Examples/Examples/Auth/SignInWithFacebook.swift new file mode 100644 index 00000000..a4d25068 --- /dev/null +++ b/Examples/Examples/Auth/SignInWithFacebook.swift @@ -0,0 +1,65 @@ +import FacebookLogin +import OSLog +import Supabase +import SwiftUI + +struct SignInWithFacebook: View { + @State private var actionState = ActionState.idle + + static let logger = Logger(subsystem: "com.supabase.examples", category: "SignInWithFacebook") + + let loginManager = LoginManager() + + var body: some View { + VStack { + Button("Sign in with Facebook") { + actionState = .inFlight + + loginManager.logIn( + configuration: LoginConfiguration( + permissions: ["public_profile", "email"], + tracking: .limited + ) + ) { result in + switch result { + case .failed(let error): + actionState = .result(.failure(error)) + Self.logger.error("Facebook login failed: \(error.localizedDescription)") + case .cancelled: + actionState = .idle + Self.logger.info("Facebook login cancelled") + case .success(_, _, let token): + Self.logger.info("Facebook login succeeded.") + + guard let idToken = token?.tokenString else { + actionState = .idle + Self.logger.error("Facebook login token is nil") + return + } + + Task { + do { + try await supabase.auth.signInWithIdToken( + credentials: OpenIDConnectCredentials( + provider: .facebook, + idToken: idToken + ) + ) + actionState = .result(.success(())) + Self.logger.info("Successfully signed in with Facebook") + } catch { + actionState = .result(.failure(error)) + Self.logger.error("Failed to sign in with Facebook: \(error.localizedDescription)") + + } + } + } + } + } + } + } +} + +#Preview { + SignInWithFacebook() +} diff --git a/Examples/Examples/ExamplesApp.swift b/Examples/Examples/ExamplesApp.swift index e38c80c2..13291681 100644 --- a/Examples/Examples/ExamplesApp.swift +++ b/Examples/Examples/ExamplesApp.swift @@ -5,12 +5,54 @@ // Created by Guilherme Souza on 22/12/22. // +import FacebookLogin import GoogleSignIn import Supabase import SwiftUI +import UIKit + +final class AppDelegate: UIResponder, UIApplicationDelegate { + func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil + ) -> Bool { + ApplicationDelegate.shared.application( + application, + didFinishLaunchingWithOptions: launchOptions + ) + } + + func application( + _ application: UIApplication, + configurationForConnecting connectingSceneSession: UISceneSession, + options: UIScene.ConnectionOptions + ) -> UISceneConfiguration { + let sceneConfig = UISceneConfiguration( + name: "Default Configuration", + sessionRole: connectingSceneSession.role + ) + sceneConfig.delegateClass = SceneDelegate.self + return sceneConfig + } +} + +final class SceneDelegate: UIResponder, UIWindowSceneDelegate { + func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { + guard let url = URLContexts.first?.url else { return } + + ApplicationDelegate.shared.application( + UIApplication.shared, + open: url, + sourceApplication: nil, + annotation: [UIApplication.OpenURLOptionsKey.annotation] + ) + } +} @main struct ExamplesApp: App { + @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate + var body: some Scene { WindowGroup { RootView() diff --git a/Examples/Examples/Info.plist b/Examples/Examples/Info.plist index c3751b58..075945ce 100644 --- a/Examples/Examples/Info.plist +++ b/Examples/Examples/Info.plist @@ -17,13 +17,30 @@ Editor CFBundleURLSchemes - DOT_REVERSED_IOS_CLIENT_ID + {{ DOT_REVERSED_IOS_CLIENT_ID }} + + CFBundleURLSchemes + + fb{{ FACEBOOK APP ID }} + + GIDClientID - YOUR_IOS_CLIENT_ID + {{ YOUR_IOS_CLIENT_ID }} GIDServerClientID - YOUR_SERVER_CLIENT_ID + {{ YOUR_SERVER_CLIENT_ID }} + FacebookAppID + {{ FACEBOOK APP ID }} + FacebookClientToken + {{ FACEBOOK CLIENT TOKEN }} + FacebookDisplayName + Examples + LSApplicationQueriesSchemes + + fbapi + fb-messenger-share-api + diff --git a/Examples/README.md b/Examples/README.md new file mode 100644 index 00000000..5d678b93 --- /dev/null +++ b/Examples/README.md @@ -0,0 +1,48 @@ +# Examples + +This directory contains example applications demonstrating the usage of Supabase Swift SDK. + +## Prerequisites + +[Requirements](../README.md#requirements) + +## Running the Examples App + +1. Open the `Examples.xcodeproj` file in Xcode +2. Select your target device or simulator +3. Build and run the project (⌘R) + +## Authentication Setup + +### Supabase Credentials Setup + +The examples app uses a local Supabase instance by default. To set up your Supabase credentials: + +1. Open `Supabase.plist` in the Examples project +2. Update the following values: + - `SUPABASE_URL`: Your Supabase project URL + - `SUPABASE_ANON_KEY`: Your Supabase project's anon/public key + +You can find these values in your Supabase project dashboard under Project Settings > API. + +### Google Sign-In Setup + +To enable Google Sign-In in the examples app: + +1. Create a project in the [Google Cloud Console](https://console.cloud.google.com/) +2. Enable the Google Sign-In API +3. Create OAuth 2.0 credentials for iOS +4. Update the `Info.plist` file with your credentials: + - Replace `{{ YOUR_IOS_CLIENT_ID }}` with your iOS client ID + - Replace `{{ YOUR_SERVER_CLIENT_ID }}` with your server client ID + - Replace `{{ DOT_REVERSED_IOS_CLIENT_ID }}` with your reversed client ID + +### Facebook Sign-In Setup + +To enable Facebook Sign-In in the examples app: + +1. Create an app in the [Facebook Developers Console](https://developers.facebook.com/) +2. Add iOS platform to your Facebook app +3. Update the `Info.plist` file with your Facebook credentials: + - Replace `{{ FACEBOOK APP ID }}` with your Facebook App ID + - Replace `{{ FACEBOOK CLIENT TOKEN }}` with your Facebook Client Token diff --git a/Supabase.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Supabase.xcworkspace/xcshareddata/swiftpm/Package.resolved index d0804396..896199ac 100644 --- a/Supabase.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Supabase.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -18,6 +18,15 @@ "version" : "0.52.0" } }, + { + "identity" : "facebook-ios-sdk", + "kind" : "remoteSourceControl", + "location" : "https://github.com/facebook/facebook-ios-sdk", + "state" : { + "revision" : "c19607d535864533523d1f437c84035e5fb101cf", + "version" : "14.1.0" + } + }, { "identity" : "factory", "kind" : "remoteSourceControl",