@react-native-firebase/auth 21.6.1 → 21.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/lib/version.js +1 -1
- package/package.json +3 -3
- package/plugin/__tests__/__snapshots__/iosPlugin_openUrlFix.test.ts.snap +350 -0
- package/plugin/__tests__/__snapshots__/{iosPlugin.test.ts.snap → iosPlugin_urlTypes.test.ts.snap} +1 -1
- package/plugin/__tests__/fixtures/AppDelegate_bare_sdk43.m +86 -0
- package/plugin/__tests__/fixtures/AppDelegate_fallback.m +46 -0
- package/plugin/__tests__/fixtures/AppDelegate_sdk42.m +102 -0
- package/plugin/__tests__/fixtures/AppDelegate_sdk44.m +79 -0
- package/plugin/__tests__/fixtures/AppDelegate_sdk45.mm +129 -0
- package/plugin/__tests__/iosPlugin_openUrlFix.test.ts +343 -0
- package/plugin/__tests__/{iosPlugin.test.ts → iosPlugin_urlTypes.test.ts} +1 -1
- package/plugin/build/index.d.ts +2 -1
- package/plugin/build/index.js +3 -2
- package/plugin/build/ios/index.d.ts +2 -1
- package/plugin/build/ios/index.js +3 -1
- package/plugin/build/ios/openUrlFix.d.ts +20 -0
- package/plugin/build/ios/openUrlFix.js +150 -0
- package/plugin/build/ios/urlTypes.d.ts +2 -1
- package/plugin/build/pluginConfig.d.ts +6 -0
- package/plugin/build/pluginConfig.js +2 -0
- package/plugin/src/index.ts +5 -3
- package/plugin/src/ios/index.ts +2 -1
- package/plugin/src/ios/openUrlFix.ts +186 -0
- package/plugin/src/ios/urlTypes.ts +2 -1
- package/plugin/src/pluginConfig.ts +7 -0
- package/plugin/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,79 @@
|
|
1
|
+
// This AppDelegate prebuild template is used in Expo SDK 44+
|
2
|
+
// It has the RCTBridge to be created by Expo ReactDelegate
|
3
|
+
|
4
|
+
#import "AppDelegate.h"
|
5
|
+
|
6
|
+
#import <React/RCTBridge.h>
|
7
|
+
#import <React/RCTBundleURLProvider.h>
|
8
|
+
#import <React/RCTRootView.h>
|
9
|
+
#import <React/RCTLinkingManager.h>
|
10
|
+
#import <React/RCTConvert.h>
|
11
|
+
|
12
|
+
#if defined(FB_SONARKIT_ENABLED) && __has_include(<FlipperKit/FlipperClient.h>)
|
13
|
+
#import <FlipperKit/FlipperClient.h>
|
14
|
+
#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
|
15
|
+
#import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h>
|
16
|
+
#import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h>
|
17
|
+
#import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h>
|
18
|
+
#import <FlipperKitReactPlugin/FlipperKitReactPlugin.h>
|
19
|
+
|
20
|
+
static void InitializeFlipper(UIApplication *application) {
|
21
|
+
FlipperClient *client = [FlipperClient sharedClient];
|
22
|
+
SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults];
|
23
|
+
[client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]];
|
24
|
+
[client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]];
|
25
|
+
[client addPlugin:[FlipperKitReactPlugin new]];
|
26
|
+
[client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]];
|
27
|
+
[client start];
|
28
|
+
}
|
29
|
+
#endif
|
30
|
+
|
31
|
+
@implementation AppDelegate
|
32
|
+
|
33
|
+
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
34
|
+
{
|
35
|
+
#if defined(FB_SONARKIT_ENABLED) && __has_include(<FlipperKit/FlipperClient.h>)
|
36
|
+
InitializeFlipper(application);
|
37
|
+
#endif
|
38
|
+
|
39
|
+
RCTBridge *bridge = [self.reactDelegate createBridgeWithDelegate:self launchOptions:launchOptions];
|
40
|
+
RCTRootView *rootView = [self.reactDelegate createRootViewWithBridge:bridge moduleName:@"main" initialProperties:nil];
|
41
|
+
rootView.backgroundColor = [UIColor whiteColor];
|
42
|
+
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
43
|
+
UIViewController *rootViewController = [self.reactDelegate createRootViewController];
|
44
|
+
rootViewController.view = rootView;
|
45
|
+
self.window.rootViewController = rootViewController;
|
46
|
+
[self.window makeKeyAndVisible];
|
47
|
+
|
48
|
+
[super application:application didFinishLaunchingWithOptions:launchOptions];
|
49
|
+
|
50
|
+
return YES;
|
51
|
+
}
|
52
|
+
|
53
|
+
- (NSArray<id<RCTBridgeModule>> *)extraModulesForBridge:(RCTBridge *)bridge
|
54
|
+
{
|
55
|
+
// If you'd like to export some custom RCTBridgeModules, add them here!
|
56
|
+
return @[];
|
57
|
+
}
|
58
|
+
|
59
|
+
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge {
|
60
|
+
#ifdef DEBUG
|
61
|
+
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
|
62
|
+
#else
|
63
|
+
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
|
64
|
+
#endif
|
65
|
+
}
|
66
|
+
|
67
|
+
// Linking API
|
68
|
+
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
|
69
|
+
return [RCTLinkingManager application:application openURL:url options:options];
|
70
|
+
}
|
71
|
+
|
72
|
+
// Universal Links
|
73
|
+
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
|
74
|
+
return [RCTLinkingManager application:application
|
75
|
+
continueUserActivity:userActivity
|
76
|
+
restorationHandler:restorationHandler];
|
77
|
+
}
|
78
|
+
|
79
|
+
@end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
// RN 0.68.1, Expo SDK 45 template
|
2
|
+
// The main difference between this and the SDK 44 one is that this is
|
3
|
+
// using React Native 0.68 and is written in Objective-C++
|
4
|
+
|
5
|
+
#import "AppDelegate.h"
|
6
|
+
|
7
|
+
#import <React/RCTBridge.h>
|
8
|
+
#import <React/RCTBundleURLProvider.h>
|
9
|
+
#import <React/RCTRootView.h>
|
10
|
+
#import <React/RCTLinkingManager.h>
|
11
|
+
#import <React/RCTConvert.h>
|
12
|
+
|
13
|
+
#import <React/RCTAppSetupUtils.h>
|
14
|
+
|
15
|
+
#if RCT_NEW_ARCH_ENABLED
|
16
|
+
#import <React/CoreModulesPlugins.h>
|
17
|
+
#import <React/RCTCxxBridgeDelegate.h>
|
18
|
+
#import <React/RCTFabricSurfaceHostingProxyRootView.h>
|
19
|
+
#import <React/RCTSurfacePresenter.h>
|
20
|
+
#import <React/RCTSurfacePresenterBridgeAdapter.h>
|
21
|
+
#import <ReactCommon/RCTTurboModuleManager.h>
|
22
|
+
|
23
|
+
#import <react/config/ReactNativeConfig.h>
|
24
|
+
|
25
|
+
@interface AppDelegate () <RCTCxxBridgeDelegate, RCTTurboModuleManagerDelegate> {
|
26
|
+
RCTTurboModuleManager *_turboModuleManager;
|
27
|
+
RCTSurfacePresenterBridgeAdapter *_bridgeAdapter;
|
28
|
+
std::shared_ptr<const facebook::react::ReactNativeConfig> _reactNativeConfig;
|
29
|
+
facebook::react::ContextContainer::Shared _contextContainer;
|
30
|
+
}
|
31
|
+
@end
|
32
|
+
#endif
|
33
|
+
|
34
|
+
@implementation AppDelegate
|
35
|
+
|
36
|
+
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
37
|
+
{
|
38
|
+
RCTAppSetupPrepareApp(application);
|
39
|
+
|
40
|
+
RCTBridge *bridge = [self.reactDelegate createBridgeWithDelegate:self launchOptions:launchOptions];
|
41
|
+
|
42
|
+
#if RCT_NEW_ARCH_ENABLED
|
43
|
+
_contextContainer = std::make_shared<facebook::react::ContextContainer const>();
|
44
|
+
_reactNativeConfig = std::make_shared<facebook::react::EmptyReactNativeConfig const>();
|
45
|
+
_contextContainer->insert("ReactNativeConfig", _reactNativeConfig);
|
46
|
+
_bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer];
|
47
|
+
bridge.surfacePresenter = _bridgeAdapter.surfacePresenter;
|
48
|
+
#endif
|
49
|
+
|
50
|
+
UIView *rootView = [self.reactDelegate createRootViewWithBridge:bridge moduleName:@"main" initialProperties:nil];
|
51
|
+
|
52
|
+
rootView.backgroundColor = [UIColor whiteColor];
|
53
|
+
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
54
|
+
UIViewController *rootViewController = [self.reactDelegate createRootViewController];
|
55
|
+
rootViewController.view = rootView;
|
56
|
+
self.window.rootViewController = rootViewController;
|
57
|
+
[self.window makeKeyAndVisible];
|
58
|
+
|
59
|
+
[super application:application didFinishLaunchingWithOptions:launchOptions];
|
60
|
+
|
61
|
+
return YES;
|
62
|
+
}
|
63
|
+
|
64
|
+
- (NSArray<id<RCTBridgeModule>> *)extraModulesForBridge:(RCTBridge *)bridge
|
65
|
+
{
|
66
|
+
// If you'd like to export some custom RCTBridgeModules, add them here!
|
67
|
+
return @[];
|
68
|
+
}
|
69
|
+
|
70
|
+
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
|
71
|
+
{
|
72
|
+
#if DEBUG
|
73
|
+
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
|
74
|
+
#else
|
75
|
+
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
|
76
|
+
#endif
|
77
|
+
}
|
78
|
+
|
79
|
+
// Linking API
|
80
|
+
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
|
81
|
+
return [super application:application openURL:url options:options] || [RCTLinkingManager application:application openURL:url options:options];
|
82
|
+
}
|
83
|
+
|
84
|
+
// Universal Links
|
85
|
+
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
|
86
|
+
BOOL result = [RCTLinkingManager application:application continueUserActivity:userActivity restorationHandler:restorationHandler];
|
87
|
+
return [super application:application continueUserActivity:userActivity restorationHandler:restorationHandler] || result;
|
88
|
+
}
|
89
|
+
|
90
|
+
#if RCT_NEW_ARCH_ENABLED
|
91
|
+
|
92
|
+
#pragma mark - RCTCxxBridgeDelegate
|
93
|
+
|
94
|
+
- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge
|
95
|
+
{
|
96
|
+
_turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge
|
97
|
+
delegate:self
|
98
|
+
jsInvoker:bridge.jsCallInvoker];
|
99
|
+
return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager);
|
100
|
+
}
|
101
|
+
|
102
|
+
#pragma mark RCTTurboModuleManagerDelegate
|
103
|
+
|
104
|
+
- (Class)getModuleClassFromName:(const char *)name
|
105
|
+
{
|
106
|
+
return RCTCoreModulesClassProvider(name);
|
107
|
+
}
|
108
|
+
|
109
|
+
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
|
110
|
+
jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
|
111
|
+
{
|
112
|
+
return nullptr;
|
113
|
+
}
|
114
|
+
|
115
|
+
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
|
116
|
+
initParams:
|
117
|
+
(const facebook::react::ObjCTurboModule::InitParams &)params
|
118
|
+
{
|
119
|
+
return nullptr;
|
120
|
+
}
|
121
|
+
|
122
|
+
- (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
|
123
|
+
{
|
124
|
+
return RCTAppSetupDefaultModuleFromClass(moduleClass);
|
125
|
+
}
|
126
|
+
|
127
|
+
#endif
|
128
|
+
|
129
|
+
@end
|
@@ -0,0 +1,343 @@
|
|
1
|
+
import fs from 'fs/promises';
|
2
|
+
import path from 'path';
|
3
|
+
import { beforeEach, describe, expect, it, jest } from '@jest/globals';
|
4
|
+
import { WarningAggregator } from '@expo/config-plugins';
|
5
|
+
import type { AppDelegateProjectFile } from '@expo/config-plugins/build/ios/Paths';
|
6
|
+
import {
|
7
|
+
shouldApplyIosOpenUrlFix,
|
8
|
+
modifyObjcAppDelegate,
|
9
|
+
withOpenUrlFixForAppDelegate,
|
10
|
+
ensureFirebaseSwizzlingIsEnabled,
|
11
|
+
appDelegateOpenUrlInsertionPointAfter,
|
12
|
+
multiline_appDelegateOpenUrlInsertionPointAfter,
|
13
|
+
} from '../src/ios/openUrlFix';
|
14
|
+
import type { ExpoConfigPluginEntry } from '../src/ios/openUrlFix';
|
15
|
+
|
16
|
+
describe('Config Plugin iOS Tests - openUrlFix', () => {
|
17
|
+
beforeEach(function () {
|
18
|
+
jest.resetAllMocks();
|
19
|
+
});
|
20
|
+
|
21
|
+
it('is disabled by default', async () => {
|
22
|
+
const config = {
|
23
|
+
name: 'TestName',
|
24
|
+
slug: 'TestSlug',
|
25
|
+
};
|
26
|
+
|
27
|
+
expect(
|
28
|
+
shouldApplyIosOpenUrlFix({
|
29
|
+
config,
|
30
|
+
}),
|
31
|
+
).toBe(false);
|
32
|
+
|
33
|
+
expect(
|
34
|
+
shouldApplyIosOpenUrlFix({
|
35
|
+
config,
|
36
|
+
props: {},
|
37
|
+
}),
|
38
|
+
).toBe(false);
|
39
|
+
|
40
|
+
expect(
|
41
|
+
shouldApplyIosOpenUrlFix({
|
42
|
+
config,
|
43
|
+
props: {
|
44
|
+
ios: {},
|
45
|
+
},
|
46
|
+
}),
|
47
|
+
).toBe(false);
|
48
|
+
|
49
|
+
expect(
|
50
|
+
shouldApplyIosOpenUrlFix({
|
51
|
+
config,
|
52
|
+
props: {
|
53
|
+
ios: {
|
54
|
+
captchaOpenUrlFix: undefined,
|
55
|
+
},
|
56
|
+
},
|
57
|
+
}),
|
58
|
+
).toBe(false);
|
59
|
+
|
60
|
+
expect(
|
61
|
+
shouldApplyIosOpenUrlFix({
|
62
|
+
config,
|
63
|
+
props: {
|
64
|
+
ios: {
|
65
|
+
captchaOpenUrlFix: 'default',
|
66
|
+
},
|
67
|
+
},
|
68
|
+
}),
|
69
|
+
).toBe(false);
|
70
|
+
|
71
|
+
expect(
|
72
|
+
shouldApplyIosOpenUrlFix({
|
73
|
+
config,
|
74
|
+
props: {
|
75
|
+
ios: {
|
76
|
+
captchaOpenUrlFix: false,
|
77
|
+
},
|
78
|
+
},
|
79
|
+
}),
|
80
|
+
).toBe(false);
|
81
|
+
|
82
|
+
expect(
|
83
|
+
shouldApplyIosOpenUrlFix({
|
84
|
+
config,
|
85
|
+
props: {
|
86
|
+
ios: {
|
87
|
+
captchaOpenUrlFix: true,
|
88
|
+
},
|
89
|
+
},
|
90
|
+
}),
|
91
|
+
).toBe(true);
|
92
|
+
});
|
93
|
+
|
94
|
+
it('is enabled by default when expo-router is found', async () => {
|
95
|
+
const cases: ExpoConfigPluginEntry[] = ['expo-router', ['expo-router'], ['expo-router', {}]];
|
96
|
+
|
97
|
+
for (const routerPluginEntry of cases) {
|
98
|
+
const plugins: ExpoConfigPluginEntry[] = [
|
99
|
+
'something',
|
100
|
+
[],
|
101
|
+
['something-else', { foo: 'bar' }],
|
102
|
+
routerPluginEntry,
|
103
|
+
];
|
104
|
+
|
105
|
+
const config = {
|
106
|
+
name: 'TestName',
|
107
|
+
slug: 'TestSlug',
|
108
|
+
plugins,
|
109
|
+
};
|
110
|
+
|
111
|
+
expect(
|
112
|
+
shouldApplyIosOpenUrlFix({
|
113
|
+
config,
|
114
|
+
props: {},
|
115
|
+
}),
|
116
|
+
).toBe(true);
|
117
|
+
|
118
|
+
expect(
|
119
|
+
shouldApplyIosOpenUrlFix({
|
120
|
+
config,
|
121
|
+
props: {
|
122
|
+
ios: {},
|
123
|
+
},
|
124
|
+
}),
|
125
|
+
).toBe(true);
|
126
|
+
|
127
|
+
expect(
|
128
|
+
shouldApplyIosOpenUrlFix({
|
129
|
+
config,
|
130
|
+
props: {
|
131
|
+
ios: {
|
132
|
+
captchaOpenUrlFix: undefined,
|
133
|
+
},
|
134
|
+
},
|
135
|
+
}),
|
136
|
+
).toBe(true);
|
137
|
+
|
138
|
+
expect(
|
139
|
+
shouldApplyIosOpenUrlFix({
|
140
|
+
config,
|
141
|
+
props: {
|
142
|
+
ios: {
|
143
|
+
captchaOpenUrlFix: 'default',
|
144
|
+
},
|
145
|
+
},
|
146
|
+
}),
|
147
|
+
).toBe(true);
|
148
|
+
|
149
|
+
expect(
|
150
|
+
shouldApplyIosOpenUrlFix({
|
151
|
+
config,
|
152
|
+
props: {
|
153
|
+
ios: {
|
154
|
+
captchaOpenUrlFix: false,
|
155
|
+
},
|
156
|
+
},
|
157
|
+
}),
|
158
|
+
).toBe(false);
|
159
|
+
|
160
|
+
expect(
|
161
|
+
shouldApplyIosOpenUrlFix({
|
162
|
+
config,
|
163
|
+
props: {
|
164
|
+
ios: {
|
165
|
+
captchaOpenUrlFix: true,
|
166
|
+
},
|
167
|
+
},
|
168
|
+
}),
|
169
|
+
).toBe(true);
|
170
|
+
}
|
171
|
+
});
|
172
|
+
|
173
|
+
it('throws an error for invalid config', () => {
|
174
|
+
expect(() =>
|
175
|
+
shouldApplyIosOpenUrlFix({
|
176
|
+
config: {
|
177
|
+
name: 'TestName',
|
178
|
+
slug: 'TestSlug',
|
179
|
+
},
|
180
|
+
props: {
|
181
|
+
ios: {
|
182
|
+
// @ts-ignore testing invalid argument
|
183
|
+
captchaOpenUrlFix: Math.PI,
|
184
|
+
},
|
185
|
+
},
|
186
|
+
}),
|
187
|
+
).toThrow("Unexpected value for 'captchaOpenUrlFix' config option");
|
188
|
+
});
|
189
|
+
|
190
|
+
const appDelegateFixturesPatch = [
|
191
|
+
'AppDelegate_bare_sdk43.m',
|
192
|
+
'AppDelegate_sdk44.m',
|
193
|
+
'AppDelegate_sdk45.mm',
|
194
|
+
];
|
195
|
+
appDelegateFixturesPatch.forEach(fixtureName => {
|
196
|
+
it(`munges AppDelegate correctly - ${fixtureName}`, async () => {
|
197
|
+
const fixturePath = path.join(__dirname, 'fixtures', fixtureName);
|
198
|
+
const appDelegate = await fs.readFile(fixturePath, { encoding: 'utf-8' });
|
199
|
+
const result = modifyObjcAppDelegate(appDelegate);
|
200
|
+
expect(result).toMatchSnapshot();
|
201
|
+
});
|
202
|
+
|
203
|
+
it(`prints warning message when configured to default and AppDelegate is modified`, async () => {
|
204
|
+
const fixturePath = path.join(__dirname, 'fixtures', fixtureName);
|
205
|
+
const appDelegate = await fs.readFile(fixturePath, { encoding: 'utf-8' });
|
206
|
+
const config = {
|
207
|
+
name: 'TestName',
|
208
|
+
slug: 'TestSlug',
|
209
|
+
modRequest: { projectRoot: path.join(__dirname, 'fixtures') } as any,
|
210
|
+
modResults: {
|
211
|
+
path: fixturePath,
|
212
|
+
language: 'objc',
|
213
|
+
contents: appDelegate,
|
214
|
+
} as AppDelegateProjectFile,
|
215
|
+
modRawConfig: { name: 'TestName', slug: 'TestSlug' },
|
216
|
+
};
|
217
|
+
const props = undefined;
|
218
|
+
const spy = jest
|
219
|
+
.spyOn(WarningAggregator, 'addWarningIOS')
|
220
|
+
.mockImplementation(() => undefined);
|
221
|
+
withOpenUrlFixForAppDelegate({ config, props });
|
222
|
+
expect(spy).toHaveBeenCalledWith(
|
223
|
+
'@react-native-firebase/auth',
|
224
|
+
'modifying iOS AppDelegate openURL method to ignore firebaseauth reCAPTCHA redirect URLs',
|
225
|
+
);
|
226
|
+
});
|
227
|
+
});
|
228
|
+
|
229
|
+
const appDelegateFixturesNoop = ['AppDelegate_sdk42.m', 'AppDelegate_fallback.m'];
|
230
|
+
appDelegateFixturesNoop.forEach(fixtureName => {
|
231
|
+
it(`skips AppDelegate without openURL - ${fixtureName}`, async () => {
|
232
|
+
const fixturePath = path.join(__dirname, 'fixtures', fixtureName);
|
233
|
+
const appDelegate = await fs.readFile(fixturePath, { encoding: 'utf-8' });
|
234
|
+
const config = {
|
235
|
+
name: 'TestName',
|
236
|
+
slug: 'TestSlug',
|
237
|
+
plugins: ['expo-router'],
|
238
|
+
modRequest: { projectRoot: path.join(__dirname, 'fixtures') } as any,
|
239
|
+
modResults: {
|
240
|
+
path: fixturePath,
|
241
|
+
language: 'objc',
|
242
|
+
contents: appDelegate,
|
243
|
+
} as AppDelegateProjectFile,
|
244
|
+
modRawConfig: { name: 'TestName', slug: 'TestSlug' },
|
245
|
+
};
|
246
|
+
const props = undefined;
|
247
|
+
const spy = jest
|
248
|
+
.spyOn(WarningAggregator, 'addWarningIOS')
|
249
|
+
.mockImplementation(() => undefined);
|
250
|
+
const result = withOpenUrlFixForAppDelegate({ config, props });
|
251
|
+
expect(result.modResults.contents).toBe(appDelegate);
|
252
|
+
expect(spy).toHaveBeenCalledWith(
|
253
|
+
'@react-native-firebase/auth',
|
254
|
+
"Skipping iOS openURL fix because no 'openURL' method was found",
|
255
|
+
);
|
256
|
+
});
|
257
|
+
|
258
|
+
it(`errors when enabled but openURL not found - ${fixtureName}`, async () => {
|
259
|
+
const fixturePath = path.join(__dirname, 'fixtures', fixtureName);
|
260
|
+
const appDelegate = await fs.readFile(fixturePath, { encoding: 'utf-8' });
|
261
|
+
const config = {
|
262
|
+
name: 'TestName',
|
263
|
+
slug: 'TestSlug',
|
264
|
+
modRequest: { projectRoot: path.join(__dirname, 'fixtures') } as any,
|
265
|
+
modResults: {
|
266
|
+
path: fixturePath,
|
267
|
+
language: 'objc',
|
268
|
+
contents: appDelegate,
|
269
|
+
} as AppDelegateProjectFile,
|
270
|
+
modRawConfig: { name: 'TestName', slug: 'TestSlug' },
|
271
|
+
};
|
272
|
+
const props = {
|
273
|
+
ios: {
|
274
|
+
captchaOpenUrlFix: true,
|
275
|
+
},
|
276
|
+
};
|
277
|
+
expect(() => withOpenUrlFixForAppDelegate({ config, props })).toThrow(
|
278
|
+
"Failed to apply iOS openURL fix because no 'openURL' method was found",
|
279
|
+
);
|
280
|
+
});
|
281
|
+
});
|
282
|
+
|
283
|
+
it(`should issue error when openURL is found but patching fails`, () => {
|
284
|
+
const snippet = [
|
285
|
+
'// preamble goes here\nint theAnswer()\n{\n\treturn 42;\n}',
|
286
|
+
'- (BOOL)application:(UIApplication *)application options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options openURL:(NSURL *)url\n{',
|
287
|
+
'int x = theAnswer();\n',
|
288
|
+
].join('');
|
289
|
+
expect(() => modifyObjcAppDelegate(snippet)).toThrow(
|
290
|
+
"Failed to apply 'captchaOpenUrlFix' but detected 'openURL' method.",
|
291
|
+
);
|
292
|
+
});
|
293
|
+
|
294
|
+
const positiveTemplateCases = [
|
295
|
+
'- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {\n\tint x=3;',
|
296
|
+
'- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options',
|
297
|
+
'\t- (\tBOOL ) application : ( UIApplication*\t) application openURL : ( NSURL*) url options : ( NSDictionary < UIApplicationOpenURLOptionsKey , id > *)\toptions',
|
298
|
+
' - ( BOOL ) application : ( UIApplication*\t) application openURL : ( NSURL*) url options : ( NSDictionary < UIApplicationOpenURLOptionsKey , id > *)\toptions\n\n{\n\n',
|
299
|
+
];
|
300
|
+
positiveTemplateCases.forEach((snippet, caseIdx) => {
|
301
|
+
it(`must match positiveTemplateCases[${caseIdx}]`, () => {
|
302
|
+
expect(appDelegateOpenUrlInsertionPointAfter.test(snippet)).toBe(true);
|
303
|
+
if (snippet.match(/{/)) {
|
304
|
+
expect(multiline_appDelegateOpenUrlInsertionPointAfter.test(snippet)).toBe(true);
|
305
|
+
expect(modifyObjcAppDelegate(snippet)).toMatchSnapshot();
|
306
|
+
}
|
307
|
+
});
|
308
|
+
});
|
309
|
+
|
310
|
+
const negativeTemplateCases = [
|
311
|
+
'- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity {',
|
312
|
+
'- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url',
|
313
|
+
'\t( BOOL ) application : ( UIApplication*\t) application openURL : ( NSURL*) url options : ( NSDictionary < UIApplicationOpenURLOptionsKey , id > *)\toptions',
|
314
|
+
];
|
315
|
+
negativeTemplateCases.forEach((snippet, caseIdx) => {
|
316
|
+
it(`must not match negativeTemplateCases[${caseIdx}]`, () => {
|
317
|
+
expect(appDelegateOpenUrlInsertionPointAfter.test(snippet)).toBe(false);
|
318
|
+
});
|
319
|
+
});
|
320
|
+
|
321
|
+
it(`rejects projects with swizzling disabled`, () => {
|
322
|
+
const config = {
|
323
|
+
name: 'TestName',
|
324
|
+
slug: 'TestSlug',
|
325
|
+
plugins: ['expo-router'],
|
326
|
+
modRequest: { projectRoot: path.join(__dirname, 'fixtures') } as any,
|
327
|
+
modResults: {
|
328
|
+
path: path.join(__dirname, 'fixtures', '/path/to/Info.plist'),
|
329
|
+
language: 'plist',
|
330
|
+
contents: '',
|
331
|
+
},
|
332
|
+
modRawConfig: { name: 'TestName', slug: 'TestSlug' },
|
333
|
+
ios: {
|
334
|
+
infoPlist: {
|
335
|
+
FirebaseAppDelegateProxyEnabled: false,
|
336
|
+
},
|
337
|
+
},
|
338
|
+
};
|
339
|
+
expect(() => ensureFirebaseSwizzlingIsEnabled(config)).toThrow(
|
340
|
+
'Your app has disabled swizzling by setting FirebaseAppDelegateProxyEnabled=false in its Info.plist.',
|
341
|
+
);
|
342
|
+
});
|
343
|
+
});
|
@@ -2,7 +2,7 @@ import path from 'path';
|
|
2
2
|
import { beforeEach, describe, expect, it, jest } from '@jest/globals';
|
3
3
|
import { setUrlTypesForCaptcha } from '../src/ios/urlTypes';
|
4
4
|
|
5
|
-
describe('Config Plugin iOS Tests', () => {
|
5
|
+
describe('Config Plugin iOS Tests - urlTypes', () => {
|
6
6
|
beforeEach(function () {
|
7
7
|
jest.resetAllMocks();
|
8
8
|
});
|
package/plugin/build/index.d.ts
CHANGED
package/plugin/build/index.js
CHANGED
@@ -5,10 +5,11 @@ const ios_1 = require("./ios");
|
|
5
5
|
/**
|
6
6
|
* A config plugin for configuring `@react-native-firebase/auth`
|
7
7
|
*/
|
8
|
-
const withRnFirebaseAuth = config => {
|
8
|
+
const withRnFirebaseAuth = (config, props) => {
|
9
9
|
return (0, config_plugins_1.withPlugins)(config, [
|
10
10
|
// iOS
|
11
|
-
ios_1.withIosCaptchaUrlTypes,
|
11
|
+
[ios_1.withIosCaptchaUrlTypes, props],
|
12
|
+
[ios_1.withIosCaptchaOpenUrlFix, props],
|
12
13
|
]);
|
13
14
|
};
|
14
15
|
const pak = require('@react-native-firebase/auth/package.json');
|
@@ -1,5 +1,7 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.withIosCaptchaUrlTypes = void 0;
|
3
|
+
exports.withIosCaptchaOpenUrlFix = exports.withIosCaptchaUrlTypes = void 0;
|
4
4
|
const urlTypes_1 = require("./urlTypes");
|
5
5
|
Object.defineProperty(exports, "withIosCaptchaUrlTypes", { enumerable: true, get: function () { return urlTypes_1.withIosCaptchaUrlTypes; } });
|
6
|
+
const openUrlFix_1 = require("./openUrlFix");
|
7
|
+
Object.defineProperty(exports, "withIosCaptchaOpenUrlFix", { enumerable: true, get: function () { return openUrlFix_1.withIosCaptchaOpenUrlFix; } });
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import { ConfigPlugin, ExportedConfigWithProps } from '@expo/config-plugins';
|
2
|
+
import type { ExpoConfig } from '@expo/config/build/Config.types';
|
3
|
+
import type { AppDelegateProjectFile } from '@expo/config-plugins/build/ios/Paths';
|
4
|
+
import type { InfoPlist } from '@expo/config-plugins/build/ios/IosConfig.types';
|
5
|
+
import { PluginConfigType } from '../pluginConfig';
|
6
|
+
export declare const withIosCaptchaOpenUrlFix: ConfigPlugin<PluginConfigType>;
|
7
|
+
export declare function shouldApplyIosOpenUrlFix({ config, props, }: {
|
8
|
+
config: ExpoConfig;
|
9
|
+
props?: PluginConfigType;
|
10
|
+
}): boolean;
|
11
|
+
export declare function withOpenUrlFixForAppDelegate({ config, props, }: {
|
12
|
+
config: ExportedConfigWithProps<AppDelegateProjectFile>;
|
13
|
+
props?: PluginConfigType;
|
14
|
+
}): ExportedConfigWithProps<AppDelegateProjectFile>;
|
15
|
+
export declare const appDelegateOpenUrlInsertionPointAfter: RegExp;
|
16
|
+
export declare const multiline_appDelegateOpenUrlInsertionPointAfter: RegExp;
|
17
|
+
export declare function modifyObjcAppDelegate(contents: string): string | null;
|
18
|
+
export type ExpoConfigPluginEntry = string | [] | [string] | [string, any];
|
19
|
+
export declare function isFirebaseSwizzlingDisabled(config: ExportedConfigWithProps<InfoPlist>): boolean;
|
20
|
+
export declare function ensureFirebaseSwizzlingIsEnabled(config: ExportedConfigWithProps<InfoPlist>): boolean;
|