将对 Android Automotive OS 的支持添加到您的模板应用

Android Automotive OS 允许用户在汽车中安装应用。要触达此平台上的用户,您需要分发一个针对驾驶员优化的应用,该应用与 Android Automotive OS 兼容。您可以重复使用 Android Auto 应用中的几乎所有代码和资源,但您必须创建满足本页所述要求的单独构建。

要在 Android Automotive OS 上运行汽车应用,您需要最新的 Templates Host,它作为系统应用提供。

开发概述

添加 Android Automotive OS 支持只需几个步骤,如本页上的各部分所述

  1. 创建汽车模块
  2. 声明对 Android Automotive OS 的支持
  3. 声明您的 CarAppServiceCarAppActivity
  4. 更新您的 Gradle 依赖项

使用 Android Studio Bumblebee 或更高版本以确保启用所有 Automotive OS 功能。

创建汽车模块

Android Automotive OS 的某些组件(例如清单)具有平台特定要求。创建一个模块,可以将这些组件的代码与项目中的其他代码(例如电话应用中使用的代码)分开。

对于现有项目,请按照以下步骤将汽车模块添加到项目中

  1. 在 Android Studio 中,点击**文件 > 新建 > 新建模块**。
  2. 选择**汽车模块**,然后点击**下一步**。
  3. 提供**应用/库名称**。这是用户在 Android Automotive OS 上看到您的应用的名称。
  4. 输入**模块名称**。
  5. 编辑**包名称**以匹配您的现有应用。
  6. 为**最低 SDK**选择**API 29: Android 10 (Q)**,然后点击**下一步**。所有支持 Android Automotive OS 上的汽车应用库的汽车都在运行 Android 10 API 级别 29 或更高版本,因此选择此值会定位所有兼容的汽车。

  7. 选择**不添加 Activity**,然后点击**完成**。

如果您要启动一个新项目

  1. 在 Android Studio 中,点击**文件 > 新建 > 新建项目**。
  2. 为**项目类型**选择**汽车**。
  3. 选择**不添加 Activity**,然后点击**下一步**。
  4. 为您的项目提供一个**名称**。这是用户在 Android Automotive OS 上看到您的应用的名称。
  5. 输入**包名称**。请参阅包名称部分以详细了解如何选择包名称。
  6. 为**最低 SDK**选择**API 29: Android 10 (Q)**,然后点击**下一步**。

    所有支持 Android Automotive OS 上的汽车应用库的汽车都在运行 Android 10 API 级别 29 或更高版本,因此选择此值会定位所有兼容的汽车。

在 Android Studio 中创建模块后,打开新汽车模块中的AndroidManifest.xml文件

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.car.app">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme" />

    <uses-feature
        android:name="android.hardware.type.automotive"
        android:required="true" />

</manifest>

application 元素包含一些标准应用程序信息以及一个 uses-feature 元素,该元素声明对 Android Automotive OS 的支持。请注意,清单中没有声明任何活动。

接下来,将以下 uses-feature 元素添加到您的清单中

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.car.app">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme" />

    <uses-feature
        android:name="android.hardware.type.automotive"
        android:required="true" />
    <uses-feature
        android:name="android.software.car.templates_host"
        android:required="true" />

    <uses-feature
        android:name="android.hardware.wifi"
        android:required="false" />
    <uses-feature
        android:name="android.hardware.screen.portrait"
        android:required="false" />
    <uses-feature
        android:name="android.hardware.screen.landscape"
        android:required="false" />
    <uses-feature
        android:name="android.hardware.camera"
        android:required="false" />

</manifest>

第一个 uses-feature 元素声明您的应用程序使用模板主机运行。将剩余的四个 uses-feature 元素明确设置为 required="false" 可确保您的应用程序不会与 Android Automotive OS 设备中的可用硬件功能发生冲突。

更新您的 Gradle 依赖项

在您的汽车模块中,您必须添加对 androidx.car.app:app-automotive 工件 的依赖项,该工件包括 CarAppActivity 实现,您的应用程序需要此实现才能在 Android Automotive OS 上运行。

如果您正在开发应用程序以同时支持 Android Auto 和 Android Automotive OS,我们建议您将 CarAppService 保留在您在移动模块和汽车模块之间共享的单独模块中。如果您使用这种方法,您需要更新您的汽车模块以使用 Gradle 的 项目依赖项 包含共享模块,如下面的代码片段所示

Groovy

buildscript {
    ...
    dependencies {
        ...
        implementation "androidx.car.app:app-automotive:car_app_library_version"
        implementation project(':shared_module_name')
    }
}

Kotlin

buildscript {
    ...
    dependencies {
        ...
        implementation("androidx.car.app:app-automotive:car_app_library_version")
        implementation(project(":shared_module_name"))
    }
}

声明对 Android Automotive OS 的支持

使用以下清单条目来声明您的应用程序支持 Android Automotive OS

<application>
    ...
    <meta-data android:name="com.android.automotive"
        android:resource="@xml/automotive_app_desc"/>
    ...
</application>

此清单条目引用一个 XML 文件,该文件声明了您的应用程序支持的汽车功能。

要表明您拥有一个 Car App Library 应用程序,请将名为 automotive_app_desc.xml 的 XML 文件添加到 Android Automotive OS 模块中的 res/xml/ 目录中。此文件应包含以下内容

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

声明您的 CarAppService 和 CarAppActivity

与 Android Auto 一样,Android Automotive OS 使用您的 CarAppService 实现来运行您的应用程序。请参阅 创建您的 CarAppService 和会话声明您的 CarAppService,以获取有关实现和声明 CarAppService 的说明。

