Android P 適配指南

前言

Goolge自 android L (6.0) 以來就持續對安裝系統進行 安全 以及 性能上的升級,這次的 android P (9.0)也不例外, 更大程度上對以前一些版本一些警告的具體落實,不管你的 Target Api 是不是 28 都將受到影響。

1. 影響全部應用 (不管TargetApi 是否 28+)

1.1 non-sdk 接口限制

此限制不只僅侷限於sdk層 ( 直接引用 或者 反射 ),而觸及到了 JNI 層,其實早在 android N 的時候就限制了 C / C++ 使用的符號集合,一旦NDK有沒法通知的變動,毫無疑問會引發程序的 crash 。html

1.1.1 SDK 接口和非 SDK 接口

SDK 接口指在 Android 框架 軟件包索 中記錄的接口, Google爲了讓開發者有過渡的時間而且起到警示的做用, 針對 non-sdk 接口設定了不一樣級別的名單類型:前端

  • 白名單:SDK
  • 淺灰名單:仍能夠訪問的非 SDK 函數/字段。
  • 深灰名單: * 對於 Target Api SDK 低於 API 28 的應用,容許使用深灰名單接口。
    • 對於 Target Api SDK 爲 API 28 或更高級別的應用:行爲與黑名單相同。
  • 黑名單:不管 Target Api SDK 如何。 平臺將表現爲彷佛接口並不存在。 例如,不管應用什麼時候嘗試使 用接口,平臺都會引起 NoSuchMethodError/NoSuchFieldException。

咱們平時開發須要注意的也就是 深灰名單黑名單,不用太在乎 淺灰名單 ,由於前面說到過能夠直接引用 non-sdk 接口,這裏基本上是指直接引用 淺灰名單的接口java

這邊先舉個例子:在官方的淺灰名單中,其中列舉可不少咱們平時用的接口,例如 Intent 獲取資源:linux

