Skip to content
Open
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
127 changes: 110 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ This repository contains a React Native plugin that provides a [Google Navigatio

## React Native Compatibility

The current version of this package has been tested and verified to work with the following React Native versions:
The current version of this package has been tested and verified to work with the following React Native versions:

**0.83.1, 0.82.1, 0.81.5, 0.80.3, 0.79.6**

Expand All @@ -58,6 +58,15 @@ In your TSX or JSX file, import the components you need:
import { NavigationView } from '@googlemaps/react-native-navigation-sdk';
```

Choose the setup guide that matches your project type:

- [Bare workflow (plain React Native)](#bare-workflow-setup)
- [Expo managed / prebuild workflow](#expo-workflow-setup)

---

## Bare Workflow Setup

### Android

#### Enable new architecture
Expand Down Expand Up @@ -127,19 +136,103 @@ ENV['RCT_NEW_ARCH_ENABLED'] = '1'

#### Set Google Maps API Key

To set up, specify your API key in the application delegate `ios/Runner/AppDelegate.m`:
To set up, specify your API key in the application delegate `ios/AppDelegate.swift`:

```objective-c
#import <GoogleMaps/GoogleMaps.h>
```swift
import GoogleMaps

@implementation AppDelegate
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[GMSServices provideAPIKey:@"API_KEY"];
return [super application:application didFinishLaunchingWithOptions:launchOptions];
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
GMSServices.provideAPIKey("YOUR_API_KEY")
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
```

---

## Expo Workflow Setup

This package ships an [Expo Config Plugin](https://docs.expo.dev/guides/config-plugins/) that automatically configures the native Android and iOS projects when you run `expo prebuild` (or `eas build`). No manual edits to `AndroidManifest.xml` or `AppDelegate.swift` are required.

### 1. Install the package

```shell
npm i @googlemaps/react-native-navigation-sdk
```

### 2. Add the plugin to `app.config.ts`

Pass your Google Maps API keys for Android and iOS via `androidApiKey` and `iosApiKey`:

```ts
export default {
// ...
plugins: [
[
'@googlemaps/react-native-navigation-sdk',
{
androidApiKey: process.env.GOOGLE_MAPS_ANDROID_API_KEY,
iosApiKey: process.env.GOOGLE_MAPS_IOS_API_KEY,
}
]
],
};
```

> [!TIP]
> Instead of passing `apiKey` as a plugin option, you can set the platform-specific fields and the plugin will pick them up automatically:
> - **Android**: `android.config.googleMaps.apiKey`
> - **iOS**: `ios.config.googleMapsApiKey`

### 3. Run prebuild

```shell
npx expo prebuild
```

This will inject the API key into `AndroidManifest.xml` and `AppDelegate.swift` automatically.

### Android — additional requirements
If you are using Expo 53 or above, there's no need to configure anything else.
<details>
<summary>If you are using Expo 52 or below</summary>

* You must enable the new architecture in your `app.config.ts`:
```ts
export default {
// ...
neyArchEnabled: true,
// ...
}
```
* You must set the minimum SDK version to 24 or higher:
```ts
export default {
// ...
android: {
minSdkVersion: 24,
},
// ...
}
```
</details>

Jetifier and core library desugaring are both automatically enabled by the Expo Config Plugin, so no manual changes to `android/gradle.properties` or `android/app/build.gradle` are required.

### iOS — minimum deployment target

The minimum iOS deployment target must be 16.0 or higher. Set it in `app.config.ts`:

```ts
export default {
ios: {
deploymentTarget: '16.0',
},
};
```

## Usage
Expand Down Expand Up @@ -243,7 +336,7 @@ const initializeNavigation = useCallback(async () => {

// Initialize the navigation session and check the status
const status = await navigationController.init();

switch (status) {
case NavigationSessionStatus.OK:
console.log('Navigation initialized successfully');
Expand Down Expand Up @@ -339,8 +432,8 @@ await navigationController.startGuidance();
#### Adding navigation listeners

```tsx
const {
navigationController,
const {
navigationController,
removeAllListeners,
setOnArrival,
setOnRouteChanged,
Expand Down Expand Up @@ -595,8 +688,8 @@ The `useNavigation()` hook provides access to the `NavigationController` and lis
```tsx
import { useNavigation } from '@googlemaps/react-native-navigation-sdk';

const {
navigationController,
const {
navigationController,
removeAllListeners,
setOnArrival,
setOnRouteChanged,
Expand Down Expand Up @@ -681,7 +774,7 @@ useEffect(() => {
}
});
setOnRouteChanged(() => console.log('Route changed'));

// Use removeAllListeners() to clear all listeners at once on cleanup
// Alternatively, clear individual listeners: setOnArrival(null)
return () => removeAllListeners();
Expand Down Expand Up @@ -713,8 +806,8 @@ For Android Auto and CarPlay support, the `useNavigationAuto()` hook provides a
```tsx
import { useNavigationAuto } from '@googlemaps/react-native-navigation-sdk';

const {
mapViewAutoController,
const {
mapViewAutoController,
removeAllListeners,
setOnAutoScreenAvailabilityChanged,
setOnCustomNavigationAutoEvent,
Expand Down
18 changes: 18 additions & 0 deletions app.plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* eslint-disable */
module.exports = require('./src/plugins');
7 changes: 7 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"android",
"ios",
"cpp",
"app.plugin.js",
"*.podspec",
"!ios/build",
"!android/build",
Expand Down Expand Up @@ -87,9 +88,15 @@
"typescript": "^5.8.3"
},
"peerDependencies": {
"@expo/config-plugins": "*",
"react": "*",
"react-native": "*"
},
"peerDependenciesMeta": {
"@expo/config-plugins": {
"optional": true
}
},
"workspaces": [
"example"
],
Expand Down
53 changes: 53 additions & 0 deletions src/plugins/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* eslint-disable */
const withApiKeyAndroid = require('./withApiKeyAndroid');
const withApiKeyIos = require('./withApiKeyIos');
const withCoreLibraryDesugaring = require('./withCoreLibraryDesugaring');
const withJetifier = require('./withJetifier');

/**
* Expo Config Plugin for @googlemaps/react-native-navigation-sdk
*
* Automatically configures both Android and iOS native projects
* with the required Google Maps API key for the Navigation SDK.
*
* Usage in app.config.ts:
*
* plugins: [
* [
* '@googlemaps/react-native-navigation-sdk',
* {
* androidApiKey: 'YOUR_ANDROID_API_KEY',
* iosApiKey: 'YOUR_IOS_API_KEY',
* }
* ]
* ]
*
* Alternatively, set the API key via:
* - android.config.googleMaps.apiKey (Android)
* - ios.config.googleMapsApiKey (iOS)
*/
const withNavigationSdk = (config, options = {}) => {
config = withApiKeyAndroid(config, options);
config = withApiKeyIos(config, options);
config = withCoreLibraryDesugaring(config);
config = withJetifier(config);
return config;
};

module.exports = withNavigationSdk;
54 changes: 54 additions & 0 deletions src/plugins/withApiKeyAndroid.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* eslint-disable */
const { withAndroidManifest } = require('@expo/config-plugins');

/**
* Config Plugin for @googlemaps/react-native-navigation-sdk (Android)
*
* Injects the Google Maps API key into AndroidManifest.xml as a <meta-data> entry
*/
const withApiKeyAndroid = (config, { androidApiKey } = {}) => {
const key = androidApiKey ?? config?.android?.config?.googleMaps?.apiKey;

if (!key) {
throw new Error(
'[withApiKeyAndroid] Google Maps API key is not set. ' +
'Pass it as a plugin option or set android.config.googleMaps.apiKey in app.config.ts.'
);
}

return withAndroidManifest(config, (c) => {
const mainApp = c.modResults.manifest.application?.[0];
if (mainApp) {
mainApp['meta-data'] = mainApp['meta-data'] ?? [];
const existing = mainApp['meta-data'].find(
(m) => m.$?.['android:name'] === 'com.google.android.geo.API_KEY'
);
if (existing) {
existing.$['android:value'] = key;
} else {
mainApp['meta-data'].push({
$: { 'android:name': 'com.google.android.geo.API_KEY', 'android:value': key },
});
}
}
return c;
});
};

module.exports = withApiKeyAndroid;
Loading