前语

Android官方的搬家适配文档有点紊乱,这篇文章旨在给开发者在适配中对代码做快速检查。适配改动将分为运转版别影响和Target版别影响,并供给或许影响的功用以便检验参阅。转载请注明来历「Bug总柴」

Android Q (API level 29)

沙箱机制(scoped-storage)

在Android Q中改动比较大的是对外置sdcard的访问权限改动,这个改动将会影响大部分需求访问外置存储的运用。

沙箱机制解读

  1. external storage在Android Q开端被设置成像internal storage那种只能访问自己包名下的空间,无法直接访问sdcard其他方位内容。就算声明晰READ_EXTERNAL_STORAGE权限,在运用中通过File.listFiles只能看到/storage/emulated/0/Android/data/ , /storage/emulated/0/Android/media/ , /storage/emulated/0/Android/obb/ 三个文件夹。
  2. READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE的通用访问外置sdcard的权限被拆分为访问音乐READ_MEDIA_AUDIO、相片READ_MEDIA_IMAGES和视频READ_MEDIA_VIDEO三种权限,而访问运用沙箱的内容无需额外央求权限。

沙箱收效机遇

  1. 假设target版别小于等于28并且运用是设备在从Android 9升级到Andoid Q的手机上,则会启用兼容形式,依然可以随意访问external存储的内容。
  2. 意味着当target版别大于28,或许运用是在Android Q的手机上新设备都会使沙箱机制收效。这儿需求说明,不管是否target到28以上,只要是在Android Q上新设备的运用都会使沙箱机制收效。
  3. 关于模拟器里面的Andorid Q Beta 1版别,需求履行adb shell sm set-isolated-storage on敞开沙箱机制

影响规模

  1. 各种为了完结离线运用功用的离线下载文件
  2. 各种缓存文件(例如信息流缓存、广告缓存等)
  3. 需求注意某些三方库或许会运用外置sdcard(例如log或许crash核算等)

四、处理方法

  1. 关于图片视频音乐和下载文件可以通过MediaStore类访问,或许运用Storage Access Framework
  2. 关于之前存储在外置sdcard的其他数据,需求搬家存储到getExternalFilesDir目录中
  3. 关于新增的文件尽量保存在getExternalFilesDir和getExternalCacheDir

Api检查

Context.getExternalFilesDir(null) -> /storage/emulated/0/Android/data//files
Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES) -> /storage/emulated/0/Android/data//files/Pictures
Context.externalCacheDir -> /storage/emulated/0/Android/data//cache
Context.obbDir -> /storage/emulated/0/Android/obb/
Environment.getExternalStorageDirectory() -> /storage/emulated/0 (沙箱机制下无法访问)
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) -> /storage/emulated/0/Pictures (沙箱机制下无法访问)

Android 9 (API level 28)

官方行为改动文档

非SDK接口运用束缚

运用 veridex工具检验apk是否有调用非SDK接口

➜  veridex-mac ./appcompat.sh --dex-file=test.apk

实例成果如下:

6889 hidden API(s) used: 6817 linked against, 72 through reflection
       0 in blacklistgetConnectionInfo
       3 in dark greylist
       47 in light greylist
To run an analysis that can give more reflection accesses, 
but could include false positives, pass the --imprecise flag.

其中:

类型 描绘
blacklist 不管是否target到28,都会报NoSuchMethodError/NoSuchFieldException
dark greylist 假设target在28一下没问题,但是target到28及以上会报NoSuchMethodError/NoSuchFieldException
light greylist 暂时没有问题,可以运用

处理方法:
去除blacklist以及dark greylist的非android sdk调用的反射调用,有些是android support包内部调用的可以考虑升级support包版别

隐私&权限相关

