新 Android Q(api29)适配及注意事项(重点)

原创
2019/04/24 10:35
阅读数 3.3K

一 设备的IMEI号,禁止获取

	从 Android Q 开始,应用必须具有 READ_PRIVILEGED_PHONE_STATE 签名权限才能访问设备的不可重置标识符(包含 IMEI 和序列号)。
禁止获取 IMEI 和设备序列号:新增了特权(普通 App 申请不了的那种)READ_PRIVILEGED_PHONE_STATE去保护设备的唯一标识符。
设备唯一标识符需要特别注意,原来的READ_PHONE_STATE权限已经不能获得IMEI和序列号,如果想在Q设备上通过使用以下代码获取设备的ID
((TelephonyManager)getActivity().getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId()
则执行以上代码会返回空值(targetSDK<=P)或者报错(targetSDK==Q)。且官方所说的READ_PRIVILEGED_PHONE_STATE权限只提供给系统app,所以这个方法行不通了。
一种获取id的方法:
public static String getUUID() {
  String serial = null;
  String m_szDevIDShort = "35" +
    Build.BOARD.length() % 10 + Build.BRAND.length() % 10 +
    Build.CPU_ABI.length() % 10 + Build.DEVICE.length() % 10 +
    Build.DISPLAY.length() % 10 + Build.HOST.length() % 10 +
    Build.ID.length() % 10 + Build.MANUFACTURER.length() % 10 +
    Build.MODEL.length() % 10 + Build.PRODUCT.length() % 10 +
    Build.TAGS.length() % 10 + Build.TYPE.length() % 10 +
    Build.USER.length() % 10; //13 位
  try {
	  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
		serial = android.os.Build.getSerial();
	  } else {
		serial = Build.SERIAL;
	  }
	  //API>=9 使用serial号
	  return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
	} catch (Exception exception) {
	//serial需要一个初始化
	serial = "serial"; // 随便一个初始化
  }
	//使用硬件信息拼凑出来的15位号码
	return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
}
虽然由于唯一标识符权限的更改会导致android.os.Build.getSerial()返回unknown,但是由于m_szDevIDShort是由硬件信息拼出来的,所以仍然保证了UUID的唯一性和持久性。
目前我们这边需要设备id的地方就是绑定手机,我们有考虑获取真正的设备id为空的情况,直接给了一个6位的随机字符串,这个问题对我们影响不大。
另外由于我们这边使用第三方推送,一般情况下推送库需要设备id才能知道到底是那个手机(具体看三方库的实现),需要实时关注推送库的更新,并进行使用。

二 compilesdk ,targetsdk修改

	compileSdkVersion 'android-Q'
defaultConfig {
...
    targetSdkVersion 'Q'
...// 目前不存在数字29哦
}

三 沙盒机制

读写外存权限已经并非必须的,删除了READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE两项危险权限,限制 App 只能使用自己的应用空间存放文件,需要原来放在sdk中的文件放在通过Context.getExternalFilesDir可以获取到属于 App 自身的文件路径,通常是~/Android/data/<package-name>/**/。在该目录中读写文件均不需要申请权限,当 App 被卸载时,该文件夹及内容也会全部删除。
当 App 需要保存一些不能随卸载删除的文件时,需要根据存放位置动态申请新增的权限:READ_MEDIA_IMAGES,READ_MEDIA_VIDEO 或 READ_MEDIA_AUDIO(分别对应系统的媒体文件夹)。 比较特殊的是 Downloads 文件夹:写入和读取自身写入的数据不需要申请权限,但想获取其他 App 存进去的文件时,必须使用系统的文件选择器,由用户选择。
需要做权限申请适配。
按访问的目标文件的地址介绍如何适配。
2.1. 访问自己文件:Q中用更精细的媒体特定权限替换并取消了 READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE权限,并且无需特定权限,应用即可访问自己沙盒中的文件。
2.2. 访问系统媒体文件:Q中引入了一个新定义媒体文件的共享集合,如果要访问沙盒外的媒体共享文件,比如照片,音乐,视频等,需要申请新的媒体权限:READ_MEDIA_IMAGES,READ_MEDIA_VIDEO,READ_MEDIA_AUDIO,申请方法同原来的存储权限。
2.3. 访问系统下载文件:对于系统下载文件夹的访问,暂时没做限制,但是,要访问其中其他应用的文件,必须允许用户使用系统的文件选择器应用来选择文件。
2.4. 访问其他应用沙盒文件:如果你的应用需要使用其他应用在沙盒内创建的文件,请点击使用其他应用的文件,本文不做介绍。
所以请判断当应用运行在Q平台上时,取消对READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE两个权限的申请。并替换为新的媒体特定权限。

