Skip to content

Commit 80f53cc

Browse files
committed
fix(ios): synchronize Google Maps configuration
1 parent 887b065 commit 80f53cc

5 files changed

Lines changed: 77 additions & 30 deletions

File tree

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,6 @@ In a bare workflow the plugin does not run, so configure both manually:
412412
```
413413

414414
```json
415-
// ios/Podfile.properties.json
416415
{
417416
"betterMaps.iosGoogleProvider": "true"
418417
}

docs/expo-setup.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ The plugin injects:
8888
- **Android:** `com.google.android.geo.API_KEY` meta-data (when `googleMapsApiKey` or `androidGoogleMapsApiKey` is set) and location permissions (when location options are set)
8989
- **iOS:** `GoogleMapsIosApiKey` in `Info.plist` and `betterMaps.iosGoogleProvider` in `Podfile.properties.json` (when `googleMapsApiKey` or `iosGoogleMapsApiKey` is set), plus location usage description strings (when location options are set)
9090

91-
On iOS, the API key and pod linkage are separate artifacts. The plugin keeps them in sync during prebuild. If you later remove Google Maps keys from the plugin config, re-run `expo prebuild` so `Podfile.properties.json` is updated and run `pod install` — a stale `"betterMaps.iosGoogleProvider": "true"` can leave the SDK linked after you stop providing a key. Bare React Native apps without the plugin must set both manually; see [Bare React Native](../README.md#bare-react-native) in the README.
91+
On iOS, the API key and pod linkage are separate artifacts. The plugin keeps them in sync during prebuild. If you later remove Google Maps keys from the plugin config, re-run `expo prebuild` to remove both `GoogleMapsIosApiKey` and `betterMaps.iosGoogleProvider`, then run `pod install` to update the linked pods. Bare React Native apps without the plugin must manage both settings manually; see [Bare React Native](../README.md#bare-react-native) in the README.
9292

9393
## Run
9494

@@ -113,7 +113,7 @@ The example's `prebuild` script builds the plugin (`build:plugin`) before runnin
113113
| Symptom | Fix |
114114
| ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
115115
| Blank Google map | Ensure `googleMapsApiKey` or the platform-specific Google Maps key is set, then run `expo prebuild` again. |
116-
| iOS Google Maps key present but provider fails | iOS needs `GoogleMapsIosApiKey` in `Info.plist` **and** `"betterMaps.iosGoogleProvider": "true"` in `Podfile.properties.json`, then `pod install`. Re-run prebuild after changing plugin keys so both stay aligned. |
116+
| iOS Google Maps key present but provider fails | iOS needs `GoogleMapsIosApiKey` in `Info.plist` **and** `"betterMaps.iosGoogleProvider": "true"` in `Podfile.properties.json`, then `pod install`. Re-run prebuild after changing or removing plugin keys so both artifacts stay aligned. |
117117
| Location dot not showing | Set `locationPermission` or `locationAlwaysPermission` in the plugin options and re-run prebuild. |
118118
| Plugin not found | Confirm `react-native-better-maps` is installed and listed in `plugins`. |
119119
| `Cannot find module './plugin/build/index'` | Run `bun run build:plugin` in the package (or `bun run build` from the repo root) before prebuild when using a workspace link. |

package/ios/GoogleMapsAPIKey.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ enum MapProviderConfigurationError: LocalizedError {
3434
case .missingGoogleMapsIosApiKey:
3535
return "react-native-better-maps: provider=\"google\" on iOS requires GoogleMapsIosApiKey in the host app Info.plist."
3636
case .googleMapsSdkNotLinked:
37-
return "react-native-better-maps: provider=\"google\" on iOS requires iosGoogleMapsApiKey or googleMapsApiKey in the react-native-better-maps config plugin to link the Google Maps SDK, then run pod install."
37+
return "react-native-better-maps: provider=\"google\" on iOS requires the Google Maps SDK to be linked. Configure iosGoogleMapsApiKey or googleMapsApiKey in the config plugin, or set betterMaps.iosGoogleProvider=true in Podfile.properties.json, then run pod install."
3838
case let .unsupportedIOSProvider(provider):
3939
return "Map provider \"\(provider)\" is not supported on iOS."
4040
}

package/plugin/src/ios.test.ts

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { join } from 'node:path';
33

44
import {
55
applyGoogleMapsIosApiKey,
6+
applyIosGoogleProviderPodfileProperty,
67
applyLocationPermissionsToInfoPlist,
78
IOS_GOOGLE_MAPS_API_KEY,
89
IOS_GOOGLE_PROVIDER_PODFILE_PROPERTY,
@@ -23,9 +24,25 @@ describe('IOS_GOOGLE_PROVIDER_PODFILE_PROPERTY', () => {
2324
'../../react-native-better-maps.podspec',
2425
);
2526
const podspec = readFileSync(podspecPath, 'utf8');
26-
expect(podspec).toContain(
27-
`'${IOS_GOOGLE_PROVIDER_PODFILE_PROPERTY}'`,
28-
);
27+
expect(podspec).toContain(`'${IOS_GOOGLE_PROVIDER_PODFILE_PROPERTY}'`);
28+
});
29+
30+
it('sets the Podfile property when the iOS Google provider is enabled', () => {
31+
expect(applyIosGoogleProviderPodfileProperty({}, true)).toEqual({
32+
[IOS_GOOGLE_PROVIDER_PODFILE_PROPERTY]: 'true',
33+
});
34+
});
35+
36+
it('clears the Podfile property when the iOS Google provider is disabled', () => {
37+
expect(
38+
applyIosGoogleProviderPodfileProperty(
39+
{
40+
[IOS_GOOGLE_PROVIDER_PODFILE_PROPERTY]: 'true',
41+
'expo.jsEngine': 'hermes',
42+
},
43+
false,
44+
),
45+
).toEqual({ 'expo.jsEngine': 'hermes' });
2946
});
3047
});
3148