Landroid/content/Intent;->FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT:I
Landroid/content/Intent;->getExtra(Ljava/lang/String;)Ljava/lang/Object;
Landroid/content/Intent;->getExtra(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;

複製代碼

然而這正是咱們平時用的不少的 Api,因此沒必要太在乎,淺灰名單屬於很是低級別的警告, 客戶端適配迫切須要解決的是 黑名單 的列表: 黑名單 基本上是咱們平時應用級開發不會用到的Api,例如:android

Lsun/util/calendar/BaseCalendar;->getMonthLength(II)I
複製代碼

對應sdk中代碼:web

//推薦使用的方法,官方不限制
    public int getMonthLength(CalendarDate var1) {
        BaseCalendar.Date var2 = (BaseCalendar.Date)var1;
        int var3 = var2.getMonth();
        if (var3 >= 1 && var3 <= 12) {
            return this.getMonthLength(var2.getNormalizedYear(), var3);
        } else {
            throw new IllegalArgumentException("Illegal month value: " + var3);
        }
    }
	
	 //官方黑名單方法,運行在 P 設備上直接crash
    private int getMonthLength(int var1, int var2) {
        int var3 = DAYS_IN_MONTH[var2];
        if (var2 == 2 && this.isLeapYear(var1)) {
            ++var3;
        }

        return var3;
    }

複製代碼

因此呢,黑名單 雖然聽起來 駭人聽聞,可是對於存量app的影響倒不是很大,由於基本上都是一些私有的,罕見的方法。算法

影響範圍最大的當屬 深灰名單, 由於官方強烈不推薦使用,可是爲了給開發者緩衝時間,只有 Target Api 28+ 纔會出現異常,表明性的 Api 有 DexFile 類:shell

Ldalvik/system/DexFile;-><init>(Ljava/io/File;Ljava/lang/ClassLoader;[Ldalvik/system/DexPathList$Element;)V
Ldalvik/system/DexFile;-><init>(Ljava/lang/String;Ljava/lang/ClassLoader;[Ldalvik/system/DexPathList$Element;)V
Ldalvik/system/DexFile;-><init>(Ljava/lang/String;Ljava/lang/String;ILjava/lang/ClassLoader;[Ldalvik/system/DexPathList$Element;)V
Ldalvik/system/DexFile;-><init>(Ljava/nio/ByteBuffer;)V
Ldalvik/system/DexFile;->DEX2OAT_FOR_BOOT_IMAGE:I
Ldalvik/system/DexFile;->DEX2OAT_FOR_FILTER:I
Ldalvik/system/DexFile;->DEX2OAT_FOR_RELOCATION:I
Ldalvik/system/DexFile;->DEX2OAT_FROM_SCRATCH:I
Ldalvik/system/DexFile;->NO_DEXOPT_NEEDED:I
Ldalvik/system/DexFile;->closeDexFile(Ljava/lang/Object;)Z
Ldalvik/system/DexFile;->createCookieWithArray([BII)Ljava/lang/Object;
Ldalvik/system/DexFile;->createCookieWithDirectBuffer(Ljava/nio/ByteBuffer;II)Ljava/lang/Object;
Ldalvik/system/DexFile;->defineClass(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/lang/Object;Ldalvik/system/DexFile;Ljava/util/List;)Ljava/lang/Class;
Ldalvik/system/DexFile;->defineClassNative(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/lang/Object;Ldalvik/system/DexFile;)Ljava/lang/Class;

複製代碼

以及 AssetManager 相關:apache

Landroid/content/res/AssetManager;->TAG:Ljava/lang/String;
Landroid/content/res/AssetManager;->addAssetPathInternal(Ljava/lang/String;Z)I
Landroid/content/res/AssetManager;->addAssetPathNative(Ljava/lang/String;Z)I
Landroid/content/res/AssetManager;->addAssetPaths([Ljava/lang/String;)[I
Landroid/content/res/AssetManager;->addOverlayPathNative(Ljava/lang/String;)I
Landroid/content/res/AssetManager;->applyStyle(JIIJ[IIJJ)V

複製代碼

這兩個類被列入深灰名單基本上就打翻了市面上一衆 熱修復 框架, 這意味着若是您的App 是以 28+爲目標版本,而且運行在 android P 之上,則這些熱修復框架可能沒法正常運行api

在今年6月份 GMTC(全球大前端技術大會) 的時候,京東架構師發表了演講 《當插件化趕上android P》 中就提到了,去黑科技化,目前 Android P 的 non-sdk 限制已經影響到京東的 插件框架

1.1.2 獲取相關 non-sdk 名單

有兩種方法:

  • 若是您的本地有 AOSP 項目的話,在根目錄運行

    make hiddenapi-aosp-blacklist
    複製代碼

而後,能夠在如下位置找到文件:

out/target/common/obj/PACKAGING/hiddenapi-aosp-blacklist.txt
複製代碼
  • 另外更好的辦法是直接用官方編譯好的結果,在 這裏獲取 查看。

1.1.3 檢查項目中的 non-sdk

你大能夠在 相應名單中 查找你想查找的類,不過官方提供了自動掃描工具 veridex

下載到本地目錄, 找到你的系統對應的腳本目錄:

解壓目錄

使用命令掃描:

appcompat.sh --dex-file=apk路徑
複製代碼

能夠看到咱們的項目中只有一個 深灰名單的警告。

1.1.4 調用non-sdk 接口

下圖是利用各類途徑使用 non-sdk 接口的結果:

訪問方式 結果
Dalvik 指令引用字段 引起 NoSuchFieldError
Dalvik 指令引用函數 引起 NoSuchMethodError
經過 Class.getDeclaredField() 或 Class.getField() 反射 引起 NoSuchFieldException
經過 Class.getDeclaredMethod() 或 Class.getMethod() 反射 引起 NoSuchMethodException
經過 Class.getDeclaredFields() 或 Class.getFields() 反射 結果中未出現非 SDK 成員
經過 Class.getDeclaredMethods() 或 Class.getMethods(). 反射結果中未出現非 SDK 成員.
經過 env->GetFieldID() 調用 JNI 返回 NULL,引起 NoSuchFieldError
經過 env->GetMethodID() 調用 JNI 返回 NULL,引起 NoSuchMethodError

1.2 安全相關

1.2.1 加密變動

Crypto Java 加密架構 (JCA) 提供程序現已被移除

相似寫法,將會發生 NoSuchProviderException:

SecureRandom.getInstance("SHA1PRNG", "Crypto")
複製代碼

android P 以前的設備上,使用 Crypto 提供商,若是 target < 24 (N) 可以正常使用,若是target 24+ 則會失敗

adnrodi P 設備上 因爲完全移除了 Crypto, 所以不管 target 是何值 都會拋出異常 NoSuchProviderException

許多算法的 Bouncy Castle 版本被棄用

加密功能的 BC 提供者被移除,官方博客中這樣說:

Starting in Android P, we plan to deprecate some functionality from the BC provider that's duplicated by the AndroidOpenSSL (also known as Conscrypt) provider

android P開始,BC 提供者變成不推薦,若是targetApi < P 會有日誌警告 targetApi >=p (28+) 將會拋出 NoSuchAlgorithmException ,如下寫法將會受影響:

Cipher.getInstance("AES/CBC/PKCS7PADDING", "BC") or 
Cipher.getInstance("AES/CBC/PKCS7PADDING", Security.getProvider("BC"))
複製代碼

所以,建議不要再指定 provider 而使用默認實現。

1.3 隱私相關

後臺應用訪問受限

  • 您的應用不能訪問麥克風或攝像頭。
  • 使用連續報告模式的傳感器(例如加速度計和陀螺儀)不會接收事件。
  • 使用變化或一次性報告模式的傳感器不會接收事件。

若是您的應用須要在運行 Android 9 的設備上檢測傳感器事件,請使用前臺服務

權限組變動

Android P 引入 CALL_LOG 權限組並將 READ_CALL_LOGWRITE_CALL_LOGPROCESS_OUTGOING_CALLS 權限移入該組。 在以前的 Android 版本中,這些權限位於 PHONE 權限組

wifi掃描權限變動:

Android 8.0和Android 8.1:

成功調用 WifiManager.getScanResults() 須要如下任何一項權限:

  • ACCESS_FINE_LOCATION
  • ACCESS_COARSE_LOCATION
  • CHANGE_WIFI_STATE

若是調用應用程序沒有任何這些權限,則調用將失敗並顯示 SecurityException

Android 9及更高版本

成功調用 WifiManager.startScan() 須要知足如下全部條件:

  • 您的應用具備 ACCESS_FINE_LOCATION 或 ACCESS_COARSE_LOCATION 權限。
  • 您的應用具備 CHANGE_WIFI_STATE 權限。

成功調用 WifiManager.getScanResults() 須要知足如下全部條件:

  • 您的應用具備 ACCESS_FINE_LOCATION 或 ACCESS_COARSE_LOCATION 權限。
  • 您的應用具備 ACCESS_WIFI_STATE 權限。
  • 設備上啓用了位置服務(在「設置」>「位置」下)。

若是調用應用程序不知足全部這些要求,則調用將失敗並顯示 SecurityException

相似的限制也適用於 getConnectionInfo() 函數,該函數返回描述當前 Wi-Fi 鏈接的 WifiInfo 對象。 若是調用應用具備如下權限,則只能使用該對象的函數來檢索 SSIDBSSID 值:

  • ACCESS_FINE_LOCATIONACCESS_COARSE_LOCATION
  • ACCESS_WIFI_STATE 檢索 SSIDBSSID 還須要在設備上啓用位置服務(在 Settings > Location 下)。

使用證書的主機名驗證

RFC 2818 中,回退到 CN 已被棄用。所以,Android 再也不回退到使用 CN。 要驗證主機名,服務器必須出示具備匹配 SAN 的證書。 不包含與主機名匹配的 SAN 的證書再也不被信任

1.4 其餘限制

1.4.1 Apache HTTP 客戶端棄用影響採用非標準 ClassLoader 的應用

其實,自 Android 6 發佈,就移除了對 Apache HTTP 客戶端的支持,而推薦改用 HttpURLConnection 類,由於它能夠經過透明壓縮和響應緩存減小網絡使用,並可最大限度下降耗電量, 今後咱們變習慣這樣使用 Apache HTTP API,即在 build.geadle 添加:

android {
    useLibrary 'org.apache.http.legacy'
}
複製代碼

androd P 開始,默認狀況下該內容庫已從 bootclasspath 中移除且不可用於應用。

這句話怎麼理解,也就是說默認 Apache HTTP API 不可用,即便在build.geadle申明瞭該庫。 這種說法分兩種狀況: 運行在 android P 設備上的應用:

  • Target 28 ,默認會報 NoClassDefFoundError,由於此庫被禁止使用,要繼續使用 Apache HTTP 客戶端,以 Android 9 及更高版本爲目標的應用能夠向其 AndroidManifest.xml 添加如下內容:

    <uses-library android:name="org.apache.http.legacy" android:required="false"/>
    複製代碼
  • Target < 28  能夠和 android 6.0 一致。

bootclasspathlinux 系統變量,是系統在啓動時會預先加載的類,以提升系統性能,這是 小米 MIX(7.0)上的 bootclasspath 變量:

/system/bin/sh: /system/framework/core-oj.jar:/system/framework/core-libart.jar:/system/framework/conscrypt.jar:/system/framework/okhttp.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/telephony-common.jar:/system/framework/voip-common.jar:/system/framework/ims-common.jar:/system/framework/apache-xml.jar:/system/framework/org.apache.http.legacy.boot.jar:/system/framework/vivo-framework.jar:/system/framework/tcmiface.jar:/system/framework/telephony-ext.jar:/system/framework/vivo-media.jar:/system/framework/qcrilhook.jar:/system/framework/WfdCommon.jar:/system/framework/com.qti.location.sdk.jar:/system/framework/oem-services.jar:/system/framework/qcom.fmradio.jar: not found
複製代碼

變量中有:/system/framework/org.apache.http.legacy.boot.jar ,所以系統會幫咱們加載,默認容許使用。

這是 android P 上的 bootclasspath 變量:

/system/framework/core-oj.jar:/system/framework/core-libart.jar:/system/framework/conscrypt.jar:/system/framework/okhttp.jar:/system/framework/bouncycastle.jar:/system/framework/apache-xml.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/telephony-common.jar:/system/framework/voip-common.jar:/system/framework/ims-common.jar:/system/framework/android.hidl.base-V1.0-java.jar:/system/framework/android.hidl.manager-V1.0-java.jar:/system/framework/framework-oahl-backward-compatibility.jar:/system/framework/android.test.base.jar
generic_x86_64:/ $ 
複製代碼

是沒有 apachehttp 庫的, 可是 他們有一個共同特色,就是系統內置了 apache 包, 在 /system/framework/目錄下:

,可是我有一個困惑的地方,就是 一樣 是運行在 android P 設備上 和 運行在 低版本上(>M) DexPathList 值確不同:

  • android P :
PathClassLoader// 這是httpClient的 ClassLoader
DexPathList[[zip file "/system/framework/org.apache.http.legacy.boot.jar", 
             zip file "/data/app/com.example.leixiang.demoapp-hOOUC7E0LuRvgmYC38vd5w==/base.apk"
            ],nativeLibraryDirectories=[/data/app/com.example.leixiang.demoapp-hOOUC7E0LuRvgmYC38vd5w==/lib/x86_64, /system/lib64]]
            
複製代碼
  • android N:
dalvik.system.PathClassLoader //這是httpClient的 ClassLoader
[DexPathList[[zip file "/data/app/com.example.leixiang.demoapp-1/base.apk"
		],nativeLibraryDirectories=[/data/app/com.example.leixiang.demoapp-1/lib/arm64, /system/lib64, /vendor/lib64]]]
複製代碼

他們不一樣之處在於,android N 設備上的 DexPathList裏面多了 apache的包,可是他們的加載器卻都仍是 PathClassLoader,我想多是 P 系統上再也不預先加載 apache http 相關類,因此把他加入 DexPathList? ,  而且 P 以前的系統加載 bootclasspath 中類也是用的 PathClassLoader?這個有待研究。

1.5 電源管理優化

Android 9 引入了一項新的電池管理功能,即應用待機羣組。 應用待機羣組能夠基於應用最近使用時間和使用頻率,幫助系統排定應用請求資源的優先級。 根據使用模式,每一個應用都會歸類到 五個 優先級羣組之一中。 系統將根據應用所屬的羣組限制每一個應用能夠訪問的設備資源:

活躍

若是用戶當前正在使用應用,應用將被歸到「活躍」羣組中,例如:

  • 應用已啓動一個 Activity
  • 應用正在運行前臺服務
  • 應用的同步適配器與某個前臺應用使用的 content provider 關聯
  • 用戶在應用中點擊了某個通知 若是應用處於「活躍」羣組,系統不會對應用的做業、報警或 FCM 消息施加任何限制。

FCM是指google推送啦,國內不要想了,至於長鏈接和心跳包是否會限制要看國內廠商具體操做了。

工做集

若是應用常常運行,但當前未處於活躍狀態,它將被歸到「工做集」羣組中。 例如,用戶在大部分時間都啓動的某個社交媒體應用可能就屬於「工做集」羣組。 若是應用被間接使用,它們也會被升級到「工做集」羣組中 。

經常使用

若是應用會按期使用,但不是天天都必須使用,它將被歸到「經常使用」羣組中。 例如,用戶在健身房運行的某個鍛鍊跟蹤應用可能就屬於「經常使用」羣組。

極少使用

若是應用不常用,那麼它屬於「極少使用」羣組。 例如,用戶僅在入住酒店期間運行的酒店應用就可能屬於「極少使用」羣組。

從未使用

安裝可是從未運行過的應用會被歸到「從未使用」羣組中。 系統會對這些應用施加極強的限制。

咱們能夠利用 UsageStatsManager.getAppStandbyBucket() 查看咱們處於哪個分組,此 api 是 21 添加。

不過用戶能夠經過配置 低電耗 白名單來擺脫分組的限制,具體配置方法看這裏

如下是各分組對應的活動限制:

Setting Jobs * Alarms Network Firebase Cloud Messaging §
User Restricts Background Activity
Restrictions enabled: Never Never Never No restriction
Doze
Doze active: Deferred to window Regular alarms: Deferred to window While-idle alarms: Deferred up to 9 minutes Deferred to window High priority: No restriction Normal priority: Deferred to window
App Standby Buckets (by bucket)
Active: No restriction No restriction No restriction No restriction
Working set: Deferred up to 2 hours Deferred up to 6 minute No restriction No restriction
Frequent: Deferred up to 8 hours Deferred up to 30 minutes No restriction High priority: 10/day
Rare: Deferred up to 24 hours Deferred up to 2 hours Deferred up to 24 hours High priority: 5/day

咱們能夠經過 adb命令 讓咱們的調試設備處於特定分組來測試相關的行爲。

$ adb shell am set-standby-bucket packagename active|working_set|frequent|rare
複製代碼

2. 針對Taget 28+ 的應用

2.1 前臺服務

前臺服務 可讓你應用處於活躍狀態,上面提到過 前臺服務 可讓你的應用分組處於 活躍分組

Target 28+ 並使用前臺服務的應用必須請求 FOREGROUND_SERVICE 權限。 這是 普通權限,所以,系統會自動爲請求權限的應用授予此權限。

2.2 隱私權變動

構建序列號棄用

在 Android 9 中,Build.SERIAL 始終設置爲 "UNKNOWN" 以保護用戶的隱私。

若是您的應用須要訪問設備的硬件序列號,您應改成請求 READ_PHONE_STATE 權限,而後調用 getSerial()

android P SDK api:

/**
 * A hardware serial number, if available. Alphanumeric only, case-insensitive.
 * For apps targeting SDK higher than {@link Build.VERSION_CODES#O_MR1} this
 * field is set to {@link Build#UNKNOWN}.
 *
 * @deprecated Use {@link #getSerial()} instead.
 **/
 @Deprecated
 // IMPORTANT: This field should be initialized via a function call to
 // prevent its value being inlined in the app during compilation because
 // we will later set it to the value based on the app's target SDK. public static final String SERIAL = getString("no.such.thing"); 複製代碼

DNS 隱私

以 Android 9 爲目標平臺的應用應採用私有 DNS API。 具體而言,當系統解析程序正在執行 DNS-over-TLS 時,應用應確保任何內置 DNS 客戶端均使用加密的 DNS 查找與系統相同的主機名,或停用它而改用系統解析程序。 停用路徑: Settings -> private dns:

private DNS 設置

2.3 安全

默認狀況下啓用網絡傳輸層安全協議 (TLS)

若是您的應用 Target 28+,則默認狀況下 isCleartextTrafficPermitted() 函數返回 false。 若是您的應用須要爲特定域名啓用明文,您必須在應用的網絡安全性配置中針對這些域名將 cleartextTrafficPermitted 顯式設置爲 true

否定會出現如下日誌錯誤輸出:

W/Glide: Load failed for http://xxx-99billxx.ufile.ucloud.cn/online/image/A1707101417703-349-0xxhdpi 
java.io.IOException: Cleartext HTTP traffic to xxx-99billxx.ufile.ucloud.cn not permitted
複製代碼

注意:該api是 api 23 才引入的。 因此,因爲一些歷史緣由沒法及時把服務器變動爲 https 的應用,應該經過配置文件針對特定域名容許使用明文傳輸,也就是 http 服務。

定義配置文件 res/xml/network_security_config.xml:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="false">
        <domain includeSubdomains="true">secure.example.com</domain>
    </domain-config>
</network-security-config>
複製代碼

而後在manifest.xml 中申明

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
    <application android:networkSecurityConfig="@xml/network_security_config"
                    ... >
        ...
    </application>
</manifest>
複製代碼

按進程分設基於網絡的數據目錄

爲改善 Android 9 中的應用穩定性和數據完整性,應用沒法再讓多個進程共用同一 WebView 數據目錄。 此類數據目錄通常存儲 Cookie、HTTP 緩存以及其餘與網絡瀏覽有關的持久性和臨時性存儲

若是您的應用必須在多個進程中使用 WebView 的實例,則必須先利用 WebView.setDataDirectorySuffix() 函數爲每一個進程指定惟一的數據目錄後綴,而後再在該進程中使用 WebView 的給定實例。 該函數會將每一個進程的網絡數據放入其在應用數據目錄內本身的目錄中。

注:即便您使用 setDataDirectorySuffix(),系統也不會跨應用的進程界限共享 Cookie 以及其餘網絡數據。 若是應用中的多個進程須要訪問同一網絡數據,您須要自行在這些進程之間複製數據。 例如,您能夠調用 getCookie() 和 setCookie(),在不一樣進程之間手動傳輸 Cookie 數

3. 新功能

Kotlin 友好

改進了 dexer 以及協調Jetbranins改進 Kotlin Compier 使用 kotlin 編寫的App在android P 上運行得更快,而且和 Jetbrains 團隊溝通,提供了新的 kotlin 插件。

ImageDecoder

替代 BitmapFactory 能夠從 流、file、byte buffer、 uRL 加載 BitmapDrawable 支持精確尺寸縮放, 而且支持加載 gif 、 Webp, 以及圓角等樣式設置。

wifi RTT

在室內,IEEE 802.11 MC WI-FI protocol 測量與附近wifi 連接點的距離(2~3個),經過 RTT,來測量距離, 能精確到 1~2米 在提供硬件支持的 Android P 設備上,應用可使用全新的 RTT API 來測量與附近支持 RTT 的 Wi-Fi 接入點 (AP) 的距離,設備不須要鏈接至 AP 便可使用 RTT

使用uses-feature來標註:

<uses-feature android:name="android.hardware.wifi.rtt" />
複製代碼

PrecomputedText

顯示文本可能很複雜,包含多種字體,行間距,字母間距,文本方向,換行符,連字符等功能。TextView必須作不少工做來測量和佈置給定的文本:讀取字體文件,查找字形,肯定形狀,測量邊界框以及在內部字緩存中緩存單詞。更重要的是,全部這些工做都發生在 UI線程 上,它可能會致使您的應用程序 丟幀 測量文本可能佔用設置文本所需時間的 90%

android P 正式引入, 對於 android P 以前經過 JetpackPrecomputedTextCompat使用.

PrecomputedText

// UI thread
val params: PrecomputedText.Params = textView.getTextMetricsParams()
val ref = WeakReference(textView)
executor.execute {
    // background thread
    val text = PrecomputedText.create("Hello", params)
    val textView = ref.get()
    textView?.post {
        // UI thread
        val textViewRef = ref.get()
        textViewRef?.text = text
    }
}
複製代碼

Magnifier

android P 引入了文本放大鏡,以改善用戶選擇文本的體驗。放大鏡經過能夠在文本上拖動的窗格查看放大文本,幫助用戶精肯定位光標或文本選擇手柄,只須要覆寫視圖的 **OnTouchEvent()**方法:

fun onTouchEvent(event:MotionEvent):Boolean {
    when(event.actionMasked){
        MotionEvent.ACTION_DOWN  - > 
              magnifier.show(event.x,event.y)
        MotionEvent.ACTION_MOVE  - > 
             magnifier.show(event.x,event.y)
        MotionEvent.ACTION_UP  - > 
             magnifier.dismiss()
    }
}
複製代碼

可是惋惜的是:目前低版本設備(<P)沒有相關兼容類使用。

DEX 文件的 ART 提早轉換

在運行 Android 9 或更高版本的設備上,Android 運行時 (ART) 提早編譯器經過將應用軟件包中的 DEX 文件轉換爲更緊湊的表示形式,進一步優化了壓縮的 Dalvik Executable 格式 (DEX) 文件。 此項變動可以讓您的應用啓動更快並消耗更少的磁盤空間和內存。

這種改進特別有利於磁盤 I/O 速度較慢的低端設備。

參考資料

相關文章
相關標籤/搜索