Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,17 @@ GoogleSignIn.configure({

Finally, run `cd ios && pod install` after installing the package.

GoogleSignIn 8 and later includes Swift dependencies that require module maps
when CocoaPods builds them as static libraries. Add this near the top of your
`ios/Podfile`, after the iOS platform declaration:

```ruby
platform :ios, min_ios_version_supported
use_modular_headers!
```

The Expo config plugin adds this declaration automatically.

## Expo config plugin

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.
Expand Down
2 changes: 1 addition & 1 deletion ReactNativeSocialAuth.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ Pod::Spec.new do |s|

install_modules_dependencies(s)

s.dependency "GoogleSignIn", "~> 7.1"
s.dependency "GoogleSignIn", "~> 8.0"
end
35 changes: 35 additions & 0 deletions plugin/src/__tests__/withSocialAuth.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { describe, expect, it } from '@jest/globals';
import {
injectModularHeaders,
injectObjCURLHandler,
injectSwiftURLHandler,
reverseClientId,
Expand Down Expand Up @@ -106,3 +107,37 @@ describe('injectObjCURLHandler', () => {
expect(() => injectObjCURLHandler('// no class here')).toThrow(/@end/);
});
});

describe('injectModularHeaders', () => {
const PODFILE_FIXTURE = `require 'expo'

platform :ios, '15.1'

prepare_react_native_project!
`;

it('enables modular headers after the platform declaration', () => {
const out = injectModularHeaders(PODFILE_FIXTURE);
expect(out).toContain(
"platform :ios, '15.1'\n" +
'# @thoughtbot/react-native-social-auth: GoogleSignIn 8+ dependencies\n' +
'use_modular_headers!'
);
});

it('does not add a duplicate declaration', () => {
const once = injectModularHeaders(PODFILE_FIXTURE);
expect(injectModularHeaders(once)).toBe(once);
});

it('preserves an existing modular-headers declaration', () => {
const podfile = `${PODFILE_FIXTURE}\nuse_modular_headers!\n`;
expect(injectModularHeaders(podfile)).toBe(podfile);
});

it('throws when the platform declaration is missing', () => {
expect(() => injectModularHeaders("require 'expo'\n")).toThrow(
/platform declaration/
);
});
});
48 changes: 48 additions & 0 deletions plugin/src/withSocialAuth.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import {
createRunOncePlugin,
withAppDelegate,
withDangerousMod,
withInfoPlist,
} from '@expo/config-plugins';
import type { ConfigPlugin } from '@expo/config-plugins';

const pkg = require('../../package.json');
const fs = require('fs').promises;
const path = require('path');

export type SocialAuthPluginProps = {
/**
Expand All @@ -20,6 +23,8 @@ export type SocialAuthPluginProps = {

const PLUGIN_NAME = '@thoughtbot/react-native-social-auth';
const MARKER = '/* @thoughtbot/react-native-social-auth: URL handler */';
const MODULAR_HEADERS_MARKER =
'# @thoughtbot/react-native-social-auth: GoogleSignIn 8+ dependencies';

/**
* Compute the reversed iOS Client ID that GoogleSignIn-iOS expects as a
Expand Down Expand Up @@ -141,6 +146,48 @@ ${MARKER}
return next.replace(endRegex, `\n${snippet}\n@end\n`);
}

/** @internal — exported for tests only. */
export function injectModularHeaders(contents: string): string {
if (
contents.includes(MODULAR_HEADERS_MARKER) ||
/^\s*use_modular_headers!\s*$/m.test(contents)
) {
return contents;
}

const platformLine = /^platform :ios,.*$/m;
if (!platformLine.test(contents)) {
throw new Error(
`[${PLUGIN_NAME}] Could not locate the iOS platform declaration in the Podfile.`
);
}

return contents.replace(
platformLine,
`$&\n${MODULAR_HEADERS_MARKER}\nuse_modular_headers!`
);
}

const withGoogleSignInModularHeaders: ConfigPlugin = (config) => {
return withDangerousMod(config, [
'ios',
async (mod) => {
const podfilePath = path.join(
mod.modRequest.platformProjectRoot,
'Podfile'
);
const contents = await fs.readFile(podfilePath, 'utf8');
const next = injectModularHeaders(contents);

if (next !== contents) {
await fs.writeFile(podfilePath, next);
}

return mod;
},
]);
};

const withSocialAuth: ConfigPlugin<SocialAuthPluginProps | void> = (
config,
props
Expand All @@ -160,6 +207,7 @@ const withSocialAuth: ConfigPlugin<SocialAuthPluginProps | void> = (

config = withGoogleSignInURLScheme(config, { reversedClientId });
config = withGoogleSignInAppDelegate(config);
config = withGoogleSignInModularHeaders(config);

return config;
};
Expand Down
Loading