运转在9.0遭到影响 或许遭到影响的功用
不能在后台访问麦克风和摄像头 后台录音、后台摄影
加速器陀螺仪等传感器不能在后台继续获取数据 步数核算
通过改动形式或许单次形式的传感器收不到工作 明显运动检测、计步器、近程传感器和心率传感器
通话记录权限组别由PHONE组调整到CALL_LOG 需求获通过记录权限的功用
通过android.intent.action.PHONE_STATETelephonyManager.listen方法获取手机号码需求央求READ_CALL_LOG 权限 例如来电归属地闪现或许来电阻拦等需求获取通话手机号的功用
wifi扫描频率束缚更为严厉,getConnectionInfo WifiManager.getScanResults()以及 WifiManager.startScan()需求而外权限详见 需求wifi扫描匹配等功用
WifiManager.getConnectionInfo() 要获得SSID和BSSID,要求定位权限并要求设备翻开定位功用,NETWORK_STATE_CHANGED_ACTION 不再能获得SSID和BSSID 需求获取wifi信息的功用
WifiManager与WifiP2pManager中getScanResults() getConnectionInfo()discoverServices() addServiceRequest()NETWORK_STATE_CHANGED_ACTION不再包含用户定位信息 运用wifi定位功用
TelephonyManager中getAllCellInfo() listen() getCellLocation() getNeighboringCellInfo()不回来成果,除非用户翻开了定位功用 运用移动信号定位
Target在9.0遭到影响 或许遭到影响的功用
发起前台服务要去注册android.permission.FOREGROUND_SERVICE权限 前台服务发起
获取序列号不能通过Build.SERIAL,需求注册android.permission.READ_PHONE_STATE然后运用Build.getSerial() 获取序列号相关功用

安全相关

运转在9.0遭到影响 或许遭到影响的功用
SSLSocket犯错不回来NullPointerException,改成回来IOException https网络差错处理
加密函数Cipher.getInstance("AES/CBC/PKCS7PADDING", "BC") Cipher.getInstance("AES/CBC/PKCS7PADDING",Security.getProvider("BC")) SecureRandom.getInstance("SHA1PRNG", "Crypto");移除 加密功用
Android secure encrypted files移除 移动app到sdcard功用
Target在9.0遭到影响 或许遭到影响的功用
DNS客户端需求依据系统运用加密DNS查找与系统相同的主机名,或改由系统解析程序 DNS自解析功用
默许要求运用https,假设需求运用http需求设置cleartextTrafficPermitted="true"详见 全部http网络央求
webview的数据包含cookies和caches不允许多进程同享 多进程运用webview
不用通过设置大局Unix权限同享数据文件,不用运用的文件同享需求运用ContentProvider 运用间文件同享

国际化相关

运转在9.0遭到影响 或许遭到影响的功用
java.text.SimpleDateFormat 运用zzzz格式、java.text.DateFormatSymbols.getZoneStrings()格式、NumberFormat.getInstance(ULocale, PLURALCURRENCYSTYLE).parse(String)格式批改 时区、钱银闪现相关功用

网络相关

运转在9.0遭到影响 或许遭到影响的功用
NetworkCapabilities支撑回来NET_CAPABILITY_NOT_VPN vpn设置功用
Apache HTTP client不能运用system ClassLoader加载,若要运用需求完结自定义ClassLoader 运用旧Apache Http client网络功用
Target在9.0遭到影响 或许遭到影响的功用
NetworkStatsManager 能获取非当时正在运用的流量状况 网络运用核算
ConnectivityManager.getMultipathPreference() 可以获取是否超过了移动流量运用束缚 网络运用状况提示
Apache Http背去除,要运用需求加上<uses-library android:name="org.apache.http.legacy" android:required="false"/>或许想apache.http相关类包通过jar方法引入 运用旧Apache Http client网络功用

界面相关

运转在9.0遭到影响 或许遭到影响的功用
通过非activity的context发起activity强制要求intent带上FLAG_ACTIVITY_NEW_TASK 后台发起页面
屏幕旋转方法由本来的“自动旋转”和“纵向”改为“自动旋转”和“固定旋转” 屏幕旋转功用
Target在9.0遭到影响 或许遭到影响的功用
长或宽为0的view不再可以获取焦点,新开页面不默许获取焦点 交互进程通过特别焦点完结的功用
webview可以支撑带透明度的8位色彩css webview css 色彩透明度功用
webview中document的root元素翻滚方位得到支撑 webview 相关
暂停挂起app的告知会在app resumed之后从头告知 告知相关

设备相关

运转在9.0遭到影响 或许遭到影响的功用
多摄像头支撑getCameraIdList()前后摄像头切换需求挑选适宜的摄像头 摄像头相关功用

其他

运转在9.0遭到影响 或许遭到影响的功用
UTF-8解码更加严厉按照Unicode规范详见 UTF-8解码相关的功用

有用参阅地址

权限组级别

