Skip to content

Commit

Permalink
feat: add carplay and android auto support (#255)
Browse files Browse the repository at this point in the history
Adds support for Apple CarPlay and Android Auto.

Added BaseAutoSceneDelegate for iOS and AndroidAutoBaseScreen for Android on a plugin level to manage setting up the base functionality for each platform.
Added example of setting up each platform in the SampleApp. iOS SampleApp has a new separate target for CarPlay support SampleAppCarPlay.
Added separate native module NavAutoModule to manage communication between RN code and the map instance.
Added a generic event channel so that user actions can be sent from native code to RN. e.g. user presses a button in CarPlay window and this event is sent to RN code.
Added a function to NavAutoModule to check whether CarPlay or Android Auto screen has been initialized and is available.

Co-authored-by: Joonas Kerttula <[email protected]>
  • Loading branch information
illuminati1911 and jokerttu authored Oct 15, 2024
1 parent 13d6fa8 commit 933209a
Show file tree
Hide file tree
Showing 69 changed files with 4,679 additions and 1,275 deletions.
100 changes: 100 additions & 0 deletions ANDROIDAUTO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Navigation for Android Auto

This guide explains how to enable and integrate Android Auto with the React Native Navigation SDK.

## Requirements

- Android device
- Android Auto test device or Android Automotive OS emulator

## Setup

Refer to the [Android for Cars developer documentation](https://developer.android.com/training/cars) to understand how the Android Auto works and to complete the initial setup. Key steps include:

- Installing Android for Cars App Library.
- Configuring your app's manifest file to include Android Auto.
- Declaring a minimum car-app level in your manifest.
- Creating 'CarAppService' and session

For all the steps above, you can refer to the Android example application for guidance.

### Screen for Android Auto

Once your project is configured accordingly, and you are ready to build the screen for Android Auto, you can leverage the `AndroidAutoBaseScreen` provided by the SDK. This base class simplifies the setup by handling initialization, teardown, and rendering the map on the Android Auto display.

Please refer to the `SampleAndroidAutoScreen.java` file in the Android example app for guidance.

To customize the Android Auto experience, override the `onGetTemplate` method in your custom AndroidAutoScreen class, providing your own `Template`:

```java
@NonNull
@Override
public Template onGetTemplate() {
/** ... */
@SuppressLint("MissingPermission")
NavigationTemplate.Builder navigationTemplateBuilder =
new NavigationTemplate.Builder()
.setActionStrip(
new ActionStrip.Builder()
.addAction(
new Action.Builder()
.setTitle("Re-center")
.setOnClickListener(
() -> {
if (mGoogleMap == null) return;
mGoogleMap.followMyLocation(GoogleMap.CameraPerspective.TILTED);
})
.build())
.addAction(
new Action.Builder()
.setTitle("Custom event")
.setOnClickListener(
() -> {
WritableMap map = Arguments.createMap();
map.putString("sampleKey", "sampleValue");
sendCustomEvent("sampleEvent", map);
})
.build())
.build())
.setMapActionStrip(new ActionStrip.Builder().addAction(Action.PAN).build());
/** ... */
}
```

For advanced customization, you can bypass the base class and implement your own screen by inheriting `Screen`. You can use the provided `AndroidAutoBaseScreen` base class as a reference on how to do that.

### React Native specific setup

On the React Native side, you can use the `useNavigationAuto` hook to interface with the Android Auto instance. The `mapViewAutoController` allows you to call map functions on the Android Auto map, and you can manage listeners using the provided functions.

```tsx
const {
mapViewAutoController,
addListeners: addAutoListener,
removeListeners: removeAutoListeners,
} = useNavigationAuto();

const navigationAutoCallbacks: NavigationAutoCallbacks = useMemo(
() => ({
onCustomNavigationAutoEvent: (event: CustomNavigationAutoEvent) => {
console.log('onCustomNavigationAutoEvent:', event);
},
onAutoScreenAvailabilityChanged: (available: boolean) => {
console.log('onAutoScreenAvailabilityChanged:', available);
setMapViewAutoAvailable(available);
},
}),
[]
);

const setMapType = (mapType: MapType) => {
console.log('setMapType', mapType);
mapViewAutoController.setMapType(mapType);
};
```

For a more detailed example, refer to the `NavigationScreen.tsx` in the React Native example application.

## Example Project

For a fully functional Android Auto implementation, check out the [SampleApp](./example/android/) Android Studio project.
86 changes: 86 additions & 0 deletions CARPLAY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Navigation for Apple CarPlay

This guide explains how to enable and integrate Apple CarPlay with the React Native Navigation SDK.

## Requirements

- iOS device or iOS simulator (iOS 14.0+)
- CarPlay Simulator
- CarPlay entitlement for your application (provided by Apple)

## Setup

Refer to the [Apple CarPlay Developer Guide](https://developer.apple.com/carplay/) to understand how CarPlay works and to complete the initial setup. Key steps include:

- Adding the CarPlay entitlement to your Xcode project.
- Creating a separate scene for the CarPlay map and enabling support for multiple scenes.

### SceneDelegate for CarPlay

Once your project is configured to support multiple scenes, and you are setting up a dedicated scene for CarPlay, you can leverage the `BaseCarSceneDelegate` provided by the SDK. This base class simplifies the setup by handling initialization, teardown, and rendering the map on the CarPlay display.

Please refer to the `CarSceneDelegate.h` and `CarSceneDelegate.m` files in the iOS example app for guidance.

To customize the CarPlay experience, override the `getTemplate` method in your custom `CarSceneDelegate` class, providing your own `CPMapTemplate`:

```objc
- (CPMapTemplate *)getTemplate {
  CPMapTemplate *template = [[CPMapTemplate alloc] init];
  [template showPanningInterfaceAnimated:YES];

  CPBarButton *customButton = [[CPBarButton alloc]
      initWithTitle:@"Custom Event"
            handler:^(CPBarButton ***_Nonnull** button) {
              NSMutableDictionary *dictionary = [
              [NSMutableDictionary alloc] init
          ];
              dictionary[@"sampleDataKey"] = @"sampleDataContent";
              [[NavAutoModule getOrCreateSharedInstance]
              onCustomNavigationAutoEvent:@"sampleEvent"
              data:dictionary
          ];
            }];

  template.leadingNavigationBarButtons = @[ customButton ];
  template.trailingNavigationBarButtons = @[];
  return template;
}
```

For advanced customization, you can bypass the base class and implement your own delegate inheriting `CPTemplateApplicationSceneDelegate`. You can use the provided `BaseCarSceneDelegate` base class as a reference on how to do that.

### React Native Setup

On the React Native side, you can use the `useNavigationAuto` hook to interface with the CarPlay instance. The `mapViewAutoController` allows you to call map functions on the CarPlay map view, and you can manage listeners using the provided functions.

```tsx
const {
mapViewAutoController,
addListeners: addAutoListener,
removeListeners: removeAutoListeners,
} = useNavigationAuto();

const navigationAutoCallbacks: NavigationAutoCallbacks = useMemo(
() => ({
onCustomNavigationAutoEvent: (event: CustomNavigationAutoEvent) => {
console.log('onCustomNavigationAutoEvent:', event);
},
onAutoScreenAvailabilityChanged: (available: boolean) => {
console.log('onAutoScreenAvailabilityChanged:', available);
setMapViewAutoAvailable(available);
},
}),
[]
);

const setMapType = (mapType: MapType) => {
console.log('setMapType', mapType);
mapViewAutoController.setMapType(mapType);
};
```

For a more detailed example, refer to the `NavigationScreen.tsx` in the React Native example application.

## Example Project

For a fully functional CarPlay implementation, check out the [SampleApp](./example/ios/) Xcode project, which includes the `SampleAppCarPlay` build target. The sample already contains test entitlement so you don't need to request one from Apple to run it.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,12 @@ By default, `NavigationView` uses all the available space provided to it. To adj
/>
```

## Support for Android Auto and Apple CarPlay
This plugin is compatible with both Android Auto and Apple CarPlay infotainment systems. For more details, please refer to the respective platform documentation:

- [Android Auto documentation](./ANDROIDAUTO.md)
- [CarPlay documentation](./CARPLAY.md)

## Known issues

### Compatibility with other libraries
Expand Down
10 changes: 6 additions & 4 deletions android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// 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.
Expand Down Expand Up @@ -37,7 +37,7 @@ if (isNewArchitectureEnabled()) {

android {
namespace "com.google.android.react.navsdk"

compileSdkVersion 31

compileOptions {
Expand Down Expand Up @@ -71,6 +71,8 @@ repositories {
}

dependencies {
implementation "androidx.car.app:app:1.4.0"
implementation "androidx.car.app:app-projected:1.4.0"
implementation 'com.facebook.react:react-native:+'
implementation 'com.android.support:multidex:1.0.3'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
Expand Down
Loading

0 comments on commit 933209a

Please sign in to comment.