Integration with CarPlay and Android Auto

Currently, the Flutter platform provides no direct support for Apple's CarPlay, Android Auto and Android Automotive. You can still integrate the native platform APIs with a Flutter app using platform-specific code and method channels. The hello_map_auto_carplay_app example demonstrates both integrations in one Flutter project: Dart owns the phone UI and HERE SDK initialization, while Android and iOS provide their respective car-display interfaces.

📘

Note

Android Auto and CarPlay may function as expected, but compatibility is not guaranteed. These platform dependencies are neither managed nor tested by the HERE SDK team. Android Automotive is not demonstrated by this example.

Architecture

  • Dart initializes the HERE SDK once, using credentials in lib/main.dart. The native Android and iOS code does not initialize the SDK again.
  • Dart selects platform-specific behavior, and a shared method channel coordinates events between Dart and native code. The channel name is com.here.sdk.examples.hello_map_auto_carplay_app/channel.
  • On Android, a native MapSurface is registered with MapSurfaceHost. Dart creates a HereMapController for the same map ID to control that surface.
  • On iOS, a native CarPlay scene presents a CPMapTemplate and a HERE SDK MapView. The phone map remains a Flutter HereMap.
  • The car map's scene is loaded after Dart has initialized the HERE SDK. iOS has an explicit Dart-to-native readiness signal; Android creates the map controller in response to the native surface-ready event.

This is a native platform integration coordinated by Flutter, not a Flutter-provided CarPlay or Android Auto UI implementation.

Prerequisites

  • A HERE SDK for Flutter download, valid credentials, and a Flutter development environment configured for Android and/or iOS. For plugin setup details, see Integrate the HERE SDK.
  • Android Auto development and testing setup. Android Auto requires a compatible phone (Android 6.0/API level 23 or higher); this example sets minSdk = 24. It also uses the AndroidX Car App Library. Test with the Desktop Head Unit (DHU) and a connected Android device.
  • For CarPlay on a real device, Apple's approval for the CarPlay Maps entitlement and a provisioning profile that includes the entitlement. The example's entitlement is commented out until that setup is available. The native CarPlay guide describes entitlement and simulator requirements; its simulator workflow does not require the production entitlement.

For platform-level setup and restrictions, see Integrate Android Auto and Integrate CarPlay. Those guides cover the native workflows in more detail; this page focuses on the Flutter-specific bridge.

Configure the project

Install the HERE SDK plugin

Unzip the HERE SDK Flutter plugin into the example's plugins directory and name the directory here_sdk:

hello_map_auto_carplay_app/plugins/here_sdk

The example's pubspec.yaml refers to it as a path dependency:

dependencies:
  here_sdk:
    path: plugins/here_sdk

From the example project directory, run flutter pub get after installing the plugin.

Set credentials

In lib/main.dart, replace the placeholders with your HERE SDK credentials. The app initializes SDKNativeEngine.makeSharedInstance() once before starting the Flutter UI; credentials remain in Dart and are not copied into native source files.

Configure Android Auto

The example adds the AndroidX Car App Library and exposes the HERE SDK AAR from the Flutter plugin to the native Android source. Its Gradle configuration includes:

defaultConfig {
    minSdk = 24
}

dependencies {
    compileOnly(fileTree("../../plugins/here_sdk/android/libs") {
        include("heresdk-navigate-*.aar")
    })
    implementation("androidx.car.app:app:1.4.0")
}

The app manifest declares the car surface and navigation-template permissions, the CarAppService, and the automotive template descriptor. It sets minimum Car API level 2 so the surface callback can receive map gesture events:

<uses-permission android:name="androidx.car.app.ACCESS_SURFACE" />
<uses-permission android:name="androidx.car.app.NAVIGATION_TEMPLATES" />

<service
    android:name=".HelloMapAutoCarAppService"
    android:exported="true">
    <intent-filter>
        <action android:name="androidx.car.app.CarAppService" />
        <category android:name="androidx.car.app.category.NAVIGATION" />
    </intent-filter>
</service>

<meta-data
    android:name="androidx.car.app.minCarApiLevel"
    android:value="2" />
<meta-data
    android:name="com.google.android.gms.car.application"
    android:resource="@xml/automotive_app_desc" />

The referenced res/xml/automotive_app_desc.xml declares template use:

<automotiveApp>
    <uses name="template" />
</automotiveApp>

MainActivity registers the channel with the Flutter engine and makes it available to the Android Auto service through AndroidAutoMapBridge. The shared map ID is 1 in both AndroidAutoMapBridge.ANDROID_AUTO_MAP_ID and Dart's Android Auto controller setup. Keep these values in sync if you change the ID.