Android 8 (API level 26)

官方行为改动文档

后台束缚

运转在8.0遭到影响 或许遭到影响的功用
后台运用通过startService()方法发起服务,
包含IntentService会遭到束缚并抛出IllegalStateException失常,
需求改成运用 JobScheduler 或许JobIntentService
全部发起后台服务的行为,包含但不限于后台下载、后台数据更新、后台初始化等等
前台服务发起不能通过发起后台服务再将其转换为前台,
需求通过startForegroundService()方法,
并在5s内调用startForeground()方法闪现前台告知,否则会ANR
全部前台服务,包含音乐播放功用、其他有告知的服务
自定义action播送以及其他系统非指向性的播送接收遭到束缚,
可通过manifests注册指向性播送或许通过Context.registerReceiver()动态注册,
系统性的播送工作可考虑通过JobScheduler装备完结
例如软件设备后的播送处理以及网络改动告知处理功用
后台运用获取方位遭到束缚,包含FusedLocationProviderApi、
GnssMeasurement、GnssNavigationMessage、
WifiManager.startScan()、LocationManager,需求运用前台服务坚持运用前台状况
后台动作检测功用、后台需求用到地舆方位的功用例如后台导航之类

隐私&权限相关

运转在8.0遭到影响 或许遭到影响的功用
ANDROID_ID从之前的仅与设备相关,改为与运用签名、设备、设备登录用户相关。 运用ANDROID_ID的功用
获取系统特点net.hostname将回来null wifi hostname获取功用
Target在8.0遭到影响 或许遭到影响的功用
系统特点net.dns*不再支撑 通过系统特点获取dns功用
需求获取DNS信息需求ACCESS_NETWORK_STATE权限,通过
NetworkRequest或许NetworkCallback获取
DNS获取功用
获取序列号不能通过Build.SERIAL,需求注册android.permission.READ_PHONE_STATE然后运用Build.getSerial() 获取序列号相关功用
LauncherApps获取不同用户的运用信息时,会当做没有任何运用设备,而不是抛出失常 桌面发起器相关功用
相同权限组的其他权限会在实在需求时才被自动颁布,之前是整个权限组一同颁布 权限颁布相关

安全相关

运转在8.0遭到影响 或许遭到影响的功用
不再支撑SSLv3 运用SSLv3的当地
HTTPS运用差错的TLS协议与服务交互时,不再运用其他TLS协议重试 HTTPS相关
在bionic之外的系统调用将被阻止 bionic系统调用
WebView被运转在多进程空间 WebView间数据同享
APKs设备路径或许会被批改 APKs管理
判别是否能设备运用需运用PackageManager.canRequestPackageInstalls(),
INSTALL_NON_MARKET_APPS失效
运用设备
8.0系统默许阻止运用设备不知道运用 运用设备功用
Thread.UncaughtExceptionHandler 会记录在stacktrace中,但不会杀死运用 线程失常处理
Target在8.0遭到影响 或许遭到影响的功用
registerContentObserver(Uri, boolean, ContentObserver)中的Uri有必要运用ContentProvider注册 以Uri来告知改动的功用
network_security_config.xml 装备阻止明文传输将同样影响WebView Https功用
AccountManager不能只通过声明GET_ACCOUNTS来获取账号,需求调用
AccountManager.newChooseAccountIntent()让用户挑选,
再通过AccountManager.getAccounts()来获取
Account Services相关
native库若包含可履行文件则不会加载 native库相关
JNI调用会检查反射的类或方法是否存在,否则会抛出失常 JNI调用
DexFile API现已过期,建议运用系统默许PathClassLoader 或许 BaseDexClassLoader
假设需求用到DexFile,不应该进行压缩,否则会解压耗费内存。
多线程加载相同类由最早加载的类的加载器决议。
Dex 加载相关

国际化相关

运转在8.0遭到影响 或许遭到影响的功用
Currency.getDisplayName()、Currency.getSymbol()、
Locale.getDisplayScript()
默许调用Locale.getDefault(Category.DISPLAY)
国际化闪现
Currency.getDisplayName(null)将会抛出失常 国际化单位闪现
关于SimpleDateFormat的时区获取由本来在设备第一次发起时分获取,改为每次实时获取 时区闪现
升级ICU到58版别 国际化单位规范

网络相关