对我们的影响:目前很多应用还有将文件直接保存到外部存储的行为,需要review代码,进行修改。最重要的是我们这边的设备id保存在外部存储上,如果用户升级到android q后,就会无法访问,暂时考虑在下个版本将此信息拷贝到沙盒内,另外由于无法保存到外部存储,就会出现卸载应用后需要手动解绑问题,这个需要跟后台配合处理。

四 后台获取经纬度

App 在后台使用定位需要动态申请ACCESS_BACKGROUND_LOCATION,
不可单独申请,原来的定位权限依然需要targetSDK <= P 应用如果请求了ACCESS_FINE_LOCATION 或 ACCESS_COARSE_LOCATION权限,Q设备会自动帮你申请ACCESS_BACKGROUND_LOCATION权限。

五 非 SDK 接口限制

	非SDK接口限制在Android P中就已提出,但是在Q中,被限制的接口的分类有较大变化。
谷歌官方也提供了官方检查器veridex用来检测一个apk中哪里使用了非SDK接口。veridex下载。https://android.googlesource.com/platform/prebuilts/runtime/+/master/appcompat,其中有windows,linux和mac版本,对应下载即可。下载解压后命令行cd到veridex目录下使用./appcompat.sh --dex-file=Q.apk即可自动扫描。Q.apk为包的绝对路径,如果包与veridex在相同目录下直接输入包文件名即可。扫描结果分为两部分,一部分为被调用的非SDK接口的位置,另一部分为非SDK接口数量统计。
项目中使用非SDK接口大概率有以下两种情况:
在自定义View的过程中为了方便,使用反射修改某个参数。三方SDK中使用了非SDK接口(这种情况比较多)。
第一种是好解决的,毕竟是我们自己写的代码。第二种就头疼了,只能更新到最新的三方SDK版本,或者提工单、换库(也是整个适配过程中工作量最庞大的部分)。

我们需要尽快使用官方检查器,检查出来那些代码使用了非sdk接口。并作出相应修改。目前我们使用了一个第三方库FreeReflection绕过非sdk接口检查,需要实时关注这个库的更新,参考链接:http://weishu.me/2019/03/16/another-free-reflection-above-android-p/。
我们需要尽快使用官方检查器,检查出来那些代码使用了非sdk接口。并作出相应修改。目前我们使用了一个第三方库FreeReflection绕过非sdk接口检查,需要实时关注这个库的更新,参考链接:http://weishu.me/2019/03/16/another-free-reflection-above-android-p/。

六 Android项目升级遇到的问题

Requires development platform Q but this is a release platform.
由于目前Q是preview版,所以targetSDK==Q 的应用只能在Q设备上跑。

NSTALL_FAILED_INVALID_APK: Failed to extract native libraries, res=-2
这个错误是由于打包压缩so库时造成的,具体原因可见:https://issuetracker.google.com/issues/37045367
在AndroidManifest.xml的application节点下加入android:extractNativeLibs="true"
可能有人加了上面代码还是不行,在app/build.gradle中的defaultConfig节点下加入
packagingOptions{ 
	  doNotStrip "/armeabi/.so" doNotStrip "/armeabi-v7a/.so" doNotStrip "/x86/.so" }

Didn't find class “org.apache.http.client.methods.HttpPost"
在AndroidManifest.xml的application节点下加入
<uses-library android:name="org.apache.http.legacy" android:required="false"/>

七 logo 适配

需要使用矢量图,及时更新图标,参考网址:https://blog.csdn.net/ccffvii/article/details/89037137
展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部