-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(auth, expo): plugin: skip expo-router on iOS for firebaseauth URLs (
#8203) - add a check for expo-router before patching AppDelegate - skip patching AppDelegate if no 'openURL' doesn't exist - throw Error if explicitly enabled but failed to find 'openURL' method - check that swizzling is enabled before patching - print a warning when config is default and AppDelegate is modified
- Loading branch information
Showing
14 changed files
with
1,339 additions
and
7 deletions.
There are no files selected for viewing
350 changes: 350 additions & 0 deletions
350
packages/auth/plugin/__tests__/__snapshots__/iosPlugin_openUrlFix.test.ts.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,350 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`Config Plugin iOS Tests - openUrlFix munges AppDelegate correctly - AppDelegate_bare_sdk43.m 1`] = ` | ||
"// This AppDelegate template is used in Expo SDK 43 | ||
// It is (nearly) identical to the pure template used when | ||
// creating a bare React Native app (without Expo) | ||
#import "AppDelegate.h" | ||
#import <React/RCTBridge.h> | ||
#import <React/RCTBundleURLProvider.h> | ||
#import <React/RCTRootView.h> | ||
#import <React/RCTLinkingManager.h> | ||
#import <React/RCTConvert.h> | ||
#if defined(FB_SONARKIT_ENABLED) && __has_include(<FlipperKit/FlipperClient.h>) | ||
#import <FlipperKit/FlipperClient.h> | ||
#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h> | ||
#import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h> | ||
#import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h> | ||
#import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h> | ||
#import <FlipperKitReactPlugin/FlipperKitReactPlugin.h> | ||
static void InitializeFlipper(UIApplication *application) { | ||
FlipperClient *client = [FlipperClient sharedClient]; | ||
SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults]; | ||
[client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]]; | ||
[client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]]; | ||
[client addPlugin:[FlipperKitReactPlugin new]]; | ||
[client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]]; | ||
[client start]; | ||
} | ||
#endif | ||
@implementation AppDelegate | ||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions | ||
{ | ||
#if defined(FB_SONARKIT_ENABLED) && __has_include(<FlipperKit/FlipperClient.h>) | ||
InitializeFlipper(application); | ||
#endif | ||
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; | ||
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@"main" initialProperties:nil]; | ||
id rootViewBackgroundColor = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"RCTRootViewBackgroundColor"]; | ||
if (rootViewBackgroundColor != nil) { | ||
rootView.backgroundColor = [RCTConvert UIColor:rootViewBackgroundColor]; | ||
} else { | ||
rootView.backgroundColor = [UIColor whiteColor]; | ||
} | ||
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; | ||
UIViewController *rootViewController = [UIViewController new]; | ||
rootViewController.view = rootView; | ||
self.window.rootViewController = rootViewController; | ||
[self.window makeKeyAndVisible]; | ||
[super application:application didFinishLaunchingWithOptions:launchOptions]; | ||
return YES; | ||
} | ||
- (NSArray<id<RCTBridgeModule>> *)extraModulesForBridge:(RCTBridge *)bridge | ||
{ | ||
// If you'd like to export some custom RCTBridgeModules, add them here! | ||
return @[]; | ||
} | ||
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { | ||
#ifdef DEBUG | ||
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; | ||
#else | ||
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; | ||
#endif | ||
} | ||
// Linking API | ||
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options { | ||
// @generated begin @react-native-firebase/auth-openURL - expo prebuild (DO NOT MODIFY) sync-5e029a87ac71df3ca5665387eb712d1b32274c6a | ||
if ([url.host caseInsensitiveCompare:@"firebaseauth"] == NSOrderedSame) { | ||
// invocations for Firebase Auth are handled elsewhere and should not be forwarded to Expo Router | ||
return NO; | ||
} | ||
// @generated end @react-native-firebase/auth-openURL | ||
return [RCTLinkingManager application:application openURL:url options:options]; | ||
} | ||
// Universal Links | ||
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler { | ||
return [RCTLinkingManager application:application | ||
continueUserActivity:userActivity | ||
restorationHandler:restorationHandler]; | ||
} | ||
@end | ||
" | ||
`; | ||
exports[`Config Plugin iOS Tests - openUrlFix munges AppDelegate correctly - AppDelegate_sdk44.m 1`] = ` | ||
"// This AppDelegate prebuild template is used in Expo SDK 44+ | ||
// It has the RCTBridge to be created by Expo ReactDelegate | ||
#import "AppDelegate.h" | ||
#import <React/RCTBridge.h> | ||
#import <React/RCTBundleURLProvider.h> | ||
#import <React/RCTRootView.h> | ||
#import <React/RCTLinkingManager.h> | ||
#import <React/RCTConvert.h> | ||
#if defined(FB_SONARKIT_ENABLED) && __has_include(<FlipperKit/FlipperClient.h>) | ||
#import <FlipperKit/FlipperClient.h> | ||
#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h> | ||
#import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h> | ||
#import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h> | ||
#import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h> | ||
#import <FlipperKitReactPlugin/FlipperKitReactPlugin.h> | ||
static void InitializeFlipper(UIApplication *application) { | ||
FlipperClient *client = [FlipperClient sharedClient]; | ||
SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults]; | ||
[client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]]; | ||
[client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]]; | ||
[client addPlugin:[FlipperKitReactPlugin new]]; | ||
[client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]]; | ||
[client start]; | ||
} | ||
#endif | ||
@implementation AppDelegate | ||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions | ||
{ | ||
#if defined(FB_SONARKIT_ENABLED) && __has_include(<FlipperKit/FlipperClient.h>) | ||
InitializeFlipper(application); | ||
#endif | ||
RCTBridge *bridge = [self.reactDelegate createBridgeWithDelegate:self launchOptions:launchOptions]; | ||
RCTRootView *rootView = [self.reactDelegate createRootViewWithBridge:bridge moduleName:@"main" initialProperties:nil]; | ||
rootView.backgroundColor = [UIColor whiteColor]; | ||
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; | ||
UIViewController *rootViewController = [self.reactDelegate createRootViewController]; | ||
rootViewController.view = rootView; | ||
self.window.rootViewController = rootViewController; | ||
[self.window makeKeyAndVisible]; | ||
[super application:application didFinishLaunchingWithOptions:launchOptions]; | ||
return YES; | ||
} | ||
- (NSArray<id<RCTBridgeModule>> *)extraModulesForBridge:(RCTBridge *)bridge | ||
{ | ||
// If you'd like to export some custom RCTBridgeModules, add them here! | ||
return @[]; | ||
} | ||
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { | ||
#ifdef DEBUG | ||
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; | ||
#else | ||
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; | ||
#endif | ||
} | ||
// Linking API | ||
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options { | ||
// @generated begin @react-native-firebase/auth-openURL - expo prebuild (DO NOT MODIFY) sync-5e029a87ac71df3ca5665387eb712d1b32274c6a | ||
if ([url.host caseInsensitiveCompare:@"firebaseauth"] == NSOrderedSame) { | ||
// invocations for Firebase Auth are handled elsewhere and should not be forwarded to Expo Router | ||
return NO; | ||
} | ||
// @generated end @react-native-firebase/auth-openURL | ||
return [RCTLinkingManager application:application openURL:url options:options]; | ||
} | ||
// Universal Links | ||
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler { | ||
return [RCTLinkingManager application:application | ||
continueUserActivity:userActivity | ||
restorationHandler:restorationHandler]; | ||
} | ||
@end | ||
" | ||
`; | ||
exports[`Config Plugin iOS Tests - openUrlFix munges AppDelegate correctly - AppDelegate_sdk45.mm 1`] = ` | ||
"// RN 0.68.1, Expo SDK 45 template | ||
// The main difference between this and the SDK 44 one is that this is | ||
// using React Native 0.68 and is written in Objective-C++ | ||
#import "AppDelegate.h" | ||
#import <React/RCTBridge.h> | ||
#import <React/RCTBundleURLProvider.h> | ||
#import <React/RCTRootView.h> | ||
#import <React/RCTLinkingManager.h> | ||
#import <React/RCTConvert.h> | ||
#import <React/RCTAppSetupUtils.h> | ||
#if RCT_NEW_ARCH_ENABLED | ||
#import <React/CoreModulesPlugins.h> | ||
#import <React/RCTCxxBridgeDelegate.h> | ||
#import <React/RCTFabricSurfaceHostingProxyRootView.h> | ||
#import <React/RCTSurfacePresenter.h> | ||
#import <React/RCTSurfacePresenterBridgeAdapter.h> | ||
#import <ReactCommon/RCTTurboModuleManager.h> | ||
#import <react/config/ReactNativeConfig.h> | ||
@interface AppDelegate () <RCTCxxBridgeDelegate, RCTTurboModuleManagerDelegate> { | ||
RCTTurboModuleManager *_turboModuleManager; | ||
RCTSurfacePresenterBridgeAdapter *_bridgeAdapter; | ||
std::shared_ptr<const facebook::react::ReactNativeConfig> _reactNativeConfig; | ||
facebook::react::ContextContainer::Shared _contextContainer; | ||
} | ||
@end | ||
#endif | ||
@implementation AppDelegate | ||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions | ||
{ | ||
RCTAppSetupPrepareApp(application); | ||
RCTBridge *bridge = [self.reactDelegate createBridgeWithDelegate:self launchOptions:launchOptions]; | ||
#if RCT_NEW_ARCH_ENABLED | ||
_contextContainer = std::make_shared<facebook::react::ContextContainer const>(); | ||
_reactNativeConfig = std::make_shared<facebook::react::EmptyReactNativeConfig const>(); | ||
_contextContainer->insert("ReactNativeConfig", _reactNativeConfig); | ||
_bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer]; | ||
bridge.surfacePresenter = _bridgeAdapter.surfacePresenter; | ||
#endif | ||
UIView *rootView = [self.reactDelegate createRootViewWithBridge:bridge moduleName:@"main" initialProperties:nil]; | ||
rootView.backgroundColor = [UIColor whiteColor]; | ||
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; | ||
UIViewController *rootViewController = [self.reactDelegate createRootViewController]; | ||
rootViewController.view = rootView; | ||
self.window.rootViewController = rootViewController; | ||
[self.window makeKeyAndVisible]; | ||
[super application:application didFinishLaunchingWithOptions:launchOptions]; | ||
return YES; | ||
} | ||
- (NSArray<id<RCTBridgeModule>> *)extraModulesForBridge:(RCTBridge *)bridge | ||
{ | ||
// If you'd like to export some custom RCTBridgeModules, add them here! | ||
return @[]; | ||
} | ||
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge | ||
{ | ||
#if DEBUG | ||
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; | ||
#else | ||
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; | ||
#endif | ||
} | ||
// Linking API | ||
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options { | ||
// @generated begin @react-native-firebase/auth-openURL - expo prebuild (DO NOT MODIFY) sync-5e029a87ac71df3ca5665387eb712d1b32274c6a | ||
if ([url.host caseInsensitiveCompare:@"firebaseauth"] == NSOrderedSame) { | ||
// invocations for Firebase Auth are handled elsewhere and should not be forwarded to Expo Router | ||
return NO; | ||
} | ||
// @generated end @react-native-firebase/auth-openURL | ||
return [super application:application openURL:url options:options] || [RCTLinkingManager application:application openURL:url options:options]; | ||
} | ||
// Universal Links | ||
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler { | ||
BOOL result = [RCTLinkingManager application:application continueUserActivity:userActivity restorationHandler:restorationHandler]; | ||
return [super application:application continueUserActivity:userActivity restorationHandler:restorationHandler] || result; | ||
} | ||
#if RCT_NEW_ARCH_ENABLED | ||
#pragma mark - RCTCxxBridgeDelegate | ||
- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge | ||
{ | ||
_turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge | ||
delegate:self | ||
jsInvoker:bridge.jsCallInvoker]; | ||
return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager); | ||
} | ||
#pragma mark RCTTurboModuleManagerDelegate | ||
- (Class)getModuleClassFromName:(const char *)name | ||
{ | ||
return RCTCoreModulesClassProvider(name); | ||
} | ||
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name | ||
jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker | ||
{ | ||
return nullptr; | ||
} | ||
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name | ||
initParams: | ||
(const facebook::react::ObjCTurboModule::InitParams &)params | ||
{ | ||
return nullptr; | ||
} | ||
- (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass | ||
{ | ||
return RCTAppSetupDefaultModuleFromClass(moduleClass); | ||
} | ||
#endif | ||
@end | ||
" | ||
`; | ||
exports[`Config Plugin iOS Tests - openUrlFix must match positiveTemplateCases[0] 1`] = ` | ||
"- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options { | ||
// @generated begin @react-native-firebase/auth-openURL - expo prebuild (DO NOT MODIFY) sync-5e029a87ac71df3ca5665387eb712d1b32274c6a | ||
if ([url.host caseInsensitiveCompare:@"firebaseauth"] == NSOrderedSame) { | ||
// invocations for Firebase Auth are handled elsewhere and should not be forwarded to Expo Router | ||
return NO; | ||
} | ||
// @generated end @react-native-firebase/auth-openURL | ||
int x=3;" | ||
`; | ||
exports[`Config Plugin iOS Tests - openUrlFix must match positiveTemplateCases[3] 1`] = ` | ||
" - ( BOOL ) application : ( UIApplication* ) application openURL : ( NSURL*) url options : ( NSDictionary < UIApplicationOpenURLOptionsKey , id > *) options | ||
{ | ||
// @generated begin @react-native-firebase/auth-openURL - expo prebuild (DO NOT MODIFY) sync-5e029a87ac71df3ca5665387eb712d1b32274c6a | ||
if ([url.host caseInsensitiveCompare:@"firebaseauth"] == NSOrderedSame) { | ||
// invocations for Firebase Auth are handled elsewhere and should not be forwarded to Expo Router | ||
return NO; | ||
} | ||
// @generated end @react-native-firebase/auth-openURL | ||
" | ||
`; |
2 changes: 1 addition & 1 deletion
2
...ts__/__snapshots__/iosPlugin.test.ts.snap → ...apshots__/iosPlugin_urlTypes.test.ts.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.