运转在8.0遭到影响 或许遭到影响的功用
无正文的 OPTIONS 央求具有 Content-Length: 0 头部 options央求相关
HttpURLConnection会确保央求终究带上“/” HttpURLConnection
ProxySelector.setDefault() 设置的署理仅处理scheme/host/port,不会处理央求参数 署理设置相关功用
不再支撑空lable的URI 运用URI相关功用
HttpsURLConnection不会履行不安全的TLS/SSL协议版别回退 HttpsURLConnection
隧道Https协议改动,具体见Networking and HTTP(S) connectivity 隧道Https
假设DatagramSocket.connect() 回来差错,DatagramSocket.send()也会回来差错 socket相关
InetAddress.isReachable() 会在会退到TCP Echo协议之前检验ICMP协议,若不可达会耗费更多时刻 IP地址判别是否可达等网络功用
在支撑设备上wifi衔接当有强度大且现已保存的网络时可以自动切换 需确保网络切换不会影响运用功用

界面相关

运转在8.0遭到影响 或许遭到影响的功用
TYPE_PHONE、TYPE_PRIORITY_PHONE、
TYPE_SYSTEM_ALERT、TYPE_SYSTEM_OVERLAY、
TYPE_SYSTEM_ERROR这些类型的窗口都会闪现在TYPE_APPLICATION_OVERLAY之下
悬浮球、快速查词等需求弹窗弹窗的当地
运用键盘导航时,获取焦点的view将会加上ripple高亮,
假设不需求这种默许的高亮,
需求设置android:defaultFocusHighlightEnabled
或许setDefaultFocusHighlightEnabled(false)
键盘导航
webview中WebSettings.getSaveFormData()回来false,
WebSettings.setSaveFormData()没有任何作用,
WebViewDatabase.clearFormData()没有任何作用,
WebViewDatabase.hasFormData()回来false
网页相关
Target在8.0遭到影响 或许遭到影响的功用
TYPE_PHONE、TYPE_PRIORITY_PHONE、
TYPE_SYSTEM_ALERT、TYPE_SYSTEM_OVERLAY、
TYPE_SYSTEM_ERROR
不能用在alert window上,有必要运用
TYPE_APPLICATION_OVERLAY
悬浮球、快速查词等需求弹窗弹窗的当地
可点击的View默许拥有可获取焦点特点 View焦点闪现
Notificaiton告知有必要指定Notificaiton Channels,否则不会闪现告知,详见notifications 告知相关

设备相关

运转在8.0遭到影响 或许遭到影响的功用
蓝牙ScanRecord.getBytes()回来长度不受束缚 蓝牙相关功用
Target在8.0遭到影响 或许遭到影响的功用
音频获取焦点时会自动下降其他音频音量,现在支撑暂停而不是下降音量,详见automatic ducking 音频播放相关功用
当来电时,自动静音音频播放 音频播放相关功用
需求运用AudioAttributes完结音频回放功用,AudioTrack过期 音频回放功用
音量按键工作会优先给前台activity,假设前台activity不处理会给最近一次播放音频的运用 音量控制

其他

运转在8.0遭到影响 或许遭到影响的功用
运用快捷方法不能通过com.android.launcher.action.INSTALL_SHORTCUT创建,
需求运用ShortcutManager,具体如何创建可以看这篇文章
快捷方法创建功用
无障碍功用中双击动作转换为点击动作、
能辨认TextView中的ClickableSpan
无障碍功用
findViewById() 回来类型由View改为<T extends View> T 掩盖findViewById() 的当地需求相应批改
从2019年1月7日起,将无法通过
LAST_TIME_CONTACTED
/TIMES_CONTACTED
/LAST_TIME_USED
/TIMES_USED
获取联络人运用状况
联络人联络状况获取功用
AbstractCollection.removeAll(java.util.Collection)
/AbstractCollection.retainAll(java.util.Collection)
当传入参数为null时会报NullPointerException
集结操作
Target在8.0遭到影响 或许遭到影响的功用
浏览器ua会包含OPR有或许导致判别是否Opera浏览器失效 依据ua判别浏览器
Collections.sort()改为在List.sort()基础上完结,之前是恰好相反。
假设在List.sort()中调用Collections.sort()会发生死循环
集结排序
在遍历的进程中进行排序,现在运用无论运用List.sort()仍是Collections.sort()都会报错 集结排序