Android Automotive OS允许用户在车载系统中安装应用程序。要覆盖此平台上的用户,您需要分发一个针对驾驶员优化的、与Android Automotive OS兼容的应用程序。您可以重用Android Auto应用程序中几乎所有代码和资源,但必须创建一个满足此页面要求的单独构建。
开发概述
添加Android Automotive OS支持只需要几个步骤,如下节所述。
- 在Android Studio中启用汽车功能.
- 创建汽车模块.
- 更新您的Gradle依赖项.
- 可选地,实现设置和登录活动。
- 可选地,读取媒体主机提示。
设计注意事项
Android Automotive OS负责布局从您的应用的媒体浏览器服务接收的媒体内容。这意味着当用户触发媒体播放时,您的应用不会绘制UI,也不会启动任何活动。
如果您正在实现设置或登录活动,则这些活动必须是针对车辆优化的。在设计应用的这些区域时,请参考Android Automotive OS的设计指南。
设置您的项目
您需要设置应用项目的几个部分才能启用对Android Automotive OS的支持。
在Android Studio中启用汽车功能
使用Android Studio 4.0或更高版本以确保启用所有Automotive OS功能。
创建汽车模块
Android Automotive OS的某些组件(例如清单)具有特定于平台的要求。创建一个模块,可以将这些组件的代码与项目中的其他代码(例如用于手机应用的代码)分开。
请按照以下步骤将汽车模块添加到您的项目中。
- 在Android Studio中,点击文件 > 新建 > 新建模块。
- 选择汽车模块,然后点击下一步。
- 输入应用程序/库名称。这是用户在Android Automotive OS上看到的应用名称。
- 输入模块名称。
- 调整包名以匹配您的应用。
为最低SDK选择API 28:Android 9.0(派),然后点击下一步。
所有支持Android Automotive OS的汽车都运行在Android 9(API级别28)或更高版本上,因此选择此值可以定位所有兼容的汽车。
选择无活动,然后点击完成。
在Android Studio中创建模块后,打开您新的汽车模块中的AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.media">
<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的支持。请注意,清单中没有声明任何活动。
如果您实现设置或登录活动,请在此处添加它们。这些活动由系统使用显式意图触发,并且是您在Android Automotive OS应用的清单中声明的唯一活动。
添加任何设置或登录活动后,通过在application
元素中设置android:appCategory="audio"
属性并添加以下uses-feature
元素来完成清单文件。
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.media"> <application android:allowBackup="true" android:appCategory="audio" 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.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" /> </manifest>
将这些功能显式设置为required="false"
可以确保您的应用不会与Automotive OS设备中可用的硬件功能冲突。
声明对Android Automotive OS的媒体支持
使用以下清单条目声明您的应用支持Android Automotive OS。
<application>
...
<meta-data android:name="com.android.automotive"
android:resource="@xml/automotive_app_desc"/>
...
</application>
此清单条目引用一个XML文件,该文件声明您的应用支持的汽车功能。
要指示您有一个媒体应用,请将名为automotive_app_desc.xml
的XML文件添加到项目中的res/xml/
目录。在此文件中包含以下内容。
<automotiveApp>
<uses name="media"/>
</automotiveApp>
意图过滤器
Android Automotive OS使用显式意图来触发媒体应用中的活动。不要在清单文件中包含任何具有CATEGORY_LAUNCHER
或ACTION_MAIN
意图过滤器的活动。
像以下示例中的活动通常以手机或其他移动设备为目标。在构建手机应用的模块中声明这些活动,而不是在构建Android Automotive OS应用的模块中声明这些活动。
<activity android:name=".MyActivity">
<intent-filter>
<!-- You can't use either of these intents for Android Automotive OS -->
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<!--
In their place, you can include other intent filters for any activities
that your app needs for Android Automotive OS, such as settings or
sign-in activities.
-->
</intent-filter>
</activity>
更新您的Gradle依赖项
我们建议您将媒体浏览器服务 保持在单独的模块中,以便在您的手机应用和汽车模块之间共享。如果您使用这种方法,则需要更新您的汽车模块以包含共享模块,如下面的代码片段所示。
Groovy
buildscript { ... dependencies { ... implementation project(':shared_module_name') } }
Kotlin
buildscript { ... dependencies { ... implementation(project(":shared_module_name")) } }
实现设置和登录活动
除了媒体浏览器服务之外,您还可以为您的 Android Automotive OS 应用提供针对车辆优化的 设置和登录活动。这些活动允许您提供 Android 媒体 API 中未包含的应用功能。
只有当您的 Android Automotive OS 应用需要允许用户登录或指定应用设置时,才实现这些活动。Android Auto 不使用这些活动。
活动工作流程
下图显示了用户如何使用 Android Automotive OS 与您的设置和登录活动进行交互。
避免在设置和登录活动中出现干扰
为确保您的设置和/或登录活动仅在用户车辆停放时可用,请验证<activity>
元素不包含以下<meta-data>
元素。如果存在此类元素,您的应用将在审核期间被拒绝。
<!-- NOT ALLOWED -->
<meta-data
android:name="distractionOptimized"
android:value="true"/>
添加设置活动
您可以添加针对车辆优化的设置活动,以便用户可以在他们的车中配置您的应用设置。您的设置活动还可以提供其他工作流程,例如登录或注销用户帐户或切换用户帐户。请记住,此活动仅由在 Android Automotive OS 上运行的应用触发。连接到 Android Auto 的手机应用不使用它。
声明设置活动
您必须在应用的清单文件中声明您的设置活动,如下面的代码片段所示。
<application>
...
<activity android:name=".AppSettingsActivity"
android:exported="true"
android:theme="@style/SettingsActivity"
android:label="@string/app_settings_activity_title">
<intent-filter>
<action android:name="android.intent.action.APPLICATION_PREFERENCES"/>
</intent-filter>
</activity>
...
</application>
实现您的设置活动
当用户启动您的应用时,Android Automotive OS 会检测到您声明的设置活动并显示一个辅助功能,例如图标。用户可以使用他们的汽车显示屏点击或选择此辅助功能以导航到该活动。Android Automotive OS 会发送ACTION_APPLICATION_PREFERENCES
意图,该意图告诉您的应用启动您的设置活动。
本节的其余部分将展示如何从通用 Android 音乐播放器 (UAMP) 示例应用 调整代码以实现您的应用的设置活动。
首先,下载示例代码。
# Clone the UAMP repositorygit clone https://github.com/android/uamp.git
# Fetch the appropriate pull request to your local repositorygit fetch origin pull/323/head:NEW_LOCAL_BRANCH_NAME
# Switch to the new branchgit checkout NEW_LOCAL_BRANCH_NAME
要实现您的活动,请按照以下步骤操作。
- 将
automotive/automotive-lib
文件夹复制到您的汽车模块中。 - 定义一个首选项树,如
automotive/src/main/res/xml/preferences.xml
中所示。 实现一个
PreferenceFragmentCompat
,您的设置活动将显示它。有关详细信息,请参阅 UAMP 中的SettingsFragment.kt
和SettingsActivity.kt
文件以及Android 设置指南。
在实现设置活动时,请考虑使用首选项库中某些组件的最佳实践。
- 在设置活动中的主视图下,深度不超过两层。
- 不要使用
DropDownPreference
。改为使用ListPreference
。 - 组织组件
PreferenceScreen
- 这必须是首选项树的顶层。
PreferenceCategory
- 用于将
Preference
对象组合在一起。 - 包含
title
。
- 用于将
- 在所有以下组件中包含
key
和title
。您还可以包含summary
、icon
或两者。Preference
- 自定义
PreferenceFragmentCompat
实现的onPreferenceTreeClick()
回调中的逻辑。
- 自定义
CheckBoxPreference
- 可以使用
summaryOn
或summaryOff
代替summary
来实现条件文本。
- 可以使用
SwitchPreference
- 可以使用
summaryOn
或summaryOff
代替summary
来实现条件文本。 - 可以使用
switchTextOn
或switchTextOff
。
- 可以使用
SeekBarPreference
- 包含
min
、max
和defaultValue
。
- 包含
EditTextPreference
- 包含
dialogTitle
、positiveButtonText
和negativeButtonText
。 - 可以使用
dialogMessage
和/或dialogLayoutResource
。
- 包含
com.example.android.uamp.automotive.lib.ListPreference
- 主要派生自
ListPreference
。 - 用于显示
Preference
对象的单选列表。 - 必须包含
entries
数组和相应的entryValues
。
- 主要派生自
com.example.android.uamp.automotive.lib.MultiSelectListPreference
- 主要派生自
MultiSelectListPreference
- 用于显示
Preference
对象的多选列表。 - 必须包含
entries
数组和相应的entryValues
。
- 主要派生自
添加登录活动
如果您的应用要求用户在使用您的应用之前登录,您可以添加一个针对车辆优化的登录活动来处理登录和注销您的应用。您还可以将登录和注销工作流程添加到设置活动,但如果您的应用在用户登录之前无法使用,请使用专用的登录活动。请记住,此活动仅由在 Android Automotive OS 上运行的应用触发。连接到 Android Auto 的手机应用不使用它。
要求在应用启动时登录
要要求用户在使用您的应用之前登录,您的媒体浏览器服务必须执行以下操作。
- 在服务的
onLoadChildren()
方法中,使用sendResult()
方法发送null
结果。 - 使用
setState()
方法将媒体会话的PlaybackStateCompat
设置为STATE_ERROR
。这会告诉 Android Automotive OS 在错误解决之前无法执行其他操作。 - 将媒体会话的
PlaybackStateCompat
错误代码设置为ERROR_CODE_AUTHENTICATION_EXPIRED
。这会告诉 Android Automotive OS 用户需要进行身份验证。 - 使用
setErrorMessage()
方法设置媒体会话的PlaybackStateCompat
错误消息。由于此错误消息面向用户,因此请根据用户的当前区域设置将其本地化。 使用
setExtras()
方法设置媒体会话的PlaybackStateCompat
附加信息。包含以下两个键:PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_LABEL
:在启动登录工作流程的按钮上显示的字符串。由于此字符串面向用户,因此请根据用户的当前区域设置将其本地化。PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_INTENT
:一个PendingIntent
,当用户点击PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_LABEL
所指的按钮时,会将用户引导到您的登录活动。
以下代码片段显示了您的应用如何在使用您的应用之前要求用户登录。
Kotlin
import androidx.media.utils.MediaConstants val signInIntent = Intent(this, SignInActivity::class.java) val signInActivityPendingIntent = PendingIntent.getActivity(this, 0, signInIntent, 0) val extras = Bundle().apply { putString( MediaConstants.PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_LABEL, "Sign in" ) putParcelable( MediaConstants.PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_INTENT, signInActivityPendingIntent ) } val playbackState = PlaybackStateCompat.Builder() .setState(PlaybackStateCompat.STATE_ERROR, 0, 0f) .setErrorMessage( PlaybackStateCompat.ERROR_CODE_AUTHENTICATION_EXPIRED, "Authentication required" ) .setExtras(extras) .build() mediaSession.setPlaybackState(playbackState)
Java
import androidx.media.utils.MediaConstants; Intent signInIntent = new Intent(this, SignInActivity.class); PendingIntent signInActivityPendingIntent = PendingIntent.getActivity(this, 0, signInIntent, 0); Bundle extras = new Bundle(); extras.putString( MediaConstants.PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_LABEL, "Sign in"); extras.putParcelable( MediaConstants.PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_INTENT, signInActivityPendingIntent); PlaybackStateCompat playbackState = new PlaybackStateCompat.Builder() .setState(PlaybackStateCompat.STATE_ERROR, 0, 0f) .setErrorMessage( PlaybackStateCompat.ERROR_CODE_AUTHENTICATION_EXPIRED, "Authentication required" ) .setExtras(extras) .build(); mediaSession.setPlaybackState(playbackState);
在用户成功进行身份验证后,将PlaybackStateCompat
设置回STATE_ERROR
以外的状态,然后通过调用活动的finish()
方法将用户带回 Android Automotive OS。
实现您的登录活动
Google 提供各种身份工具,您可以使用这些工具来帮助用户登录他们汽车中的应用。某些工具(例如 Firebase 身份验证)提供全栈工具包,可以帮助您构建自定义身份验证体验。其他工具利用用户的现有凭据或其他技术来帮助您为用户构建无缝登录体验。
以下工具可以帮助您为之前在其他设备上登录的用户构建更轻松的登录体验。
- 一键式登录和注册:如果您已经为其他设备(例如您的手机应用)实现了一键式登录,请为您的 Android Automotive OS 应用实现它以支持现有的一键式用户。
- Google 登录:如果您已经为其他设备(例如您的手机应用)实现了Google 登录,请为您的 Android Automotive OS 应用实现 Google 登录以支持现有的 Google 登录用户。
- 使用 Google 自动填充:如果用户已在其其他 Android 设备上选择使用 Google 自动填充,则他们的凭据将保存到Google 密码管理器。当这些用户登录到您的 Android Automotive OS 应用时,Google 自动填充会建议相关的已保存凭据。使用 Google 自动填充无需任何应用开发工作。但是,应用开发者可以优化他们的应用以获得更好的质量结果。所有运行 Android 8.0(API 级别 26)或更高版本的设备(包括 Android Automotive OS)都支持 Google 自动填充。
使用 AccountManager
具有身份验证功能的 Android Automotive OS 应用必须使用AccountManager,原因如下:
- 更好的用户体验和简化帐户管理:用户可以轻松地从系统设置中的帐户菜单管理所有帐户,包括登录和注销。
- “访客”体验:车辆是共享设备,这意味着 OEM 可以启用车辆中的“访客”体验,在此体验中无法添加帐户。此限制是使用
DISALLOW_MODIFY_ACCOUNTS
针对AccountManager
实现的。
权限
如果需要向用户请求权限,请使用与上一节所示活动工作流程图 中的身份验证活动或设置活动相同的流程。
读取媒体主机提示
根据连接到您的媒体浏览器服务的系统应用程序(包括其版本),您的应用程序可能会收到以下额外信息
错误处理
Android Automotive OS 上媒体应用中的错误通过媒体会话的 PlaybackStateCompat
传达。对于所有错误,请在 PlaybackStateCompat
中设置相应的错误代码和错误消息。这会导致 UI 中出现 Toast
。
发生错误但可以继续播放时,请发出非致命性错误。例如,用户可能可以在登录前播放应用中的音乐,但必须登录才能跳过歌曲。使用非致命性错误时,系统可以建议用户登录,而不会中断当前媒体项目的播放。
发出非致命性错误时,请保留其余的 PlaybackStateCompat
原样,除了错误代码和错误消息。使用这种方法可以让当前媒体项目的播放继续进行,同时用户决定是否登录。
当无法播放时(例如,没有互联网连接且没有离线内容时),请将 PlaybackStateCompat
状态设置为 STATE_ERROR
。
在后续更新您的 PlaybackStateCompat
时,请清除所有错误代码和错误消息,以避免显示同一错误的多个警告。
如果在任何时候都无法加载浏览树(例如,如果需要身份验证且用户未登录),请发送一个空的浏览树。为此,请从根媒体节点的 onLoadChildren()
返回 null 结果。发生这种情况时,系统会显示一个带有在 PlaybackStateCompat
中设置的错误消息的全屏错误。
可操作的错误
如果错误是可操作的,请在 PlaybackStateCompat
中额外设置以下两个额外信息
PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_LABEL
:用于单击以解决错误的按钮的标签。由于此字符串面向用户,因此请根据用户的当前语言环境对其进行本地化。PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_INTENT
:按钮运行以解决错误的PendingIntent
,例如启动您的登录活动。
可操作的错误显示为 Dialog
,只有在车辆停止时才能由用户解决。
测试错误案例
验证您的应用是否可在所有情况下优雅地处理错误,包括
- 不同级别的产品:例如,免费版与付费版或已登录与未登录
- 不同的驾驶状态:例如,已停车与行驶中
- 不同的连接状态:例如,在线与离线
其他注意事项
开发 Android Automotive OS 应用时,请记住以下其他注意事项
离线内容
如果适用,请实现离线播放支持。配备 Android Automotive OS 的汽车预计将拥有自己的数据连接,这意味着数据计划包含在车辆成本中或由用户付费。但是,汽车的连接变化也比移动设备更大。
在考虑您的离线支持策略时,请记住以下几点
- 下载内容的最佳时间是在您的应用正在使用时。
- 不要假设有 WiFi 可用。汽车可能永远不会进入 WiFi 范围,或者 OEM 可能已禁用 WiFi 而选择蜂窝网络。
- 虽然可以智能地缓存用户期望使用的内容,但我们建议您允许用户通过您的设置活动更改此行为。
- 汽车上的磁盘空间各不相同,因此请为用户提供一种删除离线内容的方法,例如通过设置活动中的选项。
WebView 支持
Android Automotive OS 支持 WebView,但仅限于您的设置和登录活动。使用 WebView 的活动必须在 WebView 之外具有“关闭”或“返回”功能。
以下是 WebView 可接受用例的一些示例
- 在您的设置活动中显示您的隐私政策、服务条款或其他与法律相关的链接。
- 登录活动中的基于 Web 的流程。
使用 WebView 时,您可以启用 Javascript。
保护您的 WebView
采取一切可能的预防措施,以帮助确保您的 WebView 不是进入更大互联网的入口点。请参阅以下代码片段,了解如何将 WebView 锁定到 loadUrl()
调用中使用的 URL 并阻止重定向的示例。我们强烈建议您在可行的情况下实施此类安全措施,例如在显示与法律相关的链接时。
Kotlin
override fun shouldOverrideUrlLoading(webView: WebView, webResourceRequest: WebResourceRequest): Boolean { val originalUri: Uri = Uri.parse(webView.originalUrl) // Check for allowed URLs if (originalUri.equals(Uri.parse(BLANK_URL)) || originalUri.equals(webResourceRequest.url)) { return false } if (webResourceRequest.isRedirect) { logger.w("Redirect detected, not following") return true } setupWizardWebViewClientListener.onUriBlocked(webResourceRequest.url) logger.w( String.format( "Navigation prevented to %s original is %s", webResourceRequest.url, originalUri)) return true }
Java
@Override public boolean shouldOverrideUrlLoading(WebView webView, WebResourceRequest webResourceRequest) { Uri originalUri = Uri.parse(webView.getOriginalUrl()); // Check for allowed URLs if (originalUri.equals(Uri.parse(BLANK_URL)) || originalUri.equals(webResourceRequest.getUrl())) { return false; } if (webResourceRequest.isRedirect()) { logger.w("Redirect detected, not following"); return true; } setupWizardWebViewClientListener.onUriBlocked(webResourceRequest.getUrl()); logger.w( String.format( "Navigation prevented to %s original is %s", webResourceRequest.getUrl(), originalUri)); return true; }
包名
因为您为 Android Automotive OS 分发单独的 Android 包工具包 (APK),所以您可以重用移动应用的包名或创建新的包名。如果您使用不同的包名,您的应用将有两个单独的 Play 商店列表。如果您重用当前的包名,您的应用将在两个平台上都有一个列表。
这主要是一个业务决策。例如,如果您有一个团队负责移动应用,而另一个团队负责您的 Android Automotive OS 应用,那么拥有单独的包名并让每个团队管理其自己的 Play 商店列表可能更有意义。使用这两种方法所需的的技术工作量差别不大。
下表总结了保留当前包名和使用新包名之间的一些其他关键区别
功能 | 相同的包名 | 新的包名 |
---|---|---|
商店列表 | 单个 | 多个 |
镜像安装 | 是:“快速应用重新安装”在设置向导期间 | 否 |
Play 商店审核流程 | 阻止审核:如果一个 APK 的审核失败,则在同一版本中提交的其他 APK 将被阻止 | 单独审核 |
统计数据、指标和关键指标 | 组合:您可以筛选汽车专用数据。 | 单独 |
索引和搜索排名 | 基于当前排名 | 无延续 |
与其他应用集成 | 很可能不需要更改,假设媒体代码在两个 APK 之间共享 | 可能必须更新相应的应用,例如对于与 Google 助手一起使用的 URI 播放。 |
常见问题
请参阅以下部分,了解有关 Android Automotive OS 的一些常见问题的解答。
硬件
我的应用能否访问麦克风?
对于目标 Android 10(API 级别 29)或更高版本的应用,请参阅共享音频输入文档。在 API 级别 29 之前,这是不可行的。
我们可以访问哪些汽车 API 以及如何访问?
您仅限于 OEM 公开的 API。正在制定流程以标准化您访问这些 API 的方式。
应用可以使用 SetProperty()
和 GetProperty()
在 CarPropertyManager
中访问汽车 API。请参阅源代码或参考文档以查看所有可用属性的列表。如果属性用注释 @SystemApi
,则它仅限于预加载的系统应用。
支持哪些类型的音频编解码器?
请参阅 Android CDD 中的音频编解码器详细信息。
是否支持 Widevine DRM?
支持。Widevine DRM 受支持。
开发和测试
使用第三方 SDK 和库是否有任何限制或建议?
我们对使用第三方 SDK 和库没有任何具体指南。如果您选择使用第三方 SDK 和库,您仍然有责任遵守所有汽车应用质量要求。
我可以使用前台服务吗?
前台服务的唯一允许用例是下载用于离线使用的内容。如果您有其他想要支持的前台服务用例,请使用Android Automotive OS 讨论组与我们联系。
发布 Android Automotive OS 应用
如何使用 Google Play Console 发布我的 Android Automotive OS 应用?
应用发布流程类似于发布手机应用,但您使用不同的外形尺寸。要选择您的应用使用 Android Automotive OS 外形尺寸,请按照以下步骤操作
- 打开Play Console。
- 选择您的应用。
- 在左侧菜单中,点击发布 > 设置 > 高级设置 > 外形尺寸。
- 点击添加外形尺寸 > Android Automotive OS,然后按照 Play Console 中的说明操作。
其他资源
要了解有关 Android Automotive OS 的更多信息,请参阅以下其他资源。
示例
指南
博客
视频
报告 Android Automotive OS 媒体问题
如果您在为Android Automotive OS开发媒体应用时遇到问题,您可以使用Google Issue Tracker进行报告。请确保填写问题模板中所有所需的信息。
在提交新问题之前,请检查该问题是否已在问题列表中报告。您可以通过点击追踪器中问题的星标来订阅和投票。更多信息,请参见订阅问题。