From 088af6bc2528438992b2cbc8db993b7367909dd6 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Thu, 25 Sep 2025 14:45:42 +0700 Subject: [PATCH] Add macOS OAuth browser support and platform integration Introduces native macOS OAuth browser integration via a new MacBrowser implementation, including native plugin, bridging code, and build instructions. Updates browser selection logic to support macOS standalone builds and refactors platform detection to treat macOS as a mobile runtime for authentication flows. --- Assets/Thirdweb/Plugins/macOS.meta | 8 ++ Assets/Thirdweb/Plugins/macOS/MacBrowser.mm | 106 ++++++++++++++++++ .../Thirdweb/Plugins/macOS/MacBrowser.mm.meta | 84 ++++++++++++++ Assets/Thirdweb/Plugins/macOS/README.md | 17 +++ Assets/Thirdweb/Plugins/macOS/README.md.meta | 7 ++ .../Plugins/macOS/libMacBrowser.dylib | Bin 0 -> 88560 bytes .../Plugins/macOS/libMacBrowser.dylib.meta | 83 ++++++++++++++ .../Browser/CrossPlatformUnityBrowser.cs | 2 + .../Runtime/Unity/Browser/iOSBrowser.cs | 84 +++++++++++++- .../Runtime/Unity/ThirdwebManagerBase.cs | 20 +++- 10 files changed, 401 insertions(+), 10 deletions(-) create mode 100644 Assets/Thirdweb/Plugins/macOS.meta create mode 100644 Assets/Thirdweb/Plugins/macOS/MacBrowser.mm create mode 100644 Assets/Thirdweb/Plugins/macOS/MacBrowser.mm.meta create mode 100644 Assets/Thirdweb/Plugins/macOS/README.md create mode 100644 Assets/Thirdweb/Plugins/macOS/README.md.meta create mode 100755 Assets/Thirdweb/Plugins/macOS/libMacBrowser.dylib create mode 100644 Assets/Thirdweb/Plugins/macOS/libMacBrowser.dylib.meta diff --git a/Assets/Thirdweb/Plugins/macOS.meta b/Assets/Thirdweb/Plugins/macOS.meta new file mode 100644 index 00000000..fffc90f1 --- /dev/null +++ b/Assets/Thirdweb/Plugins/macOS.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c6e9b5dce5f146478df9f3e2df5abe10 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Thirdweb/Plugins/macOS/MacBrowser.mm b/Assets/Thirdweb/Plugins/macOS/MacBrowser.mm new file mode 100644 index 00000000..405cf150 --- /dev/null +++ b/Assets/Thirdweb/Plugins/macOS/MacBrowser.mm @@ -0,0 +1,106 @@ +#import +#import + +#include "../iOS/Common.h" + +typedef void (*ASWebAuthenticationSessionCompletionCallback)(void* sessionPtr, const char* callbackUrl, int errorCode, const char* errorMessage); + +@interface Thirdweb_ASWebAuthenticationSession : NSObject + +@property (readonly, nonatomic) ASWebAuthenticationSession* session; + +@end + +@implementation Thirdweb_ASWebAuthenticationSession + +- (instancetype)initWithURL:(NSURL *)URL callbackURLScheme:(nullable NSString *)callbackURLScheme completionCallback:(ASWebAuthenticationSessionCompletionCallback)completionCallback +{ + self = [super init]; + if (self) + { + _session = [[ASWebAuthenticationSession alloc] initWithURL:URL + callbackURLScheme:callbackURLScheme + completionHandler:^(NSURL * _Nullable callbackURL, NSError * _Nullable error) + { + if (error != nil) + { + NSLog(@"[ASWebAuthenticationSession:CompletionHandler] %@", error.description); + } + + completionCallback((__bridge void*)self, toString(callbackURL.absoluteString), (int)error.code, toString(error.localizedDescription)); + }]; + + if (@available(macOS 10.15, *)) + { + _session.presentationContextProvider = self; + } + } + return self; +} + +- (ASPresentationAnchor)presentationAnchorForWebAuthenticationSession:(ASWebAuthenticationSession *)session +{ + if (@available(macOS 10.15, *)) + { + NSWindow* anchor = [NSApplication sharedApplication].keyWindow; + if (anchor == nil) + { + anchor = [NSApplication sharedApplication].mainWindow; + } + if (anchor == nil) + { + anchor = [NSApplication sharedApplication].windows.firstObject; + } + return anchor; + } + return nil; +} + +@end + +extern "C" +{ + Thirdweb_ASWebAuthenticationSession* Thirdweb_ASWebAuthenticationSession_InitWithURL( + const char* urlStr, const char* urlSchemeStr, ASWebAuthenticationSessionCompletionCallback completionCallback) + { + NSURL* url = [NSURL URLWithString: toString(urlStr)]; + NSString* urlScheme = toString(urlSchemeStr); + + Thirdweb_ASWebAuthenticationSession* session = [[Thirdweb_ASWebAuthenticationSession alloc] initWithURL:url + callbackURLScheme:urlScheme + completionCallback:completionCallback]; + return session; + } + + int Thirdweb_ASWebAuthenticationSession_Start(void* sessionPtr) + { + Thirdweb_ASWebAuthenticationSession* session = (__bridge Thirdweb_ASWebAuthenticationSession*) sessionPtr; + BOOL started = [[session session] start]; + return toBool(started); + } + + void Thirdweb_ASWebAuthenticationSession_Cancel(void* sessionPtr) + { + Thirdweb_ASWebAuthenticationSession* session = (__bridge Thirdweb_ASWebAuthenticationSession*) sessionPtr; + [[session session] cancel]; + } + + int Thirdweb_ASWebAuthenticationSession_GetPrefersEphemeralWebBrowserSession(void* sessionPtr) + { + Thirdweb_ASWebAuthenticationSession* session = (__bridge Thirdweb_ASWebAuthenticationSession*) sessionPtr; + if (@available(macOS 10.15, *)) + { + return toBool([[session session] prefersEphemeralWebBrowserSession]); + } + return 0; + } + + void Thirdweb_ASWebAuthenticationSession_SetPrefersEphemeralWebBrowserSession(void* sessionPtr, int enable) + { + Thirdweb_ASWebAuthenticationSession* session = (__bridge Thirdweb_ASWebAuthenticationSession*) sessionPtr; + if (@available(macOS 10.15, *)) + { + [[session session] setPrefersEphemeralWebBrowserSession:toBool(enable)]; + } + } +} diff --git a/Assets/Thirdweb/Plugins/macOS/MacBrowser.mm.meta b/Assets/Thirdweb/Plugins/macOS/MacBrowser.mm.meta new file mode 100644 index 00000000..b7cddad5 --- /dev/null +++ b/Assets/Thirdweb/Plugins/macOS/MacBrowser.mm.meta @@ -0,0 +1,84 @@ +fileFormatVersion: 2 +guid: 934bb3da36e34dfcb207b4c1d77efc9a +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 0 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Android: Android + second: + enabled: 0 + settings: + AndroidSharedLibraryType: Executable + CPU: ARMv7 + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: AnyOS + - first: + Standalone: Linux64 + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + Standalone: OSXUniversal + second: + enabled: 0 + settings: + CPU: AnyCPU + FrameworkDependencies: + CompileFlags: + - first: + Standalone: Win + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + Standalone: Win64 + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + iPhone: iOS + second: + enabled: 0 + settings: + AddToEmbeddedBinaries: false + CPU: AnyCPU + CompileFlags: + FrameworkDependencies: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Thirdweb/Plugins/macOS/README.md b/Assets/Thirdweb/Plugins/macOS/README.md new file mode 100644 index 00000000..e155fdec --- /dev/null +++ b/Assets/Thirdweb/Plugins/macOS/README.md @@ -0,0 +1,17 @@ +# macOS OAuth Plugin + +The native bridge in this folder (`libMacBrowser.dylib`) is a universal binary (arm64 + x86_64) built from `MacBrowser.mm`. + +## Rebuild steps + +Run these commands from the repository root on macOS: + +```bash +cd Assets/Thirdweb/Plugins/macOS +clang++ -std=c++17 -ObjC++ -fmodules -Wall -Werror -arch arm64 -framework Cocoa -framework AuthenticationServices -dynamiclib MacBrowser.mm -o /tmp/libMacBrowser_arm64.dylib +clang++ -std=c++17 -ObjC++ -fmodules -Wall -Werror -arch x86_64 -framework Cocoa -framework AuthenticationServices -dynamiclib MacBrowser.mm -o /tmp/libMacBrowser_x86_64.dylib +lipo -create /tmp/libMacBrowser_arm64.dylib /tmp/libMacBrowser_x86_64.dylib -output libMacBrowser.dylib +rm /tmp/libMacBrowser_arm64.dylib /tmp/libMacBrowser_x86_64.dylib +``` + +After rebuilding, re-run your Unity macOS build to make sure the new binary is picked up. diff --git a/Assets/Thirdweb/Plugins/macOS/README.md.meta b/Assets/Thirdweb/Plugins/macOS/README.md.meta new file mode 100644 index 00000000..89019c9b --- /dev/null +++ b/Assets/Thirdweb/Plugins/macOS/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3a9f5a8a4f5b4139af80d91a1b66ec97 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Thirdweb/Plugins/macOS/libMacBrowser.dylib b/Assets/Thirdweb/Plugins/macOS/libMacBrowser.dylib new file mode 100755 index 0000000000000000000000000000000000000000..159733092fdd1bdff81494f9b4dd572b7967e788 GIT binary patch literal 88560 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 K{_d(7&;1`a+NRwA literal 0 HcmV?d00001 diff --git a/Assets/Thirdweb/Plugins/macOS/libMacBrowser.dylib.meta b/Assets/Thirdweb/Plugins/macOS/libMacBrowser.dylib.meta new file mode 100644 index 00000000..fe0011dd --- /dev/null +++ b/Assets/Thirdweb/Plugins/macOS/libMacBrowser.dylib.meta @@ -0,0 +1,83 @@ +fileFormatVersion: 2 +guid: d6547937dc5d4cd09d0f566cbb286ee0 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 0 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Android: Android + second: + enabled: 0 + settings: + CPU: ARMv7 + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: AnyOS + - first: + Standalone: Linux64 + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + Standalone: OSXUniversal + second: + enabled: 1 + settings: + CPU: AnyCPU + FrameworkDependencies: AuthenticationServices; + CompileFlags: + - first: + Standalone: Win + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + Standalone: Win64 + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + iPhone: iOS + second: + enabled: 0 + settings: + AddToEmbeddedBinaries: false + CPU: AnyCPU + CompileFlags: + FrameworkDependencies: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Thirdweb/Runtime/Unity/Browser/CrossPlatformUnityBrowser.cs b/Assets/Thirdweb/Runtime/Unity/Browser/CrossPlatformUnityBrowser.cs index b87c4b16..06b11b43 100644 --- a/Assets/Thirdweb/Runtime/Unity/Browser/CrossPlatformUnityBrowser.cs +++ b/Assets/Thirdweb/Runtime/Unity/Browser/CrossPlatformUnityBrowser.cs @@ -37,6 +37,8 @@ public CrossPlatformUnityBrowser(string htmlOverride = null) _unityBrowser = new AndroidBrowser(); #elif UNITY_IOS _unityBrowser = new IOSBrowser(); +#elif UNITY_STANDALONE_OSX + _unityBrowser = new MacBrowser(); #else _unityBrowser = new InAppWalletBrowser(htmlOverride); #endif diff --git a/Assets/Thirdweb/Runtime/Unity/Browser/iOSBrowser.cs b/Assets/Thirdweb/Runtime/Unity/Browser/iOSBrowser.cs index a3f3ba82..718f5497 100644 --- a/Assets/Thirdweb/Runtime/Unity/Browser/iOSBrowser.cs +++ b/Assets/Thirdweb/Runtime/Unity/Browser/iOSBrowser.cs @@ -1,13 +1,12 @@ -#if UNITY_IOS && !UNITY_EDITOR +#if (UNITY_IOS || UNITY_STANDALONE_OSX) && !UNITY_EDITOR using System; using System.Collections.Generic; +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using AOT; -using System.Runtime.InteropServices; - namespace Thirdweb.Unity { public class ASWebAuthenticationSession : IDisposable @@ -26,7 +25,12 @@ public ASWebAuthenticationSession(string url, string callbackUrlScheme, ASWebAut { _sessionPtr = Thirdweb_ASWebAuthenticationSession_InitWithURL(url, callbackUrlScheme, OnAuthenticationSessionCompleted); - CompletionCallbacks.Add(_sessionPtr, completionHandler); + if (_sessionPtr == IntPtr.Zero) + { + throw new InvalidOperationException("Failed to initialize ASWebAuthenticationSession."); + } + + CompletionCallbacks[_sessionPtr] = completionHandler; } public bool Start() @@ -41,11 +45,18 @@ public void Cancel() public void Dispose() { - CompletionCallbacks.Remove(_sessionPtr); + if (_sessionPtr != IntPtr.Zero) + { + CompletionCallbacks.Remove(_sessionPtr); + } _sessionPtr = IntPtr.Zero; } +#if UNITY_STANDALONE_OSX + private const string DllName = "MacBrowser"; +#else private const string DllName = "__Internal"; +#endif [DllImport(DllName)] private static extern IntPtr Thirdweb_ASWebAuthenticationSession_InitWithURL(string url, string callbackUrlScheme, AuthenticationSessionCompletedCallback completionHandler); @@ -76,6 +87,7 @@ private static void OnAuthenticationSessionCompleted(IntPtr session, string call } } +#if UNITY_IOS public class IOSBrowser : IThirdwebBrowser { private TaskCompletionSource _taskCompletionSource; @@ -134,6 +146,68 @@ private void AuthenticationSessionCompletionHandler(string callbackUrl, ASWebAut } } } +#endif + +#if UNITY_STANDALONE_OSX + public class MacBrowser : IThirdwebBrowser + { + private TaskCompletionSource _taskCompletionSource; + + public bool prefersEphemeralWebBrowserSession { get; set; } = false; + + public async Task Login(ThirdwebClient client, string loginUrl, string redirectUrl, Action browserOpenAction, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(loginUrl)) + throw new ArgumentNullException(nameof(loginUrl)); + + if (string.IsNullOrEmpty(redirectUrl)) + throw new ArgumentNullException(nameof(redirectUrl)); + + _taskCompletionSource = new TaskCompletionSource(); + + redirectUrl = redirectUrl.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries)[0]; + + using var authenticationSession = new ASWebAuthenticationSession(loginUrl, redirectUrl, AuthenticationSessionCompletionHandler); + authenticationSession.prefersEphemeralWebBrowserSession = prefersEphemeralWebBrowserSession; + + cancellationToken.Register(() => + { + _taskCompletionSource?.TrySetCanceled(); + }); + + try + { + if (!authenticationSession.Start()) + { + _taskCompletionSource.SetResult(new BrowserResult(BrowserStatus.UnknownError, "Browser could not be started.")); + } + + return await _taskCompletionSource.Task; + } + catch (TaskCanceledException) + { + authenticationSession?.Cancel(); + throw; + } + } + + private void AuthenticationSessionCompletionHandler(string callbackUrl, ASWebAuthenticationSessionError error) + { + if (error.code == ASWebAuthenticationSessionErrorCode.None) + { + _taskCompletionSource.SetResult(new BrowserResult(BrowserStatus.Success, callbackUrl)); + } + else if (error.code == ASWebAuthenticationSessionErrorCode.CanceledLogin) + { + _taskCompletionSource.SetResult(new BrowserResult(BrowserStatus.UserCanceled, callbackUrl, error.message)); + } + else + { + _taskCompletionSource.SetResult(new BrowserResult(BrowserStatus.UnknownError, callbackUrl, error.message)); + } + } + } +#endif public class ASWebAuthenticationSessionError { diff --git a/Assets/Thirdweb/Runtime/Unity/ThirdwebManagerBase.cs b/Assets/Thirdweb/Runtime/Unity/ThirdwebManagerBase.cs index 3ff9a314..b9613f5a 100644 --- a/Assets/Thirdweb/Runtime/Unity/ThirdwebManagerBase.cs +++ b/Assets/Thirdweb/Runtime/Unity/ThirdwebManagerBase.cs @@ -452,7 +452,7 @@ public virtual async Task ConnectWallet(WalletOptions walletOpt break; case AuthProvider.SiweExternal: _ = await inAppWallet.LoginWithSiweExternal( - isMobile: Application.isMobilePlatform, + isMobile: IsMobileRuntime(), browserOpenAction: (url) => Application.OpenURL(url), forceWalletIds: walletOptions.InAppWalletOptions.ForceSiweExternalWalletIds == null || walletOptions.InAppWalletOptions.ForceSiweExternalWalletIds.Count == 0 ? null @@ -463,7 +463,7 @@ public virtual async Task ConnectWallet(WalletOptions walletOpt break; default: _ = await inAppWallet.LoginWithOauth( - isMobile: Application.isMobilePlatform, + isMobile: IsMobileRuntime(), browserOpenAction: (url) => Application.OpenURL(url), mobileRedirectScheme: MobileRedirectScheme, browser: new CrossPlatformUnityBrowser(RedirectPageHtmlOverride) @@ -501,7 +501,7 @@ public virtual async Task ConnectWallet(WalletOptions walletOpt break; case AuthProvider.SiweExternal: _ = await ecosystemWallet.LoginWithSiweExternal( - isMobile: Application.isMobilePlatform, + isMobile: IsMobileRuntime(), browserOpenAction: (url) => Application.OpenURL(url), forceWalletIds: walletOptions.EcosystemWalletOptions.ForceSiweExternalWalletIds == null || walletOptions.EcosystemWalletOptions.ForceSiweExternalWalletIds.Count == 0 ? null @@ -512,7 +512,7 @@ public virtual async Task ConnectWallet(WalletOptions walletOpt break; default: _ = await ecosystemWallet.LoginWithOauth( - isMobile: Application.isMobilePlatform, + isMobile: IsMobileRuntime(), browserOpenAction: (url) => Application.OpenURL(url), mobileRedirectScheme: MobileRedirectScheme, browser: new CrossPlatformUnityBrowser(RedirectPageHtmlOverride) @@ -588,7 +588,7 @@ public virtual async Task> LinkAccount(IThirdwebWallet mainW return await mainWallet.LinkAccount( walletToLink: walletToLink, otp: otp, - isMobile: Application.isMobilePlatform, + isMobile: IsMobileRuntime(), browserOpenAction: (url) => Application.OpenURL(url), mobileRedirectScheme: MobileRedirectScheme, browser: new CrossPlatformUnityBrowser(RedirectPageHtmlOverride), @@ -598,6 +598,16 @@ public virtual async Task> LinkAccount(IThirdwebWallet mainW ); } + protected virtual bool IsMobileRuntime() + { + if (Application.platform == RuntimePlatform.OSXPlayer) + { + return true; + } + + return Application.isMobilePlatform; + } + protected virtual bool GetAutoConnectOptions(out WalletOptions lastWalletOptions) { var connectOptionsStr = PlayerPrefs.GetString(THIRDWEB_AUTO_CONNECT_OPTIONS_KEY, null);