一、Android7.0
1、应用间共享文件
7.0中为了提高私有文件的安全性,面向7.0及更高版本的应用私有目录将被限制访问
问题:SharedPreferences闪退:私有文件的文件权限不在放权给所有的应用,在manifest里使用MODE_WORLD_READABLE或MODE_WORL_WRITEABLE进行的操作将触发SecurityException。应修改成MODE_PRIVATE
给其他应用传递file://URI这种URI类型,可能导致接收者无法访问该路径。因此,在7.0中尝试传递file://URI会触发FileUriExposedException。
申明Provider
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="{包名}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
创建resource->xml->file
在res创建xml文件,再xml文件下创建filepaths
内部存储、外部存储、公共存储目录
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
//代表Context.getFilesDir()所指向的目录
<files-path
name=""
path=""></files-path>
//代表Context.getCacheDir()所指向的目录
<cache-path
name=""
path=""></cache-path>
//代表Context.getExternalCacheDir()所指向的目录
<external-cache-path
name=""
path=""></external-cache-path>
//代表Context.getExternalFilesDir()所指向的目录
<external-files-path
name=""
path=""></external-files-path>
//代表Environment.getExternalStorageDirectory()所指向的目录
<external-path
name=""
path=""></external-path>
</paths>
代码
File imgFile = new File("照片存放目录");
Uri uri;
//根据当前系统版本决定使用哪个api,N是Android7.0的代号
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//第一个参数是上下文,第二个参数来自清单文件,必须完全一样,第三个参数为上面创建的照片file
uri = FileProvider.getUriForFile(this, "{包名}.fileprovider", imgFile);
} else {
//Android7.0还用原先的api
uri = Uri.fromFile(imgFile);
}
2、广播
Android Nougat (7.0) 中,Google 移除了三项隐式广播(Implict Broadcast)监听网络状态(CONNECTIVITY_ACTION), 监听手机拍照(ACTION_NEW_PICTURE),监听录像(ACTION_NEW_VIDEO),而在 Android O 中除了这里列出的,其余所有的隐式广播都被移除了。请充分利用 Android 7.0 以迁移到JobScheduler和相关的API(官方:https://github.com/googlesamples/android-JobScheduler)
3、APK signature scheme v2
1.只勾选V1签名就是传统方案签署,但是在 Android 7.0 上不会使用V2安全的验证方式。
2.只勾选V2签名7.0以下会显示未安装,Android 7.0 上则会使用了V2安全的验证方式。
3.同时勾选V1和V2则所有版本都没问题。
4、Popupwindow位置不正确
处理PopupWindow在Android 7.x中兼容性问题的示例
PopupWindow 中的 showAsDropDown(View anchor) 用于在指定锚点View下方显示 PopupWindow,在Android 7.0 (api<=23) 以前是没什么问题的,但是在Android 7.x系统上,会在某些情况下出现兼容问题:
如果指定 PopupWindow 的高度为 MATCH_PARENT,调用 showAsDropDown(View anchor) 时,在 7.0 之前,会在锚点 anchor 下边缘到屏幕底部之间显示 PopupWindow;而在 7.0、7.1 系统上的 PopupWindow 会占据整个屏幕(除状态栏之外)。
如果指定 PopupWindow 的高度为 WRAP_CONTENT, 调用 showAsDropDown(View anchor) 时,便不会出现兼容性的问题。
如果指定 PopupWindow 的高度为自定义的值height,调用 showAsDropDown(View anchor)时, 如果 height > 锚点 anchor 下边缘与屏幕底部的距离, 则还是会出现7.0、7.1上显示异常的问题;否则,不会出现该问题。可以看出,情况1和2是情况3的特例。
// Android 7.x中,PopupWindow高度为match_parent时,会出现兼容性问题,需要处理兼容性
if (Build.VERSION.SDK_INT >= 24) {
// 记录anchor在屏幕中的位置
int[] location = new int[2];
anchor.getLocationOnScreen(location);
int offsetY = location[1] + anchor.getHeight();
// Android 7.1中,PopupWindow高度为 match_parent 时,会占据整个屏幕
if (Build.VERSION.SDK_INT == 25) {
// 故而需要在 Android 7.1上再做特殊处理
// 获取屏幕高度
int screenHeight = ScreenUtils.getScreenHeight(context);
// 重新设置 PopupWindow 的高度
popupWindow.setHeight(screenHeight - offsetY);
}
popupWindow.showAtLocation(anchor, Gravity.NO_GRAVITY, 0, offsetY);
} else {
popupWindow.showAsDropDown(anchor);
}
二、Android6.0
1、运行时权限
需注意表中每个危险权限都属于一个权限组,我们在运行时权限处理时使用权限名,用户一旦同意授权了,那么该权限组中其他权限也将同时被授权
申请权限
checkSelfPermission、requestPermissions
//例子:
if (checkSelfPermission(Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
Manifest.permission.READ_PHONE_STATE);
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.READ_PHONE_STATE,
Manifest.permission.CAMERA},RESULT_PHONE_STATE);
}
EasyPermissions框架
dependencies {
// For developers using AndroidX in their applications
implementation 'pub.devrel:easypermissions:3.0.0'
// For developers using the Android Support Library
implementation 'pub.devrel:easypermissions:2.0.1'
}
| 权限组名 | 权限 | 权限名 |
|---|---|---|
| android.permission-group.CAMERA(相机) | android.permission.CAMERA |
允许程序访问摄像头进行拍照 |
| android.permission-group.CONTACTS(联系人) | android.permission.READ_CONTACTS |
允许程序访问联系人通讯录信息 |
android.permission.WRITE_CONTACTS |
写入联系人,但不可读取 | |
| android.permission.GET_ACCOUNTS | 允许程序访问账户Gmail列表 | |
| android.permission-group.PHONE(电话) | android.permission.READ_PHONE_STATE |
允许程序访问电话状态 |
| android.permission.CALL_PHONE | 允许程序从非系统拨号器里拨打电话 | |
android.permission.READ_CALL_LOG |
读取通话记录 | |
| android.permission.WRITE_CALL_LOG | 允许程序写入(但是不能读)用户的联系人数据 | |
| com.android.voicemail.permission.ADD_VOICEMAIL | 允许一个应用程序添加语音邮件系统 | |
| android.permission.USE_SIP | 允许程序使用SIP视频服务 | |
| android.permission.PROCESS_OUTGOING_CALLS | 允许程序监视,修改或放弃播出电话 | |
| GroupPermissionsandroid.permission-group.CALENDAR(日历) | android.permission.READ_CALENDAR | 允许程序读取用户的日程信息 |
| android.permission.WRITE_CALENDAR | 允许程序写入日程,但不可读取 | |
| android.permission-group.LOCATION(定位) | android.permission.ACCESS_FINE_LOCATION |
允许程序通过GPS芯片接收卫星的定位信息 |
android.permission.ACCESS_COARSE_LOCATION |
允许程序通过WiFi或移动基站的方式获取用户错略的经纬度信息 | |
| android.permission-group.STORAGE(存储) | android.permission.READ_EXTERNAL_STORAGE |
程序可以读取设备外部存储空间(内置SDcard和外置SDCard)的文件,如果您的App已经添加 |
android.permission.WRITE_EXTERNAL_STORAGE |
允许程序写入外部存储,如SD卡上写文件 | |
| android.permission-group.SENSORS(传感器) | android.permission.BODY_SENSORS | 传感器 |
| android.permission-group.SMS(短信) | android.permission.SEND_SMS | 允许程序发送短信 |
| android.permission.RECEIVE_SMS | 允许程序接收短信 | |
| android.permission.READ_SMS | 允许程序读取短信内容 | |
| android.permission.RECEIVE_WAP_PUSH | 允许程序接收WAP PUSH信息 | |
| android.permission.RECEIVE_MMS | 允许程序接收彩信 | |
| android.permission.READ_CELL_BROADCASTS | ||
| android.permission-group.MICROPHONE(麦克风) | android.permission.RECORD_AUDIO | 麦克风 |
2、取消支持 Apache HTTP 客户端
Android 6.0 版移除了对 Apache HTTP 客户端的支持。如果您的应用使用该客户端,并以 Android 2.3(API 级别 9)或更高版本为目标平台,请改用 HttpURLConnection 类。此 API 效率更高,因为它可以通过透明压缩和响应缓存减少网络使用,并可最大限度降低耗电量。要继续使用 Apache HTTP API,您必须先在 build.gradle 文件中声明以下编译时依赖项:
android {
useLibrary 'org.apache.http.legacy'
}