@thoughtbot/react-native-social-auth 0.1.0 → 0.2.0
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/README.md +62 -7
- package/app.plugin.js +1 -0
- package/lib/typescript/plugin/src/withSocialAuth.d.ts +28 -0
- package/lib/typescript/plugin/src/withSocialAuth.d.ts.map +1 -0
- package/package.json +38 -10
- package/plugin/build/withSocialAuth.d.ts +27 -0
- package/plugin/build/withSocialAuth.js +119 -0
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@ Drop-in Google Sign-In for React Native using Android's Credential Manager and t
|
|
|
4
4
|
|
|
5
5
|
**Platform support:** ✅ Android · ✅ iOS
|
|
6
6
|
|
|
7
|
+
> ⚠️ **Early development.** This package is pre-1.0 and under active development. The public API — configuration options, method signatures, `GoogleSignInButton` props, and error codes — may change between minor versions without a deprecation cycle. If you need stability, pin the exact version in `package.json` (`"@thoughtbot/react-native-social-auth": "0.x.y"`, not `"^0.x.y"`) and check the [CHANGELOG](CHANGELOG.md) before upgrading. We aim for a stable `1.0.0` once the API has been battle-tested.
|
|
8
|
+
|
|
7
9
|
## Features
|
|
8
10
|
|
|
9
11
|
- Android **Credential Manager** and iOS **GoogleSignIn-iOS SDK** integration, both with auto-sign-in + interactive fallback
|
|
@@ -65,6 +67,8 @@ The Web client ID is what your code references for the ID-token audience; each p
|
|
|
65
67
|
|
|
66
68
|
In addition to the Cloud Console step above, the host app needs two iOS-specific changes.
|
|
67
69
|
|
|
70
|
+
> **Using Expo?** Skip the manual `Info.plist` and `AppDelegate` edits below — [our config plugin](#expo-config-plugin) handles them during `expo prebuild`. Bare React Native CLI users continue with the manual steps in this section.
|
|
71
|
+
|
|
68
72
|
### 1. Register the OAuth URL scheme
|
|
69
73
|
|
|
70
74
|
Google routes the sign-in callback back into your app via a custom URL scheme. Add the reversed iOS Client ID to `Info.plist`:
|
|
@@ -85,29 +89,30 @@ If you use **Expo**, declare it in `app.json` under `expo.ios.infoPlist.CFBundle
|
|
|
85
89
|
|
|
86
90
|
### 2. Forward incoming URLs to the SDK
|
|
87
91
|
|
|
88
|
-
In your `AppDelegate`, forward `application(_:open:options:)` to `
|
|
92
|
+
In your `AppDelegate`, forward `application(_:open:options:)` to `GIDSignIn.sharedInstance.handle(_:)`. Importing `GoogleSignIn` here pulls in the official GoogleSignIn-iOS SDK module (already a transitive dependency of this package).
|
|
89
93
|
|
|
90
94
|
**Swift:**
|
|
91
95
|
```swift
|
|
92
|
-
import
|
|
96
|
+
import GoogleSignIn
|
|
93
97
|
|
|
94
|
-
|
|
98
|
+
@objc
|
|
99
|
+
public func application(
|
|
95
100
|
_ app: UIApplication,
|
|
96
101
|
open url: URL,
|
|
97
102
|
options: [UIApplication.OpenURLOptionsKey: Any] = [:]
|
|
98
103
|
) -> Bool {
|
|
99
|
-
return
|
|
104
|
+
return GIDSignIn.sharedInstance.handle(url)
|
|
100
105
|
}
|
|
101
106
|
```
|
|
102
107
|
|
|
103
108
|
**Objective-C:**
|
|
104
109
|
```objc
|
|
105
|
-
#import <
|
|
110
|
+
#import <GoogleSignIn/GoogleSignIn.h>
|
|
106
111
|
|
|
107
112
|
- (BOOL)application:(UIApplication *)app
|
|
108
113
|
openURL:(NSURL *)url
|
|
109
114
|
options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {
|
|
110
|
-
return [
|
|
115
|
+
return [[GIDSignIn sharedInstance] handleURL:url];
|
|
111
116
|
}
|
|
112
117
|
```
|
|
113
118
|
|
|
@@ -124,6 +129,56 @@ GoogleSignIn.configure({
|
|
|
124
129
|
|
|
125
130
|
Finally, run `cd ios && pod install` after installing the package.
|
|
126
131
|
|
|
132
|
+
## Expo config plugin
|
|
133
|
+
|
|
134
|
+
This package ships an Expo config plugin so you don't have to hand-edit `Info.plist` or `AppDelegate` in Expo projects. **Both React Native CLI and Expo projects are supported** — pick the setup section that matches your project.
|
|
135
|
+
|
|
136
|
+
> **Heads up:** Expo Go cannot ship third-party native modules. You must use a [development build](https://docs.expo.dev/develop/development-builds/introduction/) (via `expo-dev-client` and EAS Build) or the bare workflow.
|
|
137
|
+
|
|
138
|
+
### Install
|
|
139
|
+
|
|
140
|
+
```sh
|
|
141
|
+
npx expo install @thoughtbot/react-native-social-auth react-native-svg
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Add the plugin
|
|
145
|
+
|
|
146
|
+
In `app.config.ts` (or `app.json`):
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
export default {
|
|
150
|
+
expo: {
|
|
151
|
+
// ...
|
|
152
|
+
plugins: [
|
|
153
|
+
[
|
|
154
|
+
'@thoughtbot/react-native-social-auth',
|
|
155
|
+
{
|
|
156
|
+
iosClientId: process.env.EXPO_PUBLIC_GOOGLE_IOS_CLIENT_ID,
|
|
157
|
+
},
|
|
158
|
+
],
|
|
159
|
+
],
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Plugin props
|
|
165
|
+
|
|
166
|
+
| Prop | Type | Required for iOS | Description |
|
|
167
|
+
| ------------- | -------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
|
168
|
+
| `iosClientId` | `string` | Yes | Your iOS OAuth Client ID (e.g. `123456-abc.apps.googleusercontent.com`). The plugin reverses it and registers the URL scheme. |
|
|
169
|
+
|
|
170
|
+
Omit `iosClientId` if you only target Android — the plugin becomes a no-op on iOS and logs a warning.
|
|
171
|
+
|
|
172
|
+
### Regenerate native code
|
|
173
|
+
|
|
174
|
+
```sh
|
|
175
|
+
npx expo prebuild --clean
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
This runs the plugin, which writes the reversed iOS Client ID into `Info.plist`'s `CFBundleURLSchemes` and adds the `application(_:open:options:)` URL forwarder to `AppDelegate`. Subsequent prebuilds are idempotent — the plugin won't re-inject if its marker is already present.
|
|
179
|
+
|
|
180
|
+
You still call `GoogleSignIn.configure({ webClientId, iosClientId })` from JS at runtime (the plugin handles the native bits; it doesn't replace `configure()`).
|
|
181
|
+
|
|
127
182
|
## Quick start
|
|
128
183
|
|
|
129
184
|
```tsx
|
|
@@ -173,7 +228,7 @@ Stores credentials and options used by subsequent calls.
|
|
|
173
228
|
| Field | Type | Required | Description |
|
|
174
229
|
| ---------------- | ---------- | -------- | ------------------------------------------------------------------------------------------------- |
|
|
175
230
|
| `webClientId` | `string` | Yes | The **Web application** OAuth Client ID. This is the audience of the issued ID token. |
|
|
176
|
-
| `iosClientId` | `string` | No | iOS OAuth Client ID
|
|
231
|
+
| `iosClientId` | `string` | No | iOS OAuth Client ID. |
|
|
177
232
|
| `offlineAccess` | `boolean` | No | Request a server auth code in addition to the ID token. Default `false`. |
|
|
178
233
|
| `scopes` | `string[]` | No | Additional OAuth scopes beyond the default profile/email. |
|
|
179
234
|
| `hostedDomain` | `string` | No | Restrict sign-in to a Google Workspace domain. |
|
package/app.plugin.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('./plugin/build/withSocialAuth').default;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ConfigPlugin } from '@expo/config-plugins';
|
|
2
|
+
export type SocialAuthPluginProps = {
|
|
3
|
+
/**
|
|
4
|
+
* The OAuth 2.0 iOS application client ID from Google Cloud Console
|
|
5
|
+
* (format: `*.apps.googleusercontent.com`). Required to register the
|
|
6
|
+
* URL scheme that GoogleSignIn-iOS uses for its OAuth callback.
|
|
7
|
+
*
|
|
8
|
+
* Omit for Android-only setups — the plugin becomes a no-op on iOS.
|
|
9
|
+
*/
|
|
10
|
+
iosClientId?: string;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Compute the reversed iOS Client ID that GoogleSignIn-iOS expects as a
|
|
14
|
+
* `CFBundleURLSchemes` entry.
|
|
15
|
+
*
|
|
16
|
+
* Example:
|
|
17
|
+
* `123-abc.apps.googleusercontent.com`
|
|
18
|
+
* → `com.googleusercontent.apps.123-abc`
|
|
19
|
+
*/
|
|
20
|
+
/** @internal — exported for tests only. */
|
|
21
|
+
export declare function reverseClientId(iosClientId: string): string;
|
|
22
|
+
/** @internal — exported for tests only. */
|
|
23
|
+
export declare function injectSwiftURLHandler(contents: string): string;
|
|
24
|
+
/** @internal — exported for tests only. */
|
|
25
|
+
export declare function injectObjCURLHandler(contents: string): string;
|
|
26
|
+
declare const _default: ConfigPlugin<void | SocialAuthPluginProps>;
|
|
27
|
+
export default _default;
|
|
28
|
+
//# sourceMappingURL=withSocialAuth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withSocialAuth.d.ts","sourceRoot":"","sources":["../../../../plugin/src/withSocialAuth.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAIzD,MAAM,MAAM,qBAAqB,GAAG;IAClC;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAKF;;;;;;;GAOG;AACH,2CAA2C;AAC3C,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAS3D;AAyCD,2CAA2C;AAC3C,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA8B9D;AAED,2CAA2C;AAC3C,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAyB7D;;AAyBD,wBAA6E"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thoughtbot/react-native-social-auth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "OAuth sign in buttons and methods for React Native",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"types": "./lib/typescript/src/index.d.ts",
|
|
11
11
|
"default": "./lib/module/index.js"
|
|
12
12
|
},
|
|
13
|
-
"./package.json": "./package.json"
|
|
13
|
+
"./package.json": "./package.json",
|
|
14
|
+
"./app.plugin.js": "./app.plugin.js"
|
|
14
15
|
},
|
|
15
16
|
"files": [
|
|
16
17
|
"src",
|
|
@@ -18,6 +19,8 @@
|
|
|
18
19
|
"android",
|
|
19
20
|
"ios",
|
|
20
21
|
"cpp",
|
|
22
|
+
"plugin/build",
|
|
23
|
+
"app.plugin.js",
|
|
21
24
|
"*.podspec",
|
|
22
25
|
"react-native.config.js",
|
|
23
26
|
"!ios/build",
|
|
@@ -33,11 +36,12 @@
|
|
|
33
36
|
],
|
|
34
37
|
"scripts": {
|
|
35
38
|
"example": "yarn workspace @thoughtbot/react-native-social-auth-example",
|
|
36
|
-
"clean": "del-cli lib",
|
|
37
|
-
"prepare": "bob build",
|
|
39
|
+
"clean": "del-cli lib plugin/build",
|
|
40
|
+
"prepare": "bob build && yarn build:plugin",
|
|
41
|
+
"build:plugin": "tsc --project plugin/tsconfig.json",
|
|
38
42
|
"typecheck": "tsc",
|
|
39
43
|
"test": "jest",
|
|
40
|
-
"release": "release-it
|
|
44
|
+
"release": "release-it",
|
|
41
45
|
"lint": "eslint \"**/*.{js,ts,tsx}\""
|
|
42
46
|
},
|
|
43
47
|
"keywords": [
|
|
@@ -60,19 +64,22 @@
|
|
|
60
64
|
},
|
|
61
65
|
"homepage": "https://github.com/thoughtbot/react-native-social-auth#readme",
|
|
62
66
|
"publishConfig": {
|
|
63
|
-
"registry": "https://registry.npmjs.org/"
|
|
67
|
+
"registry": "https://registry.npmjs.org/",
|
|
68
|
+
"access": "public"
|
|
64
69
|
},
|
|
65
70
|
"devDependencies": {
|
|
66
71
|
"@commitlint/config-conventional": "^20.5.0",
|
|
67
72
|
"@eslint/compat": "^2.0.3",
|
|
68
73
|
"@eslint/eslintrc": "^3.3.5",
|
|
69
74
|
"@eslint/js": "^10.0.1",
|
|
75
|
+
"@expo/config-plugins": "^9",
|
|
70
76
|
"@jest/globals": "^30.0.0",
|
|
71
77
|
"@react-native/babel-preset": "0.85.0",
|
|
72
78
|
"@react-native/eslint-config": "0.85.0",
|
|
73
79
|
"@react-native/jest-preset": "0.85.0",
|
|
74
80
|
"@release-it/conventional-changelog": "^10.0.6",
|
|
75
81
|
"@testing-library/react-native": "^13.3",
|
|
82
|
+
"@types/node": "^26.0.1",
|
|
76
83
|
"@types/react": "^19.2.0",
|
|
77
84
|
"@types/react-test-renderer": "^19",
|
|
78
85
|
"commitlint": "^20.5.0",
|
|
@@ -81,6 +88,7 @@
|
|
|
81
88
|
"eslint-config-prettier": "^10.1.8",
|
|
82
89
|
"eslint-plugin-ft-flow": "^3.0.11",
|
|
83
90
|
"eslint-plugin-prettier": "^5.5.5",
|
|
91
|
+
"expo": "^56.0.12",
|
|
84
92
|
"jest": "^30.3.0",
|
|
85
93
|
"lefthook": "^2.1.4",
|
|
86
94
|
"prettier": "^3.8.1",
|
|
@@ -94,10 +102,16 @@
|
|
|
94
102
|
"typescript": "^6.0.2"
|
|
95
103
|
},
|
|
96
104
|
"peerDependencies": {
|
|
105
|
+
"@expo/config-plugins": ">=9.0.0",
|
|
97
106
|
"react": "*",
|
|
98
107
|
"react-native": "*",
|
|
99
108
|
"react-native-svg": ">=13.0.0"
|
|
100
109
|
},
|
|
110
|
+
"peerDependenciesMeta": {
|
|
111
|
+
"@expo/config-plugins": {
|
|
112
|
+
"optional": true
|
|
113
|
+
}
|
|
114
|
+
},
|
|
101
115
|
"workspaces": [
|
|
102
116
|
"example"
|
|
103
117
|
],
|
|
@@ -143,19 +157,33 @@
|
|
|
143
157
|
"release-it": {
|
|
144
158
|
"git": {
|
|
145
159
|
"commitMessage": "chore: release ${version}",
|
|
146
|
-
"tagName": "v${version}"
|
|
160
|
+
"tagName": "v${version}",
|
|
161
|
+
"tagAnnotation": "Release ${version}",
|
|
162
|
+
"requireCleanWorkingDir": true,
|
|
163
|
+
"push": true
|
|
147
164
|
},
|
|
148
165
|
"npm": {
|
|
149
|
-
"publish": true
|
|
166
|
+
"publish": true,
|
|
167
|
+
"skipChecks": true
|
|
150
168
|
},
|
|
151
169
|
"github": {
|
|
152
|
-
"release": true
|
|
170
|
+
"release": true,
|
|
171
|
+
"releaseName": "v${version}"
|
|
172
|
+
},
|
|
173
|
+
"hooks": {
|
|
174
|
+
"before:init": [
|
|
175
|
+
"yarn lint",
|
|
176
|
+
"yarn typecheck",
|
|
177
|
+
"yarn test --maxWorkers=2"
|
|
178
|
+
],
|
|
179
|
+
"after:bump": "yarn prepare"
|
|
153
180
|
},
|
|
154
181
|
"plugins": {
|
|
155
182
|
"@release-it/conventional-changelog": {
|
|
156
183
|
"preset": {
|
|
157
184
|
"name": "angular"
|
|
158
|
-
}
|
|
185
|
+
},
|
|
186
|
+
"infile": "CHANGELOG.md"
|
|
159
187
|
}
|
|
160
188
|
}
|
|
161
189
|
},
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ConfigPlugin } from '@expo/config-plugins';
|
|
2
|
+
export type SocialAuthPluginProps = {
|
|
3
|
+
/**
|
|
4
|
+
* The OAuth 2.0 iOS application client ID from Google Cloud Console
|
|
5
|
+
* (format: `*.apps.googleusercontent.com`). Required to register the
|
|
6
|
+
* URL scheme that GoogleSignIn-iOS uses for its OAuth callback.
|
|
7
|
+
*
|
|
8
|
+
* Omit for Android-only setups — the plugin becomes a no-op on iOS.
|
|
9
|
+
*/
|
|
10
|
+
iosClientId?: string;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Compute the reversed iOS Client ID that GoogleSignIn-iOS expects as a
|
|
14
|
+
* `CFBundleURLSchemes` entry.
|
|
15
|
+
*
|
|
16
|
+
* Example:
|
|
17
|
+
* `123-abc.apps.googleusercontent.com`
|
|
18
|
+
* → `com.googleusercontent.apps.123-abc`
|
|
19
|
+
*/
|
|
20
|
+
/** @internal — exported for tests only. */
|
|
21
|
+
export declare function reverseClientId(iosClientId: string): string;
|
|
22
|
+
/** @internal — exported for tests only. */
|
|
23
|
+
export declare function injectSwiftURLHandler(contents: string): string;
|
|
24
|
+
/** @internal — exported for tests only. */
|
|
25
|
+
export declare function injectObjCURLHandler(contents: string): string;
|
|
26
|
+
declare const _default: ConfigPlugin<void | SocialAuthPluginProps>;
|
|
27
|
+
export default _default;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.reverseClientId = reverseClientId;
|
|
4
|
+
exports.injectSwiftURLHandler = injectSwiftURLHandler;
|
|
5
|
+
exports.injectObjCURLHandler = injectObjCURLHandler;
|
|
6
|
+
const config_plugins_1 = require("@expo/config-plugins");
|
|
7
|
+
const pkg = require('../../package.json');
|
|
8
|
+
const PLUGIN_NAME = '@thoughtbot/react-native-social-auth';
|
|
9
|
+
const MARKER = '/* @thoughtbot/react-native-social-auth: URL handler */';
|
|
10
|
+
/**
|
|
11
|
+
* Compute the reversed iOS Client ID that GoogleSignIn-iOS expects as a
|
|
12
|
+
* `CFBundleURLSchemes` entry.
|
|
13
|
+
*
|
|
14
|
+
* Example:
|
|
15
|
+
* `123-abc.apps.googleusercontent.com`
|
|
16
|
+
* → `com.googleusercontent.apps.123-abc`
|
|
17
|
+
*/
|
|
18
|
+
/** @internal — exported for tests only. */
|
|
19
|
+
function reverseClientId(iosClientId) {
|
|
20
|
+
const suffix = '.apps.googleusercontent.com';
|
|
21
|
+
if (!iosClientId.endsWith(suffix)) {
|
|
22
|
+
throw new Error(`[${PLUGIN_NAME}] iosClientId must end with "${suffix}". Received: "${iosClientId}".`);
|
|
23
|
+
}
|
|
24
|
+
const id = iosClientId.slice(0, -suffix.length);
|
|
25
|
+
return `com.googleusercontent.apps.${id}`;
|
|
26
|
+
}
|
|
27
|
+
const withGoogleSignInURLScheme = (config, { reversedClientId }) => {
|
|
28
|
+
return (0, config_plugins_1.withInfoPlist)(config, (mod) => {
|
|
29
|
+
var _a;
|
|
30
|
+
const urlTypes = ((_a = mod.modResults).CFBundleURLTypes ?? (_a.CFBundleURLTypes = []));
|
|
31
|
+
const alreadyRegistered = urlTypes.some((entry) => (entry.CFBundleURLSchemes ?? []).includes(reversedClientId));
|
|
32
|
+
if (!alreadyRegistered) {
|
|
33
|
+
urlTypes.push({
|
|
34
|
+
CFBundleURLSchemes: [reversedClientId],
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return mod;
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
const withGoogleSignInAppDelegate = (config) => {
|
|
41
|
+
return (0, config_plugins_1.withAppDelegate)(config, (mod) => {
|
|
42
|
+
const { language, contents } = mod.modResults;
|
|
43
|
+
if (contents.includes(MARKER)) {
|
|
44
|
+
return mod;
|
|
45
|
+
}
|
|
46
|
+
if (language === 'swift') {
|
|
47
|
+
mod.modResults.contents = injectSwiftURLHandler(contents);
|
|
48
|
+
}
|
|
49
|
+
else if (language === 'objcpp' || language === 'objc') {
|
|
50
|
+
mod.modResults.contents = injectObjCURLHandler(contents);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
throw new Error(`[${PLUGIN_NAME}] Unknown AppDelegate language "${language}". Expected "swift" or "objcpp".`);
|
|
54
|
+
}
|
|
55
|
+
return mod;
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
/** @internal — exported for tests only. */
|
|
59
|
+
function injectSwiftURLHandler(contents) {
|
|
60
|
+
const snippet = `
|
|
61
|
+
${MARKER}
|
|
62
|
+
@objc
|
|
63
|
+
public func application(
|
|
64
|
+
_ app: UIApplication,
|
|
65
|
+
open url: URL,
|
|
66
|
+
options: [UIApplication.OpenURLOptionsKey: Any] = [:]
|
|
67
|
+
) -> Bool {
|
|
68
|
+
return GIDSignIn.sharedInstance.handle(url)
|
|
69
|
+
}
|
|
70
|
+
`;
|
|
71
|
+
const importLine = 'import GoogleSignIn';
|
|
72
|
+
let next = contents;
|
|
73
|
+
if (!next.includes(importLine)) {
|
|
74
|
+
next = next.replace(/(import ExpoModulesCore|import React|import Expo)/, `$1\n${importLine}`);
|
|
75
|
+
}
|
|
76
|
+
// Inject the override before the closing brace of the AppDelegate class.
|
|
77
|
+
const classCloseRegex = /\n\}\s*$/;
|
|
78
|
+
if (!classCloseRegex.test(next)) {
|
|
79
|
+
throw new Error(`[${PLUGIN_NAME}] Could not locate the AppDelegate class closing brace.`);
|
|
80
|
+
}
|
|
81
|
+
return next.replace(classCloseRegex, `\n${snippet}}\n`);
|
|
82
|
+
}
|
|
83
|
+
/** @internal — exported for tests only. */
|
|
84
|
+
function injectObjCURLHandler(contents) {
|
|
85
|
+
const snippet = `
|
|
86
|
+
${MARKER}
|
|
87
|
+
- (BOOL)application:(UIApplication *)application
|
|
88
|
+
openURL:(NSURL *)url
|
|
89
|
+
options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options
|
|
90
|
+
{
|
|
91
|
+
if ([[GIDSignIn sharedInstance] handleURL:url]) { return YES; }
|
|
92
|
+
return [super application:application openURL:url options:options];
|
|
93
|
+
}
|
|
94
|
+
`;
|
|
95
|
+
const importLine = '#import <GoogleSignIn/GoogleSignIn.h>';
|
|
96
|
+
let next = contents;
|
|
97
|
+
if (!next.includes(importLine)) {
|
|
98
|
+
next = next.replace(/(#import "AppDelegate\.h")/, `$1\n${importLine}`);
|
|
99
|
+
}
|
|
100
|
+
const endRegex = /\n@end\s*$/;
|
|
101
|
+
if (!endRegex.test(next)) {
|
|
102
|
+
throw new Error(`[${PLUGIN_NAME}] Could not locate the AppDelegate's @end directive.`);
|
|
103
|
+
}
|
|
104
|
+
return next.replace(endRegex, `\n${snippet}\n@end\n`);
|
|
105
|
+
}
|
|
106
|
+
const withSocialAuth = (config, props) => {
|
|
107
|
+
const iosClientId = props?.iosClientId;
|
|
108
|
+
if (!iosClientId) {
|
|
109
|
+
console.warn(`[${PLUGIN_NAME}] No iosClientId provided — skipping iOS configuration. ` +
|
|
110
|
+
'Android consumers can ignore this warning; iOS consumers must pass ' +
|
|
111
|
+
'{ iosClientId } in their app config plugin entry.');
|
|
112
|
+
return config;
|
|
113
|
+
}
|
|
114
|
+
const reversedClientId = reverseClientId(iosClientId);
|
|
115
|
+
config = withGoogleSignInURLScheme(config, { reversedClientId });
|
|
116
|
+
config = withGoogleSignInAppDelegate(config);
|
|
117
|
+
return config;
|
|
118
|
+
};
|
|
119
|
+
exports.default = (0, config_plugins_1.createRunOncePlugin)(withSocialAuth, PLUGIN_NAME, pkg.version);
|