标签:
Android N for Developers
转载请注明: http://blog.csdn.net/wen_demo/article/details/51943340
1.多窗口支持
Android N 添加了对同时显示多个应用窗口的支持。 在手持设备上,两个应用可以在“分屏”模式中左右并排或上下并排显示。 在电视设备上,应用可以使用“画中画”模式,在用户与另一个应用交互的同时继续播放视频。
如果您使用 N Preview SDK 构建应用,则可以配置应用处理多窗口显示的方法。 例如,您可以指定 Activity 的最小允许尺寸。 您还可以禁用应用的多窗口显示,确保系统仅以全屏模式显示应用。
Android N 允许多个应用同时共享屏幕。例如,用户可以分屏显示应用,在左边查看网页,同时在右边写邮件。 用户体验取决于设备:
图 1. 两个应用在分屏模式中左右并排显示。
用户可以通过以下方式切换到多窗口模式:
用户可以在两个 Activity 共享屏幕的同时在这两个 Activity 之间拖放数据 (在此之前,用户只能在一个 Activity 内部拖放数据)。
多窗口模式不会更改 Activity 生命周期。
在多窗口模式中,在指定时间只有最近与用户交互过的 Activity 为活动状态。 该 Activity 将被视为顶级 Activity。 所有其他 Activity 虽然可见,但均处于暂停状态。 但是,这些已暂停但可见的 Activity 在系统中享有比不可见 Activity 更高的优先级。 如果用户与其中一个暂停的 Activity 交互,该 Activity 将恢复,而之前的顶级 Activity 将暂停。
注:在多窗口模式中,用户仍可以看到处于暂停状态的应用。 应用在暂停状态下可能仍需要继续其操作。 例如,处于暂停模式但可见的视频播放应用应继续显示视频。 因此,我们建议播放视频的 Activity 不要暂停其 onPause()
处理程序中的视频。 应暂停 onStop()
中的视频,并恢复 onStart()
中的视频播放。
如处理运行时变更中所述,用户使用多窗口模式显示应用时,系统将通知 Activity 发生配置变更。 这也会发生在当用户调整应用大小,或将应用恢复到全屏模式时。 该变更与系统通知应用设备从纵向模式切换到横向模式时的 Activity 生命周期影响基本相同,但设备不仅仅是交换尺寸,而是会变更尺寸。 如处理运行时变更中所述,您的 Activity 可以自行处理配置变更,或允许系统销毁 Activity,并以新的尺寸重新创建该 Activity。
如果用户调整窗口大小,并在任意维度放大窗口尺寸,系统将调整 Activity 以匹配用户操作,同时根据需要发布运行时变更。 如果应用在新公开区域的绘制滞后,系统将使用 windowBackground
属性或默认 windowBackgroundFallback
样式属性指定的颜色暂时填充该区域。
如果您的应用面向 Android N,您可以对应用的 Activity 是否支持多窗口显示以及显示方式进行配置。 您可以在清单文件中设置属性,以控制大小和布局。 根 Activity 的属性设置适用于其任务栈中的所有 Activity。 例如,如果根 Activity 已 android:resizeableActivity
设定为 true,则任务栈中的所有 Activity 都将可以调整大小。
注:如果您使用低于 Android N 版本的 SDK 构建多向应用,则用户在多窗口模式中使用应用时,系统将强制调整应用大小。 系统将显示对话框,提醒用户应用可能会发生异常。 系统不会调整定向应用的大小;如果用户尝试在多窗口模式下打开定向应用,应用将全屏显示。
在清单的 <activity>
或 <application>
节点中设置该属性,启用或禁用多窗口显示:
android:resizeableActivity=["true" | "false"]
如果该属性设置为 true,Activity 将能以分屏和自由形状模式启动。 如果此属性设置为 false,Activity 将不支持多窗口模式。 如果该值为 false,且用户尝试在多窗口模式下启动 Activity,该 Activity 将全屏显示。
如果您的应用面向 Android N,但未对该属性指定值,则该属性的值默认设为 true。
在清单文件的 <activity>
节点中设置该属性,指明 Activity 是否支持画中画显示。 如果 android:resizeableActivity
为 false,将忽略该属性。
android:supportsPictureInPicture=["true" | "false"]
对于 Android N,<layout>
清单元素支持以下几种属性,这些属性影响 Activity 在多窗口模式中的行为:
android:defaultWidth
android:defaultHeight
android:gravity
Gravity
参考资料,了解合适的值设置。android:minimalHeight
、android:minimalWidth
例如,以下节点显示了如何指定 Activity 在自由形状模式中显示时 Activity 的默认大小、位置和最小尺寸:
<activity android:name=".MyActivity"> <layout android:defaultHeight="500dp" android:defaultWidth="600dp" android:gravity="top|end" android:minimalHeight="450dp" android:minimalWidth="300dp" /> </activity>
Android N 添加了新功能,以支持可在多窗口模式中运行的应用。
在设备处于多窗口模式中时,某些功能会被禁用或忽略,因为这些功能对与其他 Activity 或应用共享设备屏幕的 Activity 而言没有意义。 此类功能包括:
android:screenOrientation
属性所作的更改。
Activity
类中添加了以下新方法,以支持多窗口显示。 有关各方法的详细信息,请参阅 N
Preview SDK 参考。
Activity.isInMultiWindowMode()
Activity.isInPictureInPictureMode()
注:画中画模式是多窗口模式的特例。 如果 myActivity.isInPictureInPictureMode()
返回 true,则 myActivity.isInMultiWindowMode()
也返回 true。
Activity.onMultiWindowModeChanged()
Activity.onPictureInPictureModeChanged()
每个方法还有 Fragment
版本,例如 Fragment.isInMultiWindowMode()
。
如需在画中画模式中启动 Activity,请调用新方法 Activity.enterPictureInPictureMode()
。 如果设备不支持画中画模式,则此方法无效。 如需了解详细信息,请参阅画中画文档。
在启动新 Activity 时,用户可以提示系统如果可能,应将新 Activity 显示在当前 Activity 旁边。 要执行此操作,可使用标志Intent.FLAG_ACTIVITY_LAUNCH_TO_ADJACENT
。 传递此标志将请求以下行为:
如果设备处于自由形状模式,则在启动新 Activity 时,用户可通过调用 ActivityOptions.setLaunchBounds()
指定新 Activity 的尺寸和屏幕位置。 如果设备不处于多窗口模式,则该方法无效。
注:如果您在任务栈中启动 Activity,该 Activity 将替换屏幕上的 Activity,并继承其所有的多窗口属性。 如果要在多窗口模式中以单独的窗口启动新 Activity,则必须在新的任务栈中启动此 Activity。
用户可以在两个 Activity 共享屏幕的同时在这两个 Activity 之间拖放数据 (在此之前,用户只能在一个 Activity 内部拖放数据)。 因此,如果您的应用目前不支持拖放功能,您可以在其中添加此功能。
N Preview SDK 扩展了 android.view
软件包,以支持跨应用拖放。 有关以下类和方法的详细信息,请参阅 N
Preview SDK 参考。
android.view.DropPermissions
View.startDragAndDrop()
View.startDrag()
的新别名。要启用跨
Activity 拖放,请传递新标志 View.DRAG_FLAG_GLOBAL
。 如需对接收拖放数据的 Activity 授予 URI 权限,可根据情况传递新标志 View.DRAG_FLAG_GLOBAL_URI_READ
或 View.DRAG_FLAG_GLOBAL_URI_WRITE
。View.cancelDragAndDrop()
View.updateDragShadow()
Activity.requestDropPermissions()
DragEvent
中包含的 ClipData
传递的内容
URI 的权限。无论您是否针对 Android N 更新应用,都应验证应用在多窗口模式下的行为,以防用户尝试在运行 Android N 的设备上以多窗口模式启动应用。
如果在设备上安装 Android N,则将自动支持分屏模式。
如果您的应用不是使用 N Preview SDK 构建的,则用户尝试在多窗口模式中使用应用时,系统将强制调整应用大小,除非应用进行了定向声明。
如果您的应用没有进行定向声明,则应在运行 Android N 的设备上启动应用,并尝试将应用切换到分屏模式。 验证并确保在强制调整应用大小时用户体验可接受。
如果应用进行了定向声明,则应尝试将应用切换到多窗口模式。 验证并确保执行此操作后,应用仍保持全屏模式。
如果您的应用是使用 N Preview SDK 构建的,且未禁用多窗口支持,则分别在分屏和自由形状模式下验证以下行为。
要在多窗口模式中验证应用性能,请执行以下操作。 除非另有说明,否则请分别在分屏和多窗口模式中执行以下操作。
如果您通过设置 android:resizableActivity="false"
禁用了多窗口支持,则应在运行 Android N 的设备上启动应用,并尝试将应用切换到自由形状和分屏模式。 验证并确保执行此操作后,应用仍保持全屏模式。
2.通知栏
Android N 引入了一些新 API,允许应用发布具有高度可见性和交互性的通知。
Android N 扩展了现有 RemoteInput
通知 API,以支持手持式设备上的内联回复。 此功能允许用户从通知栏快速进行回复,无需访问应用。
此外,Android N 还允许捆绑类似的通知并将它们显示为一则通知。 为了实现此功能,Android N 使用现有的NotificationCompat.Builder.setGroup()
方法。用户可以从通知栏展开各通知,并分别对每则通知进行回复和清除等操作。
最后,Android N 还添加了一些新 API,允许您在应用的自定义通知视图中使用系统装饰元素。 这些 API 可帮助确保通知视图与标准模板的展示效果相一致。
本文重点介绍您在应用中使用新通知功能时应加以考虑的一些重要变更。
利用 Android N 中的直接回复功能,用户可以直接在通知界面内快速回复短信或更新任务列表。 在手持式设备上,可通过通知中另外附加的按钮进行内联回复操作。 当用户通过键盘回复时,系统会将文本回复附加到您为通知操作指定的 Intent,并将 Intent 发送到手持式设备应用。
图 1.Android N 添加了 Reply 操作按钮。
要创建支持直接回复的通知操作:
RemoteInput.Builder
实例。
该类的构造函数接受系统用作文本输入密钥的字符串。 之后,手持式设备应用使用该密钥检索输入的文本。
// Key for the string that‘s delivered in the action‘s intent. private static final String KEY_TEXT_REPLY = "key_text_reply"; String replyLabel = getResources().getString(R.string.reply_label); RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY) .setLabel(replyLabel) .build();
addRemoteInput()
向操作附加 RemoteInput
对象。
// Create the reply action and add the remote input. Notification.Action action = new Notification.Action.Builder(R.drawable.ic_reply_icon, getString(R.string.label), replyPendingIntent) .addRemoteInput(remoteInput) .build();
// Build the notification and add the action. Notification newMessageNotification = new Notification.Builder(mContext) .setSmallIcon(R.drawable.ic_message) .setContentTitle(getString(R.string.title)) .setContentText(getString(R.string.content)) .addAction(action)) .build(); // Issue the notification. NotificationManager notificationManager = NotificationManager.from(mContext); notificationManager.notify(notificationId, newMessageNotification);
在触发通知操作时系统提示用户输入回复。
图 2.用户从通知栏输入文本。
要从通知界面接收用户输入并发送到在回复操作的 Intent 中声明的 Activity:
getResultsFromIntent()
。
该方法返回含有文本回复的 Bundle
。
Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
RemoteInput.Builder
构造函数)。以下代码段说明了方法如何从捆绑包检索输入文本:
// Obtain the intent that started this activity by calling // Activity.getIntent() and pass it into this method to // get the associated string. private CharSequence getMessageText(Intent intent) { Bundle remoteInput = RemoteInput.getResultsFromIntent(intent); if (remoteInput != null) { return remoteInput.getCharSequence(KEY_TEXT_REPLY); } return null; }
onReceive()
方法的上下文。
// Build a new notification, which informs the user that the system // handled their interaction with the previous notification. Notification repliedNotification = new Notification.Builder(context) .setSmallIcon(R.drawable.ic_message) .setContentText(getString(R.string.replied)) .build(); // Issue the new notification. NotificationManager notificationManager = NotificationManager.from(context); notificationManager.notify(notificationId, repliedNotification);
对于交互式应用(例如聊天),这可以用来在处理检索到的文本时添加其他上下文。 例如,这些应用可以显示多行聊天记录。 当用户通过 RemoteInput
回复时,您可以使用 setRemoteInputHistory()
方法更新回复历史。
在应用收到远程输入后,必须更新或取消通知。 如果用户使用直接回复来对远程更新进行回复,则不可取消通知。 否则,更新通知以显示用户的回复。对于使用 MessagingStyle
的通知,您应该添加回复来作为最新消息。 当使用其它模板时,您可以将用户的回复追加到远程输入历史。
Android N 为开发者提供了表示通知队列的新方法: 捆绑通知。这类似于 Android Wear 中的通知堆栈功能。 例如,如果应用为接收的消息创建通知,那么在接收到多个消息时,应用会将通知捆绑在一起成为一个群组。
您可以使用现有的 Builder.setGroup()
方法捆绑类似的通知。
通知组对组内的通知施加层次结构。 层次结构的顶层是父级通知,其显示该群组的摘要信息。 用户可以逐步展开通知组,随着用户深入展开,系统将显示更多信息。 当用户展开捆绑包时,系统将显示其所有子通知的更多信息;当用户展开其中一则通知时,系统显示该通知的所有内容。
图 3.用户可以逐步展开通知组。
注:如果同一应用发送了四条或以上通知,并且未指定分组,系统会自动将它们分到一组。
如需了解如何将通知添加到组,请参阅将各通知添加到组。
本节提供了有关何时使用通知组而非早期版本 Android 平台中的 InboxStyle
通知的指南。
只有在您的用例满足以下所有条件时才应使用通知组:
好的通知组用例示例包括:显示传入消息列表的短信应用,或显示收到的电子邮件列表的电子邮件应用。
适合显示单一通知的用例示例包括:从某一个人收到的单独消息,或以列表表示的单行文本项目。 您可以使用 InboxStyle
或 BigTextStyle
实现此功能。
即使组内仅含有一则子通知,应用也应发布组摘要。 如果只含有一则通知,系统将取消摘要并直接显示子通知。 这样可确保用户在滑动切换组内的子通知时,系统仍可以提供一致的用户体验。
注:本版本 Android N 目前还无法在仅含一则子通知时取消通知组的摘要。 我们将在之后版本的 Android N 中添加此功能。
虽然系统通常以群组的方式显示子通知,但您可以进行设置,使其暂时作为浮动通知显示。 该功能非常实用,因为其允许用户立即访问最近的子通知以及与其相关的操作。
自 Android 5.0(API 级别 21)起,Notification
API 中就添加了通知组和远程输入,以支持 Android
Wear 设备。 如果您已经使用这些 API 构建通知,则只需验证应用行为是否符合上述指南,并考虑实现 setRemoteInputHistory()
。
为了支持后向兼容性,支持库的 NotificationCompat
类中提供了相同的 API,以便您构建可在早期
Android 版本中运行的通知。 在手持式设备和平板电脑上,用户只能看到摘要通知,因此应用应仍提供收件箱式或类似形式的通知显示模式,以显示群组的全部信息内容。 鉴于 Android Wear 设备允许用户查看所有子通知,包括更早级别平台上的通知,您应在不依赖 API 级别的基础上构建子通知。
从 Android N 开始,您将可以自定义通知视图,同时仍可以使用系统装饰元素,例如通知标头、操作和可展开的布局。
为启用该功能,Android N 添加了以下 API,以便您样式化自己的自定义视图:
DecoratedCustomViewStyle()
DecoratedMediaCustomViewStyle()
如需使用这些新 API,可调用 setStyle()
方法,并向其传递所需的自定义视图样式。
此代码段显示了如何使用 DecoratedCustomViewStyle()
方法构建自定义通知对象。
Notification notification = new Notification.Builder() .setSmallIcon(R.drawable.ic_stat_player) .setLargeIcon(albumArtBitmap)) .setCustomContentView(contentView); .setStyle(new Notification.DecoratedCustomViewStyle()) .build();
Android N 引入了一项新的 API 来自定义通知样式。 使用 MessageStyle
类,您可以更改在通知中显示的多个标签,包括会话标题、其他消息和通知的内容视图。
以下代码段演示了如何使用 MessageStyle
类来自定义通知样式。
Notification notification = new Notification.Builder() .setStyle(new Notification.MessagingStyle("Me") .setConversationTitle("Team lunch") .addMessage("Hi", timestamp1, null) // Pass in null for user. .addMessage("What‘s up?", timestamp2, "Coworker") .addMessage("Not much", timestamp3, null) .addMessage("How about lunch?", timestamp4, "Coworker"));
3.Data Saver
在智能手机的整个生命周期,蜂窝数据计划的成本通常会超出设备本身的成本。 在 N Developer Preview 中,用户可以在整个设备上启用 Data Saver,以减少流量消耗,无论是在漫游,账单周期即将结束,还是使用少量的预付费数据包。
当用户在 Settings 中启用 Data Saver 且设备位于按流量计费的网络上时,系统屏蔽后台流量消耗,同时指示应用在前台尽可能使用较少的数据。 用户可以将特定应用加入白名单以允许后台按流量计费的流量消耗,即使在打开 Data Saver 时也是如此。
N Developer Preview 扩展ConnectivityManager
API,为应用提供检索用户的
Data Saver 首选项和监控首选项变更的方式。 这被认为是应用检查用户是否启用了 Data Saver 并努力限制前台和后台流量消耗的有效方法。
在 N Developer Preview 中,应用可以使用 ConnectivityManager
API 来确定正在应用的是哪些流量消耗限制。 getRestrictBackgroundStatus()
方法返回下列值之一:
RESTRICT_BACKGROUND_STATUS_DISABLED
RESTRICT_BACKGROUND_STATUS_ENABLED
RESTRICT_BACKGROUND_STATUS_WHITELISTED
这被认为是在设备连接到按流量计费的网络时限制流量消耗的有效方法,即使 Data Saver 被禁用或应用在白名单中。 以下示例代码使用ConnectivityManager.isActiveNetworkMetered()
和 ConnectivityManager.getRestrictBackgroundStatus()
来确定应用应使用多少数据:
ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); // Checks if the device is on a metered network if (connMgr.isActiveNetworkMetered()) { // Checks user’s Data Saver settings. switch (connMgr.getRestrictBackgroundStatus()) { case RESTRICT_BACKGROUND_STATUS_ENABLED: // Background data usage is blocked for this app. Wherever possible, // the app should also use less data in the foreground. case RESTRICT_BACKGROUND_STATUS_WHITELISTED: // The app is whitelisted. Wherever possible, // the app should use less data in the foreground and background. case RESTRICT_BACKGROUND_STATUS_DISABLED: // Data Saver is disabled. Since the device is connected to a // metered network, the app should use less data wherever possible. } } else { // The device is not on a metered network. // Use data as required to perform syncs, downloads, and updates. }
如果您的应用需要使用后台数据,它可以通过发送一项包含您的应用软件包名称的 URI 的Settings.ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS
Intent 来请求白名单权限:例如 package:MY_APP_ID
。
发送 Intent 和 URI 将启动 Settings 应用,还会显示您的应用的流量消耗设置。 用户随后可以决定是否启用应用的后台数据。 在您发送此 Intent 之前,先询问用户是否希望启用 Settings 应用,以启用后台流量消耗,这是一种有效的做法。
应用可以通过创建一条 BroadcastReceiver
以侦听 ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED
以及使用 Context.registerReceiver()
动态注册接收器来监控
Data Saver 首选项变更。 当应用接收到这条广播时,应通过调用 ConnectivityManager.getRestrictBackgroundStatus()
来检查新的
Data Saver 首选项是否会影响其权限。
注:系统只会向使用 Context.registerReceiver()
进行动态注册的应用发送此广播。
在其清单中注册接收此广播的应用将不会收到它们。
$ adb shell dumpsys netpolicy
$ adb shell cmd netpolicy
$ adb shell cmd netpolicy set restrict-background <boolean>
true
或 false
时,启用或禁用 Data Saver 模式。$ adb shell cmd netpolicy add restrict-background-whitelist <UID>
$ adb shell cmd netpolicy remove restrict-background-whitelist <UID>
从白名单中移除指定软件包 UID,以阻止当 Data Saver 启用时后台按流量计费的流量消耗。
4.TV
TV 输入服务允许用户通过时移 API 暂停和继续频道播放。 Android N 通过允许用户保存多个录制的会话,扩展了时移。
用户可以提前安排录制,或在观看节目时开始录制。 系统保存录制后,用户即可使用系统 TV 应用浏览、管理和播放录制。
如果想要为 TV 输入服务提供录制功能,您必须指示系统您的应用支持录制,实现录制节目功能,处理和传达录制期间发生的所有错误,并管理录制的会话。
注:Live Channels 应用尚不提供可让用户创建或访问录制的方式。 在变更 Live Channels 应用之前,可能无法充分测试您的 TV 输入服务的录制体验。
为了通知系统您的 TV 输入服务支持录制,请将您的服务元数据 XML 文件中的 android:canRecord
属性设置为 true
:
<tv-input xmlns:android="http://schemas.android.com/apk/res/android" android:canRecord="true" android:setupActivity="com.example.sampletvinput.SampleTvInputSetupActivity" />
如需了解有关服务元数据文件的详细信息,请参阅在清单中声明您的 TV 输入。
或者,您可以使用以下步骤在您的代码中表明录制支持:
TvInputService.onCreate()
方法中,使用 TvInputInfo.Builder
类创建一个新的 TvInputInfo
对象。TvInputInfo
对象时,在调用 build()
之前先调用 setCanRecord(true)
,以表明您的服务支持录制。TvInputManager.updateTvInputInfo()
在系统中注册 TvInputInfo
对象。
TV 输入服务注册其支持录制功能后,系统会在需要访问应用的录制实现时调用 TvInputService.onCreateRecordingSession()
。 实现您自己的TvInputService.RecordingSession
子类并在触发 onCreateRecordingSession()
回调后返回它。 此子类负责切换到正确的频道数据,录制请求的数据,以及向系统传达录制状态和错误。
系统调用在频道 URI 中传递的 RecordingSession.onTune()
时,将调到该 URI 指定的频道。 通过调用 notifyTuned()
通知系统应用已调到所需的频道,或者,如果应用无法调到正确的频道,请调用 notifyError()
。
系统接下来调用 RecordingSession.onStartRecording()
回调。您的应用必须立即开始录制。系统调用此回调时,它可能会提供一个 URI,其中包含有关将录制的节目的信息。 完成录制后,您需要将此数据复制到 RecordedPrograms
数据表。
最后,系统调用 RecordingSession.onStopRecording()
。此时,您的应用必须立即停止录制。 您还需要在 RecordedPrograms
表中创建一个条目。 此条目应在 RecordedPrograms.COLUMN_RECORDING_DATA_URI
列中包含录制的会话数据 URI,以及在初始调用 onStartRecording()
时系统提供的任何节目信息。
如需了解有关如何访问 RecordedPrograms
表的更多详情,请参阅管理录制的会话。
如果录制期间发生错误,使录制的数据无法使用,则通过调用 RecordingSession.notifyError()
通知系统。同样,您可以在创建录制会话后调用notifyError()
,以通知系统您的应用不再录制会话。
如果录制期间发生错误,但您想提供可使用的部分录制供用户播放,则调用 RecordingSession.notifyRecordingStopped()
以使系统可以使用部分会话。
系统在 TvContract.RecordedPrograms
内容提供程序表中维护来自所有支持录制的频道应用的所有已录制会话的信息。 此信息可通过RecordedPrograms.Uri
内容 URI 访问。使用内容提供程序 API 读取、添加和删除此表中的条目。
如需了解有关使用内容提供程序数据的详细信息,请参阅内容提供程序基本知识。
TV 设备的存储可能有限,因此请运用您的最佳判断来分配存储,以保存录制的会话。 如果没有足够的空间存储录制的会话,请使用RecordingCallback.onError(RECORDING_ERROR_INSUFFICIENT_SPACE)
。
当用户发起录制时,您应尽快开始录制数据。 为便于执行此操作,请在系统调用 onCreateRecordingSession()
回调时完成前期的所有耗时任务,如访问和分配存储空间。 这样做让您能够在触发 onStartRecording()
回调时立即开始录制。
5.密匙 Key Attestation
密钥认证会给你更多的信心,你在使用你的应用程序 的密钥存储在设备的硬件支持的密钥库。下面的部分 描述如何验证性能的硬件支持的密钥和如何 解释认证证书的扩展数据模式。
在密钥认证,你指定一个密钥对的别名。在返回的认证 工具,提供了一个证书链,您可以使用它来验证 ,密钥对的性质。
在这个链的根证书签名使用的认证密钥, 该设备制造商注入设备的硬件支持 密钥存储在。
笔记在设备与Android和谷歌播放 服务船,根证书是由谷歌发行。你应该确认 在谷歌的根证书列表出现这个根证书。
实施重点认证,完成以下步骤:
密钥库
对象的getcertificatechain()
得到一个参考的X.509证书与密钥相关的
硬件支持外链的方法。通过检查每个证书的有效性CRL
对象的isrevoked()
方法
警告:虽然你可以在你的应用程序 直接完成这个过程,它的安全检查证书吊销列表 单独的服务器上,你的信任。
创建一个认证
对象,通过在 证书链作为参数的第一个元素:
/“证书”包含一个特定的证书关联的密钥链 / /对在设备的硬件支持的密钥库。 attestationcert X509Certificate= (X509Certificate)证书【零] 认证hardwarekeyattestation= 新 认证(attestationcert)
认证对象提取扩展数据在这个证书 将这些信息存储在一个更方便的格式。更多的细节 扩展的数据模式,看证书扩展数据模式。
在使用访问器方法认证
类 从证书检索扩展数据。这些方法使用相同的名称和结构层次 在证书扩展数据 图式。
例如,查看设备的TEE验证启动键,使用以下方法 序列:
/“hardwarekeyattestation”包含了认证的第一要素 / /证书链。 authorizationlistteeauthlist=hardwarekeyattestation。getteeenforced() rootoftrustteerootoftrust=teeauthlist。getrootoftrust() 字节[ ]teeverifiedbootkey=teerootoftrust。getverifiedbootkey()
从扩展数据比较认证
与 设定的值,您期望的硬件支持的密钥包含对象。
警告:虽然你可以在你的应用程序 直接完成这个过程,它的安全检查在一个单独的服务器,你信任证书的扩展数据 。
密钥认证验证扩展数据显示在第一 证书在设备的硬件支持的密钥库内的链。的 证书存储的信息根据ASN。1模式:
KeyDescription ::= SEQUENCE { attestationVersion INTEGER, attestationSecurityLevel SecurityLevel, keymasterVersion INTEGER, keymasterSecurityLevel SecurityLevel, attestationChallenge OCTET_STRING, 保留octet_string, softwareEnforced AuthorizationList, teeEnforced AuthorizationList, } SecurityLevel ::= ENUMERATED { Software (0), TrustedEnvironment (1), } AuthorizationList ::= SEQUENCE { purpose [1] EXPLICIT SET OF INTEGER OPTIONAL, algorithm [2] EXPLICIT INTEGER OPTIONAL, keySize [3] EXPLICIT INTEGER OPTIONAL, digest [5] EXPLICIT SET OF INTEGER OPTIONAL, padding [6] EXPLICIT SET OF INTEGER OPTIONAL, ecCurve [10] EXPLICIT INTEGER OPTIONAL, rsaPublicExponent [200] EXPLICIT INTEGER OPTIONAL, activeDateTime [400] EXPLICIT INTEGER OPTIONAL, originationExpireDateTime [401] EXPLICIT INTEGER OPTIONAL, usageExpireDateTime [402] EXPLICIT INTEGER OPTIONAL, noAuthRequired [503] EXPLICIT NULL OPTIONAL, userAuthType [504] EXPLICIT INTEGER OPTIONAL, authTimeout [505] EXPLICIT INTEGER OPTIONAL, allowWhileOnBody [506] EXPLICIT NULL OPTIONAL, allApplications [600] EXPLICIT NULL OPTIONAL, applicationId [601] EXPLICIT OCTET_STRING OPTIONAL, creationDateTime [701] EXPLICIT INTEGER OPTIONAL, origin [702] EXPLICIT INTEGER OPTIONAL, rollbackResistant [703] EXPLICIT NULL OPTIONAL, rootOfTrust [704] EXPLICIT RootOfTrust OPTIONAL, osVersion [705] EXPLICIT INTEGER OPTIONAL, osPatchLevel [706] EXPLICIT INTEGER OPTIONAL, attestationChallenge [708] EXPLICIT INTEGER OPTIONAL, attestationApplicationId [709] EXPLICIT OCTET_STRING OPTIONAL, } RootOfTrust ::= SEQUENCE { verifiedBootKey OCTET_STRING, deviceLocked BOOLEAN, verifiedBootState VerifiedBootState, } VerifiedBootState ::= ENUMERATED { Verified (0), SelfSigned (1), Unverified (2), Failed (3), }
下面的列表给出了各元素在图式:
这个序列的值提供了密钥对被 通过密钥认证验证的一般信息和提供容易获得额外的 细节。
attestationversion
attestationsecurity
这个安全 水平该认证。
笔记虽然它可能证明是 密钥存储在Android系统,如果attestationsecurity
值设置为软件你 不能信任这些证明如果Android系统成为损害。
keymasterversion
keymastersecurity
attestationchallenge
保留
softwareenforced
teeenforced
这个数据结构在多大程度上反映了软件的功能,如 密钥对,是基于它的位置在保护装置。
因为数据结构是一个枚举,它具有完全相同的一个 以下值:
这个数据结构包含密钥对的性质本身,在大师的硬件抽象层(HAL)的定义 。你比较这些值 到设备的当前状态或一组预期值进行验证,使用你的应用程序的一 密钥仍然有效。
每个域名对应一个类似命名的大师标签。例如, 密钥大小
在授权列表字段对应的km_tag_key_size
大师的标签。
在下面的列表中的每个字段是可选的:
目的
km_tag_purpose
大师的标签,它使用1个标签ID值。算法
对应于km_tag_algorithm
大师的标签,它使用的
2标签的ID值。
当一个authorizationlist
对象是关键 认证有关,该值始终是km_algorithm_rsa
或_公里_ EC算法
。
密钥大小
km_tag_key_size
大师的标签,它使用3个标签ID值。消化
一天_公里_文摘
大师的标签,它使用5个标签ID值。衬垫
km_tag_padding
大师的标签,它使用6个标签ID值。eccurve
对应于_公里_ EC标记_曲线
大师的标签,它使用一个10 标签ID值。
用于生成椭圆曲线的参数集(EC)的密钥对, 采用ECDSA签名与验证,在Android系统 。
rsapublicexponent
_ _公里_ RSA公共_指数标签
大师的标签,它使用一个标签ID
值200。activedatetime
_ Active DateTime _公里_标签
大师的标签,它使用一个标签ID值
400。originationexpiredatetime
一天_公里_起源_
datetime _ expire
大师的标签,它使用一个 标签ID值为401。usageexpiredatetime
km_tag_usage_expire_datetime
大师的标签,它使用一个标签ID
值402。noauthrequired
对应于公里_标签_没有_
auth _ required
大师的标签,它使用一个标签ID 值503。
当一个authorizationlist
对象是关键 认证有关,该值始终是真实的。
userauthtype
_标签使用_ auth公里_ _类型
大师的标签,它使用一个标签ID值
504。authtimeout
公里_标签_ auth _暂停。
大师的标签,它使用的
505标签的ID值。allowwhileonbody
对应于km_tag_allow_while_on_body
大师的标签, 使用价值的标签ID。
允许使用的身份验证超时时间,如果 用户还穿着他们身上的装置后的关键。注意安全 身体上的传感器确定设备是否被佩戴在用户的 体。
当一个authorizationlist
对象是关键 认证有关,该值始终是真实的。
所有应用
对应于_标签应用全_ _公里
大师的标签, 使用价值的标签ID。
指示是否在设备上的所有应用程序都可以访问密钥对。
当一个authorizationlist
对象是关键 认证有关,该值始终是真实的。
applicationid
km_tag_application_id
大师的标签,它使用一个标签ID值
601。creationdatetime
一天_公里_ _创作的DateTime
大师的标签,它使用一个标签ID
值701。起源
对应于km_tag_origin
大师的标签,它使用702个标签ID值。
当一个authorizationlist
对象是关键 认证有关,这个值通常设置为km_origin_generated
。如果认证使用大师 版本0.2或0.3,然而,起源可设置为km_origin_unknown
相反。
rollbackresistant
km_tag_rollback_resistant
大师的标签,它使用一个标签ID
值703。rootoftrust
对应于km_tag_root_of_trust
大师的标签,它使用一个标签ID值
704。
更多详情,请参见描述rootoftrust
数据结构。
osversion
对应于我们把_公里_ _版本
大师的标签,这 使用705标签ID值。
与 大师相关的Android操作系统的版本,指定为一六位整数。例如,版本6.0.1 表示为060001。
只有大师1或更高版本包含此值在 授权清单。
ospatchlevel
对应于km_tag_patchlevel
大师的标签,这 使用706标签ID值。
与安全补丁,在大师用 相关的年份和月份,指定为一六位整数。例如,六月的 2016补丁是表示为201606。
只有大师1或更高版本包含此值在 授权清单。
attestationchallenge
对应于km_tag_attestation_challenge
大师 标签,它使用一个708标签的ID值。
那是在 大师定义的密钥相关的挑战字符串。
attestationapplicationid
对应于km_tag_attestation_application_id
大师的标签,它使用709个标签ID值。
那个签名密钥对 是在大师认证证书的唯一ID。
这个值的集合定义了设备的状态信息。
需要的是下面列表中的每个字段:
verifiedbootkey
一个安全的关键,验证了系统的图像哈希。建议 你使用SHA-256算法对这个散列。
devicelocked
verifiedbootstate
osversion
patchmonthyear
这个数据结构提供了设备当前的启动状态,这 代表提供给用户和应用程序的 装置启动完后保护水平。有关此功能的更多信息,参见开机状态在验证启动文件部分。
这是数据结构中的枚举,因此需要准确的 以下值之一:
表示一个完整的信任链,包括Bootloader、引导 分区,所有分区和验证。
当设备在启动状态下,其verifiedbootkey
是 设备的嵌入式证书的哈希,该设备制造商 添加到设备的ROM在工厂。
表示设备嵌入式证书验证了装置的 引导分区,签名是有效的。
当设备在启动状态下,其verifiedbootkey
是的 用户安装证书的哈希,这标志一个引导分区 ,用户增加了在原来的地方的装置, 制造商提供引导。
表明该装置已验证失败。认证 证书不应使用该值为verifiedbootstate
。
6.网络安全配置
Android N 包含一个网络安全配置特性,让应用可以在一个安全的声明性配置文件中自定义其网络安全设置,而无需修改应用代码。 可以针对特定域和特定应用配置这些设置。 该特性的主要功能如下所示:
网络安全配置特性使用一个 XML 文件,您可以在该文件中指定应用的设置。 您必须在应用的清单中包含一个条目来指向该文件。 以下代码摘自一份清单,演示了如何创建此条目:
<?xml version="1.0" encoding="utf-8"?> <manifest ... > <application ... > <meta-data android:name="android.security.net.config" android:resource="@xml/network_security_config" /> ... </application> </manifest>
应用可能需要信任自定义的 CA 集,而不是平台默认值。 出现此情况的最常见原因包括:
默认情况下,来自所有应用的安全(例如 TLS、HTTPS)连接均信任预装的系统 CA,而面向 API 级别 23 (Android M) 及更低级别的应用默认情况下还会信任用户添加的 CA 存储。 应用可以使用 base-config
(针对应用范围的定制)或 domain-config
(针对每个域的定制)自定义自己的连接。
假设您要连接到使用自签署 SSL 证书的主机,或者连接到其 SSL 证书是由您信任的非公共 CA(如公司内部 CA)签发的主机。
res/xml/network_security_config.xml
:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config> <domain includeSubdomains="true">example.com</domain> <trust-anchors> <certificates src="@raw/my_ca"/> </trust-anchors> </domain-config> </network-security-config>
以 PEM 或 DER 格式将自签署或非公共 CA 证书添加到 res/raw/my_ca
。
如果应用不想信任系统信任的所有 CA,则可以自行指定,缩减要信任的 CA 集。 这样可防止应用信任任何其他 CA 签发的欺诈性证书。
限制信任的 CA 集的配置与针对特定域信任自定义 CA 相似,不同的是,前者要在资源中提供多个 CA。
res/xml/network_security_config.xml
:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config> <domain includeSubdomains="true">secure.example.com</domain> <domain includeSubdomains="true">cdn.example.com</domain> <trust-anchors> <certificates src="@raw/trusted_roots"/> </trust-anchors> </domain-config> </network-security-config>
以 PEM 或 DER 格式将信任的 CA 添加到 res/raw/trusted_roots
。 请注意,如果使用 PEM 格式,文件必须仅包含 PEM 数据,且没有额外的文本。 您还可以提供多个 <certificates>
元素,而不是只能提供一个元素。
应用可能需要信任系统不信任的附加 CA,出现此情况的原因可能是系统还未包含此 CA,或 CA 不符合添加到 Android 系统中的要求。 应用可以通过为一个配置指定多个证书源来实现此目的。
res/xml/network_security_config.xml
:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config> <trust-anchors> <certificates src="@raw/extracas"/> <certificates src="system"/> </trust-anchors> </base-config> </network-security-config>
调试通过 HTTPS 连接的应用时,您可能需要连接到没有用于生产服务器的 SSL 证书的本地开发服务器。 为了支持此操作,而又不对应用的代码进行任何修改,您可以通过使用 debug-overrides
指定仅在 android:debuggable 为 true
时才信任的仅调试
CA。 通常,IDE 和构建工具会自动为非发布版本设置此标志。
这比一般的条件代码更安全,因为出于安全考虑,应用存储不接受被标记为可调试的应用。
res/xml/network_security_config.xml
:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <debug-overrides> <trust-anchors> <certificates src="@raw/debug_cas"/> </trust-anchors> </debug-overrides> </network-security-config>
旨在连接到仅使用安全连接的目标的应用可以选择不再对这些目标提供 cleartext(使用解密的 HTTP 协议而非 HTTPS)支持。 此选项有助于防止应用因外部源(如后端服务器)提供的 URL 发生变化而意外回归。 请参阅 NetworkSecurityPolicy.isCleartextTrafficPermitted()
了解更多详情。
例如,应用可能需要确保所有与 secure.example.com
的连接始终是通过 HTTPS 完成,以防止来自恶意网络的敏感流量。
res/xml/network_security_config.xml
:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config usesCleartextTraffic="false"> <domain includeSubdomains="true">secure.example.com</domain> </domain-config> </network-security-config>
一般情况下,应用信任所有预装 CA。如果有预装 CA 要签发欺诈性证书,则应用将面临被中间人攻击 (MiTM) 的风险。 有些应用通过限制信任的 CA 集或通过证书固定来选择限制其接受的证书集。
通过按公钥的哈希值(X.509 证书的 SubjectPublicKeyInfo)提供证书集完成证书固定。 然后,证书链仅在至少包含一个已固定的公钥时才有效。
请注意,使用证书固定时,您应始终包含一个备份密钥,这样,当您需要强制切换到新密钥时,或更改 CA 时(固定到某个 CA 证书或该 CA 的中间证书时),您应用的连接性不会受到影响。 否则,您必须推送应用的更新以恢复连接性。
此外,可以设置固定到期时间,在该时间之后不执行证书固定。 这有助于防止尚未更新的应用出现连接问题。 不过,设置固定到期时间可能会绕过证书固定。
res/xml/network_security_config.xml
:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config> <domain includeSubdomains="true">example.com</domain> <pin-set expiration="2018-01-01"> <pin digest="SHA-256">7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin> <!-- backup pin --> <pin digest="SHA-256">fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=</pin> </pin-set> </domain-config> </network-security-config>
继承未在特定配置中设置的值。此行为允许进行更复杂的配置,同时保证配置文件可读。
如果未在特定条目中设置值,则使用来自下一个更通用的条目中的值。 未在 domain-config
中设置的值从父级 domain-config
(如果已嵌套)或从 base-config
(如果未嵌套)中获取。 未在 base-config
中设置的值使用平台默认值。
例如,考虑所有与 example.com
的子域的连接必须使用自定义 CA 集。此外,允许使用这些域的 cleartext traffic,连接到 secure.example.com
时除外。通过在 example.com
的配置中嵌套 secure.example.com
的配置,不需要重复 trust-anchors
。
res/xml/network_security_config.xml
:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config> <domain includeSubdomains="true">example.com</domain> <trust-anchors> <certificates src="@raw/my_ca"/> </trust-anchors> <domain-config cleartextTrafficPermitted="false"> <domain includeSubdomains="true">secure.example.com</domain> </domain-config> </domain-config> </network-security-config>
网络安全配置特性使用 XML 文件格式。 文件的整体结构如以下代码示例所示:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config> <trust-anchors> <certificates src="..."/> ... </trust-anchors> </base-config> <domain-config> <domain>android.com</domain> ... <trust-anchors> <certificates src="..."/> ... </trust-anchors> <pin-set> <pin digest="...">...</pin> ... </pin-set> </domain-config> ... <debug-overrides> <trust-anchors> <certificates src="..."/> ... </trust-anchors> </debug-overrides> </network-security-config>
以下部分介绍语法和文件格式的其他详细信息。
<base-config>
<domain-config>
<debug-overrides>
<base-config usesCleartextTraffic=["true" | "false"]> ... </base-config>
<trust-anchors>
domain-config
涵盖范围内的所有连接所使用的默认配置。
未设置的任何值均使用平台默认值。面向上述 API 级别 24 及更高级别的应用的默认配置:
<base-config usesCleartextTraffic="true"> <trust-anchors> <certificates src="system" /> </trust-anchors> </base-config>面向 API 级别 23 及更低级别的应用的默认配置:
<base-config usesCleartextTraffic="true"> <trust-anchors> <certificates src="system" /> <certificates src="user" /> </trust-anchors> </base-config>
<domain-config usesCleartextTraffic=["true" | "false"]> ... </domain-config>
<domain>
<trust-anchors>
<pin-set>
<domain-config>
domain
元素的定义连接到特定目标的配置。
请注意,如果有多个 domain-config
元素涵盖某个目标,则使用匹配域规则最具体(最长)的配置。
<domain includeSubdomains=["true" | "false"]>example.com</domain>
includeSubdomains
"true"
,则此域规则与域及所有子域(包括子域的子域)匹配,否则,该规则仅适用于精确匹配项。<debug-overrides> ... </debug-overrides>
<trust-anchors>
"true"
时将应用的重写,IDE
和构建工具生成的非发布版本通常属于此情况。 将在 debug-overrides
中指定的信任锚添加到所有其他配置,并且当服务器的证书链使用其中一个仅调试信任锚时不执行证书固定。 如果 android:debuggable 为 "false"
,则完全忽略此部分。<trust-anchors> ... </trust-anchors>
<certificates>
<certificates src=["system" | "user" | "raw resource"] overridePins=["true" | "false"] />
trust-anchors
元素的 X.509 证书集。src
"system"
"user"
overridePins
指定来自此源的 CA 是否绕过证书固定。如果为 "true"
,则为穿过此源的其中一个 CA 的链颁发证书,并且不执行证书固定。 这对于调试 CA 或支持用户对应用的安全流量进行中间人攻击 (MiTM) 非常有用。
默认值为 "false"
,除非在 debug-overrides
元素中另外指定(在这种情况下,默认值为 "true"
)。
<pin-set expiration="date"> ... </pin-set>
<pin>
<pin>
。expiration
yyyy-MM-dd
格式的日期,在该日期及之后固定过期,因而禁用固定。 如果未设置该属性,则固定不会过期。
设置到期时间有助于防止未更新到其 PKP 集(例如,由于用户禁用应用更新)的应用出现连接问题。
<pin digest=["SHA-256"]>base64 encoded digest of X.509 SubjectPublicKeyInfo (SPKI)</pin>
digest
用于生成 PKP 的摘要算法。目前仅支持 "SHA-256"
。
7.ICU4J Android
ICU4J 是一个广泛使用的开源 Java 库集合,为软件应用提供 Unicode 和全球化支持。 Android N 在 android.icu
软件包下显示 Android 框架中的 ICU4J API 子集,供应用开发者使用。 这些 API 使用设备上具有的本地化数据。 因此,您可以通过不将 ICU4J 库编译到 APK 来减少 APK 占用空间;相反,您可以只在框架中调用它们。 (在此情况下,您可能想要提供多个版本的
APK,这样,运行比 Android N 低的 Android 版本的用户可以下载包含 ICU4J 库的应用版本。)
本文档开头提供了有关支持这些库所需的最低 Android API 级别的一些基本信息。 然后,介绍关于 Android 特定的 ICU4J 实现您需要了解的内容。 最后,介绍如何在 Android 框架中使用 ICU4J API。
Android N 通过 android.icu
软件包(而非 com.ibm.icu
)显示 ICU4J API 的子集。由于种种原因,Android 框架可能选择不显示 ICU4J API;例如,Android N 不显示一些已弃用的 API 或 ICU 团队尚未将其声明为“稳定”的 API。 由于 ICU 团队将来会弃用这些 API,因此,Android 也会将其标记为已弃用,但将继续包含它们。
表 1. Android N 中使用的 ICU 和 CLDR 版本。
Android API 级别 | ICU 版本 | CLDR 版本 |
---|---|---|
Android N | 56 | 28 |
以下是几点注意事项:
如果您已在应用中使用 ICU4J API,且 android.icu
API 符合您的要求,那么要迁移至框架 API,需要将 Java 导入从 com.ibm.icu
更改为 android.icu
。 然后,您可以从 APK 移除您自己的 ICU4J 文件的副本。
注:ICU4J 框架 API 使用 android.icu
命名空间,而不是 com.ibm.icu
。这是为了避免在包含自己的 com.ibm.icu
库的 APK 中出现命名空间冲突。
java
和 android
软件包中的某些类与在 ICU4J 中找到的一些类等效。 不过,ICU4J 通常为标准和语言提供更广泛的支持。
下面是一些入门示例:
类 | 替代项 |
---|---|
java.lang.Character |
android.icu.lang.UCharacter |
java.text.BreakIterator |
android.icu.text.BreakIterator |
java.text.DecimalFormat |
android.icu.text.DecimalFormat |
java.util.Calendar |
android.icu.util.Calendar |
android.text.BidiFormatter |
android.icu.text.Bidi |
android.text.format.DateFormat |
android.icu.text.DateFormat |
android.text.format.DateUtils |
android.icu.text.DateFormat android.icu.text.RelativeDateTimeFormatter |
ICU4J 按照 ICU 许可发布。如需了解详情,请参阅 ICU 用户指南。
8.Java 8 支持
Android N 支持 Java 8 语言功能,您可以在开发面向 Android N 的应用时使用这些功能。本页面介绍了 Android N Preview 中支持的新语言功能、如何正确设置项目以使用这些功能,以及您可能遇到的任何已知问题。
要开始使用这些功能,您需要下载并设置 Android Studio 2.1 和 Android N Preview SDK,包括所需的 Jack 工具链和更新的 Android Plugin for Gradle。 如果您尚未安装 Android N Preview SDK,请参阅 Develop for Android N 设置。
注:开发面向 Android N 平台的应用并不要求必须使用新的 Java 8 语言功能。 如果您不想使用 Java 8 语言功能编写代码,您可以将项目的源和目标兼容性值保留为 Java 7,但您仍必须使用 JDK 8 进行编译,以便针对 Android N 平台进行构建。
Android 目前仅支持部分 Java 8 语言功能。在开发面向 Android N Preview 的应用时,现已可使用以下功能:
注:在 Android 的较早版本中测试 Lambda 表达式和方法引用,前往您的 build.gradle
文件,将 compileSdkVersion
和 targetSdkVersion
设置为 23 或更低版本。 您仍需要启用
Jack 工具链以使用这些 Java 8 功能。
此外,现已可使用以下 Java 8 语言功能 API:
要使用新的 Java 8 语言功能,还需使用新的 Jack 工具链。新的 Android 工具链将 Java 源语言编译成 Android 可读取的
Dalvik 可执行文件字节码,且有其自己的 .jack
库格式,在一个工具中提供了大多数工具链功能:重新打包、压缩、模糊化以及 Dalvik 可执行文件分包。
以下是构建 Android Dalvik 可执行文件可用的两种工具链的对比:
.java
--> .class
) --> dx (.class
--> .dex
).java
--> .jack
--> .dex
)
如需为您的项目启用 Java 8 语言功能和 Jack,请在模块层级的 build.gradle
文件中输入以下内容:
android { ... defaultConfig { ... jackOptions { enabled true } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } }
Instant Run 目前不能用于 Jack,在使用新的工具链时将被禁用。
由于 Jack 在编译应用时不生成中间类文件,依赖这些文件的工具目前不能用于 Jack。例如以下工具:
如果您在使用 Jack 的过程中发现其他问题,请提交错误。
9.Android for Work 更新
Android for Work 现在支持使用 QR 码来配置企业负责的设备。 安装向导现在允许您通过扫描 QR 码来配置设备。
个人资料所有者可以要求用户为在工作资料中运行的应用指定安全性挑战。 系统会在用户尝试打开任何工作应用时显示安全性挑战。 如果用户成功完成安全性挑战,系统可解锁工作资料并将其解密(如果需要)。
如果个人资料所有者发送一项 ACTION_SET_NEW_PASSWORD
Intent,系统会提示用户设置一项安全性挑战。
个人资料所有者也可以发送一项 ACTION_SET_NEW_PARENT_PROFILE_PASSWORD
Intent 来提示用户设置设备锁定。
个人资料所有者可以选择为工作挑战设置不同于其他设备密码策略的密码策略。 例如,设备挑战响应的最小长度可以与其它密码要求的长度不同。 个人资料所有者使用常见的 DevicePolicyManager
方法来设置挑战策略,如 setPasswordQuality()
和 setPasswordMinimumLength()
。
个人资料所有者还能通过使用由新的DevicePolicyManager.getParentProfileInstance()
方法返回的 DevicePolicyManager
实例来设置设备锁定,
此外,个人资料所有者可以使用 DevicePolicyManager
类的新 setOrganizationColor()
和setOrganizationName()
方法来自定义工作挑战的凭据屏幕。
有关新方法和常量的详细信息,请参阅 N Preview SDK 参考 中的 DevicePolicyManager
参考页面。
设备所有者和个人资料所有者可以通过调用新 DevicePolicyManager.setPackagesSuspended()
方法来临时暂停软件包访问。 所有者可以用同样的方法来重新启用这些软件包。
在软件包被暂停期间,它不能启动 Activity ,到软件包的通知会被阻止,而概览屏幕中的应用条目会被隐藏。 暂停的软件包不会显示在概览屏幕中,并且它们不能显示对话(包括提醒和 Snackbar), 也不能播放音频或振动设备。
启动器应对暂停的应用应用一个独特的 UI,以指示应用目前不可用;例如它们可以将应用图标显示为灰色。 启动器可以通过调用新DevicePolicyManager.getPackageSuspended()
方法来确定应用是否被暂停。
在双个人资料设备上,用户可以打开或关闭工作模式。在工作模式关闭时,托管个人资料会被暂时关闭。 工作资料应用、后台同步和通知都会被停用,包括个人资料所有者应用。 在工作资料被停用时,系统会显示一个持久的状态图标,以提醒用户他们将无法启动工作应用。 系统启动器会指示工作应用和小工具都将无法访问。
设备所有者和个人资料所有者可以要求工作应用始终通过指定的 VPN 连接到网络。 如果所有者设置了此要求,设备会在启动时自动开始 VPN。
所有者可以通过调用新 DevicePolicyManager.setAlwaysOnVpnPackage()
方法来要求使用 VPN。 通过调用新DevicePolicyManager.GetAlwaysOnVpnPackage()
方法来确定所有者是否设置了 VPN 要求。
由于 VPN 服务无需应用交互即可由系统直接绑定,因此,VPN 客户端必须针对 Always on VPN 处理新的入口点。 像以前一样,您可以通过使用与操作android.net.VpnService
匹配的
Intent 过滤器查找活动的服务。
用户可以使用 Settings > More > VPN 屏幕来手动设置实现 VpnService
的 Always
on VPN 客户端。
个人资料所有者可以允许主用户对工作联系人进行本地搜索和目录查找。 例如,用户可以从他们的个人拨号器或联系人应用访问个人和工作目录联系人(如果他们的个人资料管理员允许)。
利用联系人提供程序的开发者可以使用企业联系人 API 从主用户访问工作资料目录条目(如果策略允许):
ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI
ContactsContract.Phone.ENTERPRISE_CONTENT_FILTER_URI
ContactsContract.Email.ENTERPRISE_CONTENT_FILTER_URI
ContactsContract.Callable.ENTERPRISE_CONTENT_FILTER_URI
ContactsContract.Directory.ENTERPRISE_CONTENT_URI
ContactsContract.Directory.isEntepriseDirectoryId()
个人资料所有者可以使用以下新方法来控制主用户的工作联系人可见性:
DevicePolicyManager.setCrossProfileContactsSearchDisabled()
DevicePolicyManager.getCrossProfileContactsSearchDisabled()
设备所有者可以远程重新启动设备。有些情况下,部署在公共场所的封装内设备会阻止访问电源按钮。 如果设备需要重新启动,管理员可以使用新DevicePolicyManager.reboot()
方法来进行此操作。
设备所有者可以使用新的 UserManager
用户限制 DISALLOW_DATA_ROAMING
来停用数据网络漫游。
设备所有者可以通过远程跟踪设备活动来识别可疑活动 ,包括应用启动、ADB Activity 和屏幕解锁。 进程记录不要求用户同意。 若要检索记录,设备所有者可以使用 DevicePolicyManager.setSecurityLoggingEnabled()
来启用设备记录。
API 更改包括:
android.app.admin.SecurityLog
和它的方法void DevicePolicyManager.setSecurityLoggingEnabled()
boolean DevicePolicyManager.isSecurityLoggingEnabled()
List<SecurityEvent> DevicePolicyManager.retrieveSecurityLogs()
List<SecurityEvent> DevicePolicyManager.retrievePreRebootSecurityLogs()
void DeviceAdminReceiver.onSecurityLogsAvailable()
设备所有者可以远程触发和检索包含设备状态转储文件的错误报告,这允许对已知事故或受损害的设备进行取证调查。 鉴于错误报告的详细性质,需要经过用户同意。
Android N 包括以下 API 添加来支持此功能。如需详细信息,请参阅 N Preview SDK 参考。
DevicePolicyManager.requestBugreport()
DeviceAdminReceiver.onBugreportFailed()
DeviceAdminReceiver.onBugreportShared()
DeviceAdminReceiver.onBugreportSharingDeclined()
DeviceAdminReceiver.BUGREPORT_FAILURE_FAILED_COMPLETING
DeviceAdminReceiver.BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE
个人资料所有者和设备所有者现在可以通过调用新方法 DevicePolicyManager.removeKeyPair()
来移除通过 installKeyPair()
安装的客户端证书。
如果个人资料所有者或设备所有者授予第三方应用管理证书的权限,应用便可授予自身访问其所安装证书的权限,无需所有者进行任何干预。
用于管理证书的现有 API 经过扩展,现包括:
DevicePolicyManager.installKeyPair()
影响用户体验或限制用户设置的策略是向用户完全公开的,个人资料所有者和设备所有者可以将策略归于他们公司的 IT 部门。 除了“Settings”中一贯的“Action not allowed”消息之外,IT 管理员可以通过以下新 DevicePolicyManager
方法在设备设置中设置组织特定的支持消息:
DevicePolicyManager.setShortSupportMessage()
DevicePolicyManager.setLongSupportMessage()
设备或个人资料所有者可以通过新 DevicePolicyManager.setApplicationRestrictionsManagingPackage()
方法启用另一项应用,以管理应用限制。 提名的应用可以通过调用 DevicePolicyManager.isCallerApplicationRestrictionsManagingPackage()
来检查是否已被授予此权限。
提名管理应用限制的应用可以为该用户或个人资料内的任何软件包调用 setApplicationRestrictions()
和 getApplicationRestrictions()
。
用户可以停用工作应用的位置权限,同时仍可继续在个人应用中访问位置信息。 Location Settings 中的一个单独的位置访问开关允许用户拒绝对工作资料内运行的应用的位置更新或最后位置查询。
顶层位置关闭开关停用对主个人资料和托管个人资料的位置访问权限。
应用可以用企业颜色和徽标来自定义个人资料所有者和设备所有者配置流程。
DevicePolicyManager.EXTRA_PROVISIONING_MAIN_COLOR
DevicePolicyManager.EXTRA_PROVISIONING_LOGO_URI
个人资料所有者和设备所有者可以为一项指定的 Wi-Fi 配置设置多个 CA 证书。 如果企业 Wi-Fi 网络针对有相同 SSID 的独立接入点设置了独立 CA,IT 管理员可以使用新 setCaCertificates()
方法将所有相关 CA 包括在 Wi-Fi 配置中。
添加的 API 有:
WifiEnterpriseConfig.setCaCertificates()
WifiEnterpriseConfig.getCaCertificates()
设备所有者可以提供将显示在锁屏上的所有者信息。 该信息的优先级高于用户锁屏消息(如果已设置)。 新 DevicePolicyManager
方法有:
setDeviceOwnerLockScreenInfo()
getDeviceOwnerLockScreenInfo()
个人资料所有者可以为调用后端(调用帐户)指定一项使用工作特定 ConnectionService
的工作拨号器应用。
工作拨号器会保持仅限工作的调用记录,并仅依赖于工作联系人。 无论拨号应用是什么,用户都将获得一致的调用内 UI 体验。 传入到工作调用帐户的工作调用会与传入到个人调用帐户的个人调用相区别。
拨号器应检查新标记 android.telecom.Call.PROPERTY_WORK_CALL
,以确定一项调用是否是工作调用。 如果一项调用是工作调用,拨号器应通过添加工作徽章等方式做如此指示。
新的用户限制 (DISALLOW_SET_WALLPAPER
) 可以阻止用户更改他们的壁纸。 设备所有者或个人资料所有者仍可以改变壁纸,但只能更改他们控制的用户或个人资料的壁纸。 例如,个人资料所有者不能更改父用户的壁纸,但主个人资料的个人资料所有者或设备所有者却可以。 想要更改壁纸的个人资料所有者或设备所有者应检查他们管理的用户或个人资料是否有壁纸 (isWallpaperSupported()
)
以及他们是否被允许更改这个壁纸(通过新方法WallpaperManager.isWallpaperSettingAllowed()
)。
新的用户限制 (DISALLOW_SET_USER_ICON
) 阻止用户更改其用户图标。 用户的设备所有者或个人资料所有者仍可以更改图标。 但是个人资料所有者只能更改其控制的个人资料的用户图标。
设备所有者或个人资料所有者可以使用新的 HardwarePropertiesManager
界面来检索有关设备运行状况的信息,如 CPU 或 GPU 温度和 CPU 使用率。 新的监测界面特别适合监测在远程位置运行的无人值守设备。
10.作用域目录访问
应用(如照片应用)通常只需要访问外部存储中的特定目录,例如 Pictures
目录。 现有的外部存储访问方法未经专门设计,无法轻松地为这些类型的应用提供目标目录访问。 例如:
READ_EXTERNAL_STORAGE
或 WRITE_EXTERNAL_STORAGE
将允许访问外部存储上的所有公共目录,这可能导致访问的内容超出应用需要的内容。Android N 提供简化的全新 API 以访问通用外部存储目录。
使用 StorageManager
类获取适当的 StorageVolume
实例。然后,通过调用该实例的 StorageVolume.createAccessIntent()
方法创建一个 Intent。使用此 Intent 访问外部存储目录。 若要获取所有可用卷的列表,包括可移动介质卷,请使用 StorageManager.getVolumesList()
。
如果您有关于特定文件的信息,使用 StorageManager.getStorageVolume(File)
来获得包含该文件的 StorageVolume
。 调用在 StorageVolume
上的createAccessIntent()
以访问文件的外部存储目录。
在二级卷(例如外部 SD 卡)上,当调用 StorageVolume.createAccessIntent()
以请求访问整个卷,而不是特定目录时,传入“null”。如果您向主要卷传入“null”,或者如果您传入无效的目录名,StorageVolume.createAccessIntent()
将返回“null”。
以下代码段展示如何在主要共享存储中打开Pictures
目录:
StorageManager sm = (StorageManager)getSystemService(Context.STORAGE_SERVICE); StorageVolume volume = sm.getPrimaryVolume(); Intent intent = volume.createAccessIntent(Environment.DIRECTORY_PICTURES); startActivityForResult(intent, request_code);
系统尝试授予对外部目录的访问权限,并使用一个简化的 UI 向用户确认访问权限(如果需要):
图 1. 一个请求访问 Pictures 目录的应用。
如果用户授予访问权限,则系统会调用 onActivityResult()
重写方法,且结果代码为 Activity.RESULT_OK
,Intent 数据包含 URI。使用提供的 URI 访问目录信息,与使用存储访问框架返回的
URI 类似。
如果用户不授予访问权限,则系统会调用 onActivityResult()
重写方法,且结果代码为 Activity.RESULT_CANCELED
,Intent 数据为 null。
注:获得特定外部目录的访问权限也会获得该目录中子目录的访问权限。
若要使用作用域目录访问来访问可移动介质上的目录,首先要添加一个用于侦听 MEDIA_MOUNTED
通知的 BroadcastReceiver
,例如:
<receiver android:name=".MediaMountedReceiver" android:enabled="true" android:exported="true" > <intent-filter> <action android:name="android.intent.action.MEDIA_MOUNTED" /> <data android:scheme="file" /> </intent-filter> </receiver>
当用户装载可移动介质时,如 SD 卡,系统将发送一则 MEDIA_MOUNTED
通知。此通知在 Intent
数据中提供一个 StorageVolume
对象,您可用它访问可移动介质上的目录。 以下示例访问可移动介质上的 Pictures
目录:
// BroadcastReceiver has already cached the MEDIA_MOUNTED // notification Intent in mediaMountedIntent StorageVolume volume = (StorageVolume) mediaMountedIntent.getParcelableExtra(StorageVolume.EXTRA_STORAGE_VOLUME); volume.createAccessIntent(Environment.DIRECTORY_PICTURES); startActivityForResult(intent, request_code);
请尽可能保留外部目录访问 URI,这样即不必重复要求用户授予访问权限。 在用户授予访问权限后,使用目录访问 URI 调用getContentResolver().takePersistableUriPermssion()
。 系统将保留此 URI,后续的访问请求将返回 RESULT_OK
,且不会向用户显示确认 UI。
如果用户拒绝授予外部目录访问权限,请勿立即再次请求访问权限。 一再不停地请求访问权限会导致非常差的用户体验。 如果用户拒绝了一项请求,而应用再次请求访问,UI 会显示一个 Don‘t ask again 复选框:
图 1. 应用第二次请求访问可移动介质。
如果用户选择 Don‘t ask again 并拒绝请求,您的应用向指定目录提出的所有未来请求都将被自动拒绝,并且将不会有请求 UI 呈现给用户。
标签:
原文地址:http://blog.csdn.net/wen_demo/article/details/51943340