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
MapSurfaceis registered withMapSurfaceHost. Dart creates aHereMapControllerfor the same map ID to control that surface. - On iOS, a native CarPlay scene presents a
CPMapTemplateand a HERE SDKMapView. The phone map remains a FlutterHereMap. - 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_sdkThe example's pubspec.yaml refers to it as a path dependency:
dependencies:
here_sdk:
path: plugins/here_sdkFrom 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
main.dartinitializes the HERE SDK in Dart and starts the Flutter app. The phone'sHereMaploads its scene;HelloMapExamplethen installs a method-call handler for native events.HelloMapAutoCarAppServicecreatesHelloMapAutoScreenfor the car host. When the host provides a surface, the screen attaches a nativeMapSurface, registers it withMapSurfaceHostusing map ID1, and sendsonMapSurfaceReadyto Dart.- Dart responds by initializing
HereMapController(1), loading thenormalDaymap scene, and positioning the camera over Berlin at a distance of about 10 km. The SDK is not initialized again for the car display. - Scroll, scale, and fling gestures are handled directly by the native
MapSurfacefrom the car surface callbacks. Scale details are also sent to Dart asandroidAutoOnScaleat a throttled rate. The navigation template provides zoom-in, zoom-out, and exit actions. - When the car host destroys its surface, native code destroys the map surface and sends
onSurfaceDestroyed; Dart finalizes and clears itsHereMapController.
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
- Dart initializes the HERE SDK, then calls
onDartHereSdkReadyover the method channel on iOS. The call retries briefly while the native channel is being registered. SceneDelegaterecords this readiness signal. WhenCarPlaySceneDelegatereceives the CarPlay connection event, it installs aCPMapTemplatewith zoom buttons and waits to create the map until the Dart readiness signal has arrived.- The CarPlay scene creates a native HERE SDK
MapView, loads thenormalDayscene, and positions its camera over Berlin at a distance of about 10 km. The zoom buttons operate on that map view. - On connection and disconnection, native code sends
onCarPlayConnectedandonCarPlayDisconnectedto Dart. On disconnection, the scene releases its map example and window references and resets its initialization state; both events are forwarded to callbacks inHelloMapExample.
Run and test
- Install the HERE SDK plugin at
plugins/here_sdkand set credentials inlib/main.dart. - From
examples/flutter/hello_map_auto_carplay_app, runflutter pub get, then launch the app on the target platform from your IDE or withflutter run. - 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.
- 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.
Updated 3 days ago