Android 7.0 Nougat 提供新功能以提升性能、生产效率和安全性,主要新增了以下的新特性和优化:
Android N 增加了许多新的 notifications API,进行了重新的设计,引入了新的风格。
快速设置 "通常用于直接从通知栏显示关键设置和操作,非常简单。在 Android N 中,已扩展" 快速设置 "的范围,使其更加有用更方便。为额外的" 快速设置 "图块添加了更多空间,用户可以通过向左或向右滑动跨分页的显示区域访问它们。 还让用户可以控制显示哪些" 快速设置 " 图块以及显示的位置 — 用户可以通过拖放图块来添加或移动图块。
对于开发者,Android N 还添加了一个新的 API,从而可以定义自己的 "快速设置" 图块,使用户可以轻松访问应用中的关键控件和操作。
Android 运行组件的 JIT 编译器最实际的好处之一是应用安装和系统更新的速度。即使在 Android 6.0 中需要几分钟进行优化和安装的大型应用,现在只需几秒钟就可以完成安装。系统更新也变得更快,因为省去了优化步骤。
在 Android N 中,低电耗模式又前进了一步,随时随地可以省电。只要屏幕关闭了一段时间,且设备未插入电源,低电耗模式就会对应用使用熟悉的 CPU 和网络限制。这意味着用户即使将设备放入口袋里也可以省电。
Project Svelte 在持续改善,以最大程度减少生态系统中一系列 Android 设备中系统和应用使用的 RAM。在 Android N 中,Project Svelte 注重优化在后台中运行应用的方式。
后台处理是大多数应用的一个重要部分。处理得当,可实现非常棒的用户体验—即时、快速和情境感知。如果处理不得当,后台处理会毫无必要地消耗 RAM 和电池,同时影响其他应用的系统性能。
Android N 删除了三项隐式广播(CONNECTIVITY_ACTION、ACTION_NEW_PICTURE 和 ACTION_NEW_VIDEO)
,以帮助优化内存使用和电量消耗。此项变更很有必要,因为隐式广播会在后台频繁启动已注册侦听这些广播的应用,删除这些广播可以显著提升设备性能和用户体验。
移动设备会经历频繁的连接变更,例如在 Wi-Fi 和移动数据之间切换时。目前,可以通过在应用清单文件中注册一个接收器来侦听隐式 CONNECTIVITY_ACTION 广播,让应用能够监控这些变更。由于很多应用会注册接收此广播,因此单次网络切换即会导致所有应用被唤醒并同时处理此广播。同理,应用可以注册接收来自其他应用(例如相机)的隐式 ACTION_NEW_PICTURE 和 ACTION_NEW_VIDEO 广播。当用户使用相机应用拍摄照片时,这些应用即会被唤醒处理广播。
为减缓这些问题,Android N 应用了以下优化措施:
1、面向 Android N 开发的应用不会收到 CONNECTIVITY_ACTION 广播,即使它们已有清单条目来请求接受这些事件的通知。在前台运行的应用如果使用 BroadcastReceiver 请求接收通知,则仍可以在主线程中侦听 CONNECTIVITY_CHANGE。
2、 应用无法发送或接收 ACTION_NEW_PICTURE 和 ACTION_NEW_VIDEO 广播。此项优化会影响所有应用,而不仅仅是面向 Android N 的应用。
未来的 Android 版本还可能会弃用其他隐式广播以及未绑定的后台服务。有鉴于此,应避免依赖在清单文件中声明的接收器来侦听隐式广播或删除此依赖关系,以及避免或删除对后台服务的依赖关系。
Android 框架提供多种解决方案来降低这些隐式广播或后台服务的必要性。例如,JobScheduler API 提供了一个稳健可靠的机制来安排满足指定条件(例如连入不按流量计费的网络)时所执行的网络操作。甚至可以使用 JobScheduler 来响应内容提供程序所发生的变更。
在移动设备的整个生命周期,蜂窝数据计划的成本通常会超出设备本身的成本。对于许多用户而言,蜂窝数据是他们想要节省的昂贵资源。
Android N 推出了 Data Saver 模式,这是一项新的系统服务,有助于减少应用使用的蜂窝数据,无论是在漫游,账单周期即将结束,还是使用少量的预付费数据包。 Data Saver 让用户可以控制应用使用蜂窝数据的方式,同时让开发者打开 Data Saver 时可以提供更多有效的服务。
Android N 将一项新的 3D 渲染 API Vulkan? 集成到平台中。就像 OpenGL? ES 一样,Vulkan 是 3D 图形和渲染的一项开放标准,由 Khronos Group 维护。
Vulkan 是完全从零开始设计,以最小化驱动器中的 CPU 开销,并能让应用更直接地控制 GPU 操作。Vulkan 还允许多个线程同时执行工作,如命令缓冲区构建,以获得更好的并行化。
Vulkan 开发工具和库都已卷入 Android NDK。它们包括:
● 头
● 验证层(调试库)
● SPIR-V 着色程序编译器
● SPIR-V 运行时着色器编译库
● Vulkan 仅适用于已启用 Vulkan 硬件的设备上的应用,如 Nexus 5X、Nexus 6P 和 Nexus Player。
Android N 现在支持在平台中进行号码屏蔽,提供框架 API,让服务提供商可以维护屏蔽的号码列表。默认短信应用、默认手机应用和提供商应用可以对屏蔽的号码列表进行读取和写入操作,其他应用则无法访问此列表。
Android N 允许默认的手机应用过滤来电。手机应用执行此操作的方式是实现新的 CallScreeningService,该方法允许手机应用基于来电的 Call.Details 执行大量操作,例如:
● 拒绝来电
● 不允许来电到达通话记录
● 不向用户显示来电通知
Android N 现在允许用户在设置中选择多个区域设置,以更好地支持双语用例。应用可以使用新的 API 获取用户选择的区域设置,然后为多区域设置用户提供更成熟的用户体验,如以多个语言显示搜索结果,并且不会以用户了解的语言翻译网页。
除多区域设置支持外,Android N 还扩展了用户可用的语言范围。它针对常用语言提供超过 25 种的变体,如英语、西班牙语、法语和阿拉伯语。它还针对 100 多种新语言添加了部分支持。
应用可以通过调用 LocaleList.GetDefault() 获取用户设置的区域设置列表。 为支持扩展的区域设置数量,Android N 正在改变其解析资源的方式。
Android N 引入更多表情符号和表情符号相关功能,包括肤色表情符号和支持变量选择符。如果应用支持表情符号,请遵循以下准则,以便能充分利用这些表情符号相关功能优势。
ICU4J 是一个广泛使用的开源 Java 库集合,为软件应用提供 Unicode 和全球化支持。Android N 在 android.icu 软件包下显示 Android 框架中的 ICU4J API 子集,供应用开发者使用。迁移很简单,主要是需要从 com.java.icu 命名空间更改为 android.icu。如果已在应用中使用 ICU4J 捆绑包,切换到 Android 框架中提供的 android.icu API 可以大量节省 APK 大小。
Android N 添加了框架接口和对 OpenGL ES 3.2 的平台支持,包括:
● 来自 Android 扩展包 (AEP) 的所有扩展(EXT_texture_sRGB_decode 除外)。
● 针对 HDR 的浮点帧缓冲和延迟着色。
● Android N 允许用户按照他们的喜好修改表情符号呈现的肤色。键盘应用应为有多个肤色的表情符号提供可视化的指示,并应允许用户选择他们喜欢的肤色。若要确定哪些系统表情符号有肤色修改器,使用 hasGlyph(String) 方法。可以通过读取 Unicode 文档来确定哪些表情符号使用肤色。
● BaseVertex 绘图调用可实现更好的批处理和流媒体服务。
● 强大的缓冲区访问控制可减少 webGL 开销。
(面向 Android 的 Google VR SDK)
Android N 添加了新的 VR 模式的平台支持和优化,以使开发者能为用户打造高质量移动 VR 体验。新版针对开发者提供了大量性能增强特性,包括单一缓冲区渲染以及允许 VR 应用访问某个专属的 CPU 核心。在应用中,可以享受到专为 VR 设计的平滑头部跟踪和立体声通知功能。
(API 参考 android.accessibilityservice.GestureDescription)
Android N 现在针对新的设备设置直接在欢迎屏幕上提供 "Vision Settings"。这使用户可以更容易发现和配置他们设备上的无障碍功能,包括放大手势、字体大小、显示屏尺寸和 TalkBack。
使用硬件支持的密钥库,可更安全地在 Android 设备上创建、存储和使用加密密钥。它们可保护密钥免受 Linux 内核、潜在的 Android 漏洞的攻击,也可防止从已取得根权限的设备提取密钥。
为了让硬件支持的密钥库使用起来更简单和更安全,Android N 引入了密钥认证。应用和关闭的设备可使用密钥认证以坚决地确定 RSA 或 EC 密钥对是否受硬件支持、密钥对的属性如何,以及其使用和有效性有何限制。
应用和关闭的设备服务可以通过 X.509 认证证书(必须由有效的认证密钥签署)请求有关密钥对的信息。认证密钥是一个 ECDSA 签署密钥,其在出厂时被注入设备的硬件支持的密钥库。因此,有效的认证密钥签署的认证证书可确认硬件支持的密钥库是否存在,以及该密钥库中密钥对的详细信息。
为确保设备使用安全的官方 Android 出厂映像,密钥认证要求设备 bootloader 向可信执行环境 (TEE) 提供以下信息:
设备上安装的操作系统版本和补丁级别
● 验证的启动公钥和锁定状态。
● 除密钥认证外,Android N 还推出了指纹绑定密钥,在指纹注册时不会撤销。
在 Android 7.0 的适配中,遇到了些问题,主要是新特性上的一些变化,需要针对性的做适配。
随着 Android 版本越来越高,Android 对隐私的保护力度也越来越大。从 Android6.0 引入的动态权限控制 (Runtime Permissions) 到 Android7.0 的 "私有目录被限制访问","StrictMode API 政策"。这些更改在为用户带来更加安全的操作系统的同时也为开发者带来了一些新的任务。如何让你的 APP 能够适应这些改变而不是 cash,是摆在每一位 Android 开发者身上的责任。
随着 Android 版本越来越高,Android 对隐私的保护力度也越来越大。从 Android6.0 引入的动态权限控制 (Runtime Permissions) 到 Android7.0 的 "私有目录被限制访问","StrictMode API 政策"。这些更改在为用户带来更加安全的操作系统的同时也为开发者带来了一些新的任务。如何让你的 APP 能够适应这些改变而不是 cash,是摆在每一位 Android 开发者身上的责任。
● 私有文件的文件权限不在放权给所有的应用,使用 MODE_WORLD_READABLE 或 MODE_WORLD_WRITEABLE 进行的操作将触发 SecurityException。
● 给其他应用传递 file:// URI 类型的 Uri,可能会导致接受者无法访问该路径。 因此,在 Android7.0 中尝试传递 file:// URI 会触发 FileUriExposedException。
● DownloadManager 不再按文件名分享私人存储的文件。COLUMN_LOCAL_FILENAME 在 Android7.0 中被标记为 deprecated, 旧版应用在访问 COLUMN_LOCAL_FILENAME 时可能出现无法访问的路径。 面向 Android N 或更高版本的应用在尝试访问 COLUMN_LOCAL_FILENAME 时会触发 SecurityException。
在 Android7.0 系统上,Android 框架强制执行了 StrictMode API 政策禁止向你的应用外公开 file:// URI。 如果一项包含文件 file:// URI 类型 的 Intent 离开你的应用,应用失败,并出现 FileUriExposedException 异常,如调用系统相机拍照,或裁切照片。
调用系统相机拍照,裁切照片。
在 Android7.0 之前,如果你想调用系统相机拍照可以通过以下代码来进行:
- File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg");
- if (!file.getParentFile().exists())file.getParentFile().mkdirs();
- Uri imageUri = Uri.fromFile(file);
- Intent intent = new Intent();
- intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//设置Action为拍照
- intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//将拍取的照片保存到指定URI
- startActivityForResult(intent,1006);
在 Android7.0 上使用上述方式调用系统相拍照会抛出如下异常:
- android.os.FileUriExposedException: file:////storage/emulated/0/temp/1474956193735.jpg exposed beyond app through Intent.getData()
- at android.os.StrictMode.onFileUriExposed(StrictMode.java:1799)
- at android.net.Uri.checkFileUriExposed(Uri.java:2346)
- at android.content.Intent.prepareToLeaveProcess(Intent.java:8933)
- at android.content.Intent.prepareToLeaveProcess(Intent.java:8894)
- at android.app.Instrumentation.execStartActivity(Instrumentation.java:1517)
- at android.app.Activity.startActivityForResult(Activity.java:4223)
- ...
- at android.app.Activity.startActivityForResult(Activity.java:4182)
闪退截图如下:
这是由于 Android7.0 执行了 "StrictMode API 政策禁" 的原因,不过小伙伴们不用担心,上文讲到了可以用 FileProvider 来解决这一问题,
现在我们就来一步一步的解决这个问题。
使用 FileProvider
使用 FileProvider 的大致步骤如下:
第一步:在 manifest 清单文件中注册 provider
- <provider
- android:name="android.support.v4.content.FileProvider"
- android:authorities="com.jph.takephoto.fileprovider"
- android:grantUriPermissions="true"
- android:exported="false">
- <meta-data
- android:name="android.support.FILE_PROVIDER_PATHS"
- android:resource="@xml/file_paths" />
- </provider>
第二步:指定共享的目录
为了指定共享的目录我们需要在资源 (res) 目录下创建一个 xml 目录,然后创建一个名为 "file_paths"(名字可以随便起,只要和在 manifest 注册的 provider 所引用的 resource 保持一致即可)的资源文件,内容如下:
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <paths>
- <external-path path="" name="camera_photos" />
- </paths>
- </resources>
代表的根目录: Context.getFilesDir()
代表的根目录: Environment.getExternalStorageDirectory()
代表的根目录: getCacheDir()
第三步:使用 FileProvider
上述准备工作做完之后,现在我们就可以使用 FileProvider 了。
还是以调用系统相机拍照为例,我们需要将上述拍照代码修改为如下:
- File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg");
- if (!file.getParentFile().exists())file.getParentFile().mkdirs();
- Uri imageUri = FileProvider.getUriForFile(context, "com.jph.takephoto.fileprovider", file);//通过FileProvider创建一个content类型的Uri
- Intent intent = new Intent();
- intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //添加这一句表示对目标应用临时授权该Uri所代表的文件
- intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//设置Action为拍照
- intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//将拍取的照片保存到指定URI
- startActivityForResult(intent,1006);
上述代码中主要有两处改变:
1、将之前 Uri 的 scheme 类型为 file 的 Uri 改成了有 FileProvider 创建一个 content 类型的 Uri。
2、添加了 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 来对目标应用临时授权该 Uri 所代表的文件。
将 getUriForFile 方法获取的 Uri 打印出来如下:
- content: //com.jph.takephoto.fileprovider/camera_photos/temp/1474960080319.jpg。
其中 camera_photos 就是 file_paths.xml 中 paths 的 name。
因为上述指定的 path 为 path="",所以 content://com.jph.takephoto.fileprovider/camera_photos / 代表的真实路径就是根目录,即:/storage/emulated/0/。
content://com.jph.takephoto.fileprovider/camera_photos/temp/1474960080319.jpg 代表的真实路径是:/storage/emulated/0/temp/1474960080319.jpg。
裁切照片代码:
- File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg");
- if (!file.getParentFile().exists())file.getParentFile().mkdirs();
- Uri outputUri = Uri.fromFile(file);
- Uri imageUri=Uri.fromFile(new File("/storage/emulated/0/temp/1474960080319.jpg"));
- Intent intent = new Intent("com.android.camera.action.CROP");
- intent.setDataAndType(imageUri, "image/*");
- intent.putExtra("crop", "true");
- intent.putExtra("aspectX", 1);
- intent.putExtra("aspectY", 1);
- intent.putExtra("scale", true);
- intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);
- intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
- intent.putExtra("noFaceDetection", true); // no face detection
- startActivityForResult(intent,1008);
和拍照一样,上述代码在 Android7.0 上同样会引起 android.os.FileUriExposedException 异常,解决办法就是上文说说的使用 FileProvider。
然后,将上述代码改为如下即可:
- File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg");
- if (!file.getParentFile().exists())file.getParentFile().mkdirs();
- Uri outputUri = FileProvider.getUriForFile(context, "com.jph.takephoto.fileprovider",file);
- Uri imageUri=FileProvider.getUriForFile(context, "com.jph.takephoto.fileprovider", new File("/storage/emulated/0/temp/1474960080319.jpg");//通过FileProvider创建一个content类型的Uri
- Intent intent = new Intent("com.android.camera.action.CROP");
- intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- intent.setDataAndType(imageUri, "image/*");
- intent.putExtra("crop", "true");
- intent.putExtra("aspectX", 1);
- intent.putExtra("aspectY", 1);
- intent.putExtra("scale", true);
- intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);
- intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
- intent.putExtra("noFaceDetection", true); // no face detection
- startActivityForResult(intent,1008);
另外,裁切照片推荐大家使用开源工具库 TakePhoto,
TakePhoto 是一款在 Android 设备上获取照片(拍照或从相册、文件中选择)、裁剪图片、压缩图片的开源工具库。
来源: http://www.bubuko.com/infodetail-1965628.html