Configure CarPlay

The iOS app needs separate scene configurations for its Flutter phone window and the CarPlay display. The phone role keeps Flutter's SceneDelegate, which registers the method channel; the CarPlay role names CPTemplateApplicationScene and CarPlaySceneDelegate in Info.plist:

<key>UIApplicationSupportsMultipleScenes</key>
<true/>
<key>UISceneConfigurations</key>
<dict>
    <key>UIWindowSceneSessionRoleApplication</key>
    <array>
        <dict>
            <key>UISceneClassName</key>
            <string>UIWindowScene</string>
            <key>UISceneDelegateClassName</key>
            <string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
        </dict>
    </array>
<key>CPTemplateApplicationSceneSessionRoleApplication</key>
<array>
    <dict>
        <key>UISceneClassName</key>
        <string>CPTemplateApplicationScene</string>
        <key>UISceneDelegateClassName</key>
        <string>$(PRODUCT_MODULE_NAME).CarPlaySceneDelegate</string>
    </dict>
</array>
</dict>

The example targets iOS 15.0. Xcode is configured to use Runner/Entitlements.plist; after obtaining Apple's CarPlay Maps entitlement, enable this key in that file and use a matching provisioning profile:

<key>com.apple.developer.carplay-maps</key>
<true/>

Coordinate over the method channel

Dart and native code use the same channel name. Android also uses map ID 1 to associate its registered MapSurface with HereMapController(1):

const MethodChannel channel = MethodChannel(
  'com.here.sdk.examples.hello_map_auto_carplay_app/channel',
);

The Android AndroidAutoMapBridge.CHANNEL_NAME and iOS SceneDelegate.channelName must match this string.

Runtime flow

Android Auto

  1. main.dart initializes the HERE SDK in Dart and starts the Flutter app. The phone's HereMap loads its scene; HelloMapExample then installs a method-call handler for native events.
  2. HelloMapAutoCarAppService creates HelloMapAutoScreen for the car host. When the host provides a surface, the screen attaches a native MapSurface, registers it with MapSurfaceHost using map ID 1, and sends onMapSurfaceReady to Dart.
  3. Dart responds by initializing HereMapController(1), loading the normalDay map scene, and positioning the camera over Berlin at a distance of about 10 km. The SDK is not initialized again for the car display.
  4. Scroll, scale, and fling gestures are handled directly by the native MapSurface from the car surface callbacks. Scale details are also sent to Dart as androidAutoOnScale at a throttled rate. The navigation template provides zoom-in, zoom-out, and exit actions.
  5. When the car host destroys its surface, native code destroys the map surface and sends onSurfaceDestroyed; Dart finalizes and clears its HereMapController.

Android does not send the explicit onDartHereSdkReady method used by iOS. Instead, it reports that its native map surface is ready, and Dart initializes the controller and loads the scene after the Flutter-side SDK setup.

CarPlay

  1. Dart initializes the HERE SDK, then calls onDartHereSdkReady over the method channel on iOS. The call retries briefly while the native channel is being registered.
  2. SceneDelegate records this readiness signal. When CarPlaySceneDelegate receives the CarPlay connection event, it installs a CPMapTemplate with zoom buttons and waits to create the map until the Dart readiness signal has arrived.
  3. The CarPlay scene creates a native HERE SDK MapView, loads the normalDay scene, and positions its camera over Berlin at a distance of about 10 km. The zoom buttons operate on that map view.
  4. On connection and disconnection, native code sends onCarPlayConnected and onCarPlayDisconnected to Dart. On disconnection, the scene releases its map example and window references and resets its initialization state; both events are forwarded to callbacks in HelloMapExample.

Run and test

  1. Install the HERE SDK plugin at plugins/here_sdk and set credentials in lib/main.dart.
  2. From examples/flutter/hello_map_auto_carplay_app, run flutter pub get, then launch the app on the target platform from your IDE or with flutter run.
  3. For Android Auto, connect a compatible Android device and use the DHU to test the app's car screen. Follow the native Android Auto guide for DHU setup and device-side developer settings.
  4. For CarPlay, run the app in the iOS Simulator, then open I/O > External Displays > CarPlay to launch the simulator's external CarPlay display. Follow the native CarPlay guide for simulator and entitlement details.

The combined Flutter example contains the complete implementation. For additional native configuration and platform guidance, see Android Auto and CarPlay.


Did this page help you?