@@ -39,6 +56,18 @@ describe('applyGoogleMapsIosApiKey', () => {
3956
[IOS_GOOGLE_MAPS_API_KEY]: 'test-ios-key',
4057
});
4158
});
59+
60+
it('removes an existing GoogleMapsIosApiKey when the API key is omitted', () => {
61+
expect(
62+
applyGoogleMapsIosApiKey(
63+
{
64+
[IOS_GOOGLE_MAPS_API_KEY]: 'stale-key',
65+
CFBundleDisplayName: 'Better Maps',
66+
},
67+
undefined,
68+
),
69+
).toEqual({ CFBundleDisplayName: 'Better Maps' });
70+
});
4271
});
4372

4473
describe('resolveIosGoogleMapsApiKey', () => {
@@ -66,6 +95,15 @@ describe('resolveIosGoogleMapsApiKey', () => {
6695
resolveIosGoogleMapsApiKey({ iosGoogleMapsApiKey: ' ' }),
6796
).toBeUndefined();
6897
});
98+
99+
it('falls back to googleMapsApiKey when the iOS key is blank', () => {
100+
expect(
101+
resolveIosGoogleMapsApiKey({
102+
iosGoogleMapsApiKey: ' ',
103+
googleMapsApiKey: 'shared',
104+
}),
105+
).toBe('shared');
106+
});
69107
});
70108

71109
describe('shouldEnableIosGoogleMapsProvider', () => {

package/plugin/src/ios.ts

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,41 @@ import {
1515
} from './types';
1616

1717
type InfoPlist = IOSConfig.InfoPlist;
18+
type PodfileProperties = Record<string, string>;
1819

1920
export const IOS_GOOGLE_MAPS_API_KEY = 'GoogleMapsIosApiKey';
2021
/** Must match the Podfile.properties.json key in `react-native-better-maps.podspec`. */
21-
export const IOS_GOOGLE_PROVIDER_PODFILE_PROPERTY = 'betterMaps.iosGoogleProvider';
22+
export const IOS_GOOGLE_PROVIDER_PODFILE_PROPERTY =
23+
'betterMaps.iosGoogleProvider';
2224

2325
export function applyGoogleMapsIosApiKey(
2426
infoPlist: InfoPlist,
2527
apiKey: string | undefined,
2628
): InfoPlist {
27-
if (!apiKey) {
28-
return infoPlist;
29+
const nextInfoPlist = { ...infoPlist };
30+
31+
if (apiKey) {
32+
nextInfoPlist[IOS_GOOGLE_MAPS_API_KEY] = apiKey;
33+
} else {
34+
delete nextInfoPlist[IOS_GOOGLE_MAPS_API_KEY];
2935
}
3036

31-
return {
32-
...infoPlist,
33-
[IOS_GOOGLE_MAPS_API_KEY]: apiKey,
34-
};
37+
return nextInfoPlist;
38+
}
39+
40+
export function applyIosGoogleProviderPodfileProperty(
41+
podfileProperties: PodfileProperties,
42+
enabled: boolean,
43+
): PodfileProperties {
44+
const nextPodfileProperties = { ...podfileProperties };
45+
46+
if (enabled) {
47+
nextPodfileProperties[IOS_GOOGLE_PROVIDER_PODFILE_PROPERTY] = 'true';
48+
} else {
49+
delete nextPodfileProperties[IOS_GOOGLE_PROVIDER_PODFILE_PROPERTY];
50+
}
51+
52+
return nextPodfileProperties;
3553
}
3654

3755
export function applyLocationPermissionsToInfoPlist(
@@ -59,12 +77,10 @@ const withIosGoogleProviderPodfileProperty: ConfigPlugin<
5977
const enableIosGoogleProvider = shouldEnableIosGoogleMapsProvider(options);
6078

6179
return withPodfileProperties(config, (config) => {
62-
if (enableIosGoogleProvider) {
63-
config.modResults[IOS_GOOGLE_PROVIDER_PODFILE_PROPERTY] = 'true';
64-
} else {
65-
delete config.modResults[IOS_GOOGLE_PROVIDER_PODFILE_PROPERTY];
66-
}
67-
80+
config.modResults = applyIosGoogleProviderPodfileProperty(
81+
config.modResults,
82+
enableIosGoogleProvider,
83+
);
6884
return config;
6985
});
7086
};
@@ -78,17 +94,11 @@ export const withBetterMapsIos: ConfigPlugin<BetterMapsPluginOptions> = (
7894
const iosGoogleMapsApiKey = resolveIosGoogleMapsApiKey(options);
7995
const needsLocation = requiresForegroundLocation(options);
8096

81-
if (!iosGoogleMapsApiKey && !needsLocation) {
82-
return config;
83-
}
84-
8597
return withInfoPlist(config, (config) => {
86-
if (iosGoogleMapsApiKey) {
87-
config.modResults = applyGoogleMapsIosApiKey(
88-
config.modResults,
89-
iosGoogleMapsApiKey,
90-
);
91-
}
98+
config.modResults = applyGoogleMapsIosApiKey(
99+
config.modResults,
100+
iosGoogleMapsApiKey,
101+
);
92102
if (needsLocation) {
93103
config.modResults = applyLocationPermissionsToInfoPlist(
94104
config.modResults,

0 commit comments

Comments
 (0)