与 Android Auto 不同,您必须包含一个额外的应用程序组件,即 CarAppActivity,作为 Android Automotive OS 应用程序的入口点。此活动的实现包含在 androidx.car.app:app-automotive 工件中,负责与模板主机应用程序通信以呈现应用程序的 UI。您应该在清单中只包含此活动的单个实例,并且必须按如下方式声明:

<activity
    android:exported="true"
    android:theme="@android:style/Theme.DeviceDefault.NoActionBar"
    android:name="androidx.car.app.activity.CarAppActivity"
    android:launchMode="singleTask"
    android:label="Your app name">

    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>

    <meta-data android:name="distractionOptimized" android:value="true" />

</activity>
  • android:name 设置为 app-automotive 工件中 CarAppActivity 类的完全限定类名。
  • android:exported 设置为 true,因为该活动必须由除自身之外的应用程序(即启动器)启动。
  • android:launchMode 设置为 singleTask,以便用户在从启动器导航到其他位置后可以返回到同一活动的实例。
  • android:theme 设置为 @android:style/Theme.DeviceDefault.NoActionBar,以便应用程序占用可用的所有屏幕空间。
  • 意图过滤器表明这是应用程序的启动器活动。
  • 有一个 <meta-data> 元素指示操作系统应用程序可以在存在 UX 限制的情况下使用,例如车辆正在行驶时。

对于 导航 应用程序,CarAppActivity 需要一些额外的清单条目,如下面的代码片段所示

<activity
    android:exported="true"
    android:theme="@android:style/Theme.DeviceDefault.NoActionBar"
    android:name="androidx.car.app.activity.CarAppActivity"
    android:launchMode="singleTask"
    android:label="Your app name">

    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
        <!-- Include the category below ONLY for navigation apps -->
        <category android:name="android.intent.category.APP_MAPS" />
    </intent-filter>

    <!-- Include the intent-filter below ONLY for navigation apps -->
    <intent-filter>
        <action android:name="androidx.car.app.action.NAVIGATE" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:scheme="geo" />
    </intent-filter>

    <meta-data android:name="distractionOptimized" android:value="true" />

</activity>
  • 额外的 android.intent.category.APP_MAPS 类别通知系统您的应用程序能够显示用户的当前位置。
  • androidx.car.app.action.NAVIGATE 意图过滤器确保用户在处理来自其他汽车应用程序的隐式导航意图时可以选择使用您的应用程序。

其他注意事项

在开发 Android Automotive OS 应用程序时,请牢记以下其他注意事项

包名

由于您为 Android Automotive OS 分发了单独的 Android 包套件 (APK),因此您可以重用移动应用程序中的包名或创建新的包名。如果您使用不同的包名,您的应用程序将有两个单独的 Play 商店列表。如果您重用当前的包名,您的应用程序将在两个平台上都拥有一个列表。

这主要是一个业务决策。例如,如果您有一个团队负责开发移动应用程序,而另一个团队负责开发 Android Automotive OS 应用程序,那么使用单独的包名并让每个团队管理自己的 Play 商店列表可能更有意义。使用这两种方法所需的技术工作量没有太大差异。

下表总结了保留当前包名或使用新包名之间的其他一些关键区别

功能 相同的包名 新的包名
商店列表 单个 多个
镜像安装 是:在安装向导期间快速重新安装应用程序
Play 商店审查流程 阻止审查:如果一个 APK 的审查失败,则在同一版本中提交的其他 APK 会被阻止 单独审查
统计信息、指标和 关键指标 合并:您可以按设备名称筛选汽车专用数据。 单独
索引和搜索排名 建立在当前排名基础上 没有延续
与其他应用程序集成 可能不需要进行任何更改,假设媒体代码在两个 APK 之间共享 可能需要更新相应的应用程序,例如使用 Google 助理进行 URI 播放

离线内容

如果适用,请在您的应用程序中实现离线支持。配备 Android Automotive OS 的汽车预计将拥有自己的数据连接,这意味着数据计划包含在车辆成本中或由用户支付。但是,汽车的连接性预计也会比移动设备更不稳定。

在考虑离线支持策略时,请牢记以下几点

  • 下载内容的最佳时机是在应用程序使用期间。
  • 不要假设可以使用 Wi-Fi。汽车可能永远不会进入 Wi-Fi 范围,或者原始设备制造商 (OEM) 可能已禁用 Wi-Fi 以支持蜂窝网络。
  • 虽然可以智能地缓存您希望用户使用的内容,但我们建议您让用户更改此行为。
  • 汽车上的磁盘空间各不相同,因此请为用户提供一种删除离线内容的方法。

常见问题解答

请参阅以下部分以获取有关 Android Automotive OS 的一些常见问题的答案。

使用第三方 SDK 和库是否有任何限制或建议?

使用第三方 SDK 和库没有具体的指南。如果您选择使用第三方 SDK 和库,您仍然有责任遵守所有汽车应用程序质量要求。

如何使用 Google Play 管理中心发布 Android Automotive OS 应用程序?

应用程序发布流程类似于发布手机应用程序,但您使用不同的外形尺寸。要选择加入应用程序以使用 Android Automotive OS 发布类型,请按照以下步骤操作

  1. 打开 Play 管理中心
  2. 选择您的应用程序。
  3. 从左侧菜单中,选择**发布 > 设置 > 高级设置 > 外形尺寸**。
  4. 选择**添加外形尺寸 > Android Automotive OS**,然后按照 Play 管理中心的说明操作。

故障排除

有关 Android Automotive OS 上一些常见故障排除方案的帮助,请参阅以下内容。

  • 即使从系统设置中卸载了 Car App Library 应用程序,在尝试安装新版本时也会出现错误。

    要确保应用程序已卸载,请使用命令 adb uninstall app.package.name