Andriod版本適配 check list(持續(xù)更新)

前言

Android官方的遷移適配文檔有點(diǎn)混亂,這篇文章旨在給開發(fā)者在適配中對(duì)代碼做快速檢查。適配變化將分為運(yùn)行版本影響和Target版本影響,并提供可能影響的功能以便測(cè)試參考。轉(zhuǎn)載請(qǐng)注明來源「Bug總柴」

Android Q (API level 29)

沙箱機(jī)制(scoped-storage)

在Android Q中變化比較大的是對(duì)外置sdcard的訪問權(quán)限變化,這個(gè)變化將會(huì)影響大部分需要訪問外置存儲(chǔ)的應(yīng)用。

沙箱機(jī)制解讀

  1. external storage在Android Q開始被設(shè)置成像internal storage那種只能訪問自己包名下的空間,無法直接訪問sdcard其他位置內(nèi)容。就算聲明了READ_EXTERNAL_STORAGE權(quán)限,在應(yīng)用中通過File.listFiles只能看到/storage/emulated/0/Android/data/<package> , /storage/emulated/0/Android/media/<package> , /storage/emulated/0/Android/obb/<package> 三個(gè)文件夾。
  2. READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE的通用訪問外置sdcard的權(quán)限被拆分為訪問音樂READ_MEDIA_AUDIO、照片READ_MEDIA_IMAGES和視頻READ_MEDIA_VIDEO三種權(quán)限,而訪問應(yīng)用沙箱的內(nèi)容無需額外申請(qǐng)權(quán)限。

沙箱生效時(shí)機(jī)

  1. 如果target版本小于等于28并且應(yīng)用是安裝在從Android 9升級(jí)到Andoid Q的手機(jī)上,則會(huì)啟用兼容模式,仍然可以隨意訪問external存儲(chǔ)的內(nèi)容。
  2. 意味著當(dāng)target版本大于28,或者應(yīng)用是在Android Q的手機(jī)上新安裝都會(huì)使沙箱機(jī)制生效。這里需要說明,不管是否target到28以上,只要是在Android Q上新安裝的應(yīng)用都會(huì)使沙箱機(jī)制生效。
  3. 對(duì)于模擬器里面的Andorid Q Beta 1版本,需要執(zhí)行adb shell sm set-isolated-storage on開啟沙箱機(jī)制

影響范圍

  1. 各種為了實(shí)現(xiàn)離線使用功能的離線下載文件
  2. 各種緩存文件(例如信息流緩存、廣告緩存等)
  3. 需要注意某些三方庫(kù)可能會(huì)使用外置sdcard(例如log或者crash統(tǒng)計(jì)等)

四、處理辦法

  1. 對(duì)于圖片視頻音樂和下載文件可以通過MediaStore類訪問,或者使用Storage Access Framework
  2. 對(duì)于之前存儲(chǔ)在外置sdcard的其他數(shù)據(jù),需要遷移存儲(chǔ)到getExternalFilesDir目錄中
  3. 對(duì)于新增的文件盡量保存在getExternalFilesDir和getExternalCacheDir

Api檢查

Context.getExternalFilesDir(null) -> /storage/emulated/0/Android/data/<package>/files
Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES) -> /storage/emulated/0/Android/data/<package>/files/Pictures
Context.externalCacheDir -> /storage/emulated/0/Android/data/<package>/cache
Context.obbDir -> /storage/emulated/0/Android/obb/<package>
Environment.getExternalStorageDirectory() -> /storage/emulated/0 (沙箱機(jī)制下無法訪問)
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) -> /storage/emulated/0/Pictures (沙箱機(jī)制下無法訪問)

Android 9 (API level 28)

官方行為變更文檔

非SDK接口使用限制

使用 veridex工具測(cè)試apk是否有調(diào)用非SDK接口

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

實(shí)例結(jié)果如下:

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,都會(huì)報(bào)NoSuchMethodError/NoSuchFieldException
dark greylist 如果target在28一下沒問題,但是target到28及以上會(huì)報(bào)NoSuchMethodError/NoSuchFieldException
light greylist 暫時(shí)沒有問題,可以使用

處理辦法:
去除blacklist以及dark greylist的非android sdk調(diào)用的反射調(diào)用,有些是android support包內(nèi)部調(diào)用的可以考慮升級(jí)support包版本

隱私&權(quán)限相關(guān)

運(yùn)行在9.0受到影響 可能受到影響的功能
不能在后臺(tái)訪問麥克風(fēng)和攝像頭 后臺(tái)錄音、后臺(tái)拍照
加速器陀螺儀等傳感器不能在后臺(tái)持續(xù)獲取數(shù)據(jù) 步數(shù)計(jì)算
通過變化模式或者單次模式的傳感器收不到事件 顯著運(yùn)動(dòng)檢測(cè)、計(jì)步器、近程傳感器和心率傳感器
通話記錄權(quán)限組別由PHONE組調(diào)整到CALL_LOG 需要獲通過記錄權(quán)限的功能
通過android.intent.action.PHONE_STATETelephonyManager.listen方法獲取手機(jī)號(hào)碼需要申請(qǐng)READ_CALL_LOG 權(quán)限 例如來電歸屬地顯示或者來電攔截等需要獲取通話手機(jī)號(hào)的功能
wifi掃描頻率限制更為嚴(yán)格,getConnectionInfo WifiManager.getScanResults()以及WifiManager.startScan()需要而外權(quán)限詳見 需要wifi掃描匹配等功能
WifiManager.getConnectionInfo() 要獲得SSID和BSSID,要求定位權(quán)限并要求設(shè)備打開定位功能,NETWORK_STATE_CHANGED_ACTION不再能獲得SSID和BSSID 需要獲取wifi信息的功能
WifiManager與WifiP2pManager中getScanResults() getConnectionInfo()discoverServices() addServiceRequest()NETWORK_STATE_CHANGED_ACTION不再包含用戶定位信息 使用wifi定位功能
TelephonyManagergetAllCellInfo() listen() getCellLocation() getNeighboringCellInfo()不返回結(jié)果,除非用戶打開了定位功能 使用移動(dòng)信號(hào)定位
Target在9.0受到影響 可能受到影響的功能
啟動(dòng)前臺(tái)服務(wù)要去注冊(cè)android.permission.FOREGROUND_SERVICE權(quán)限 前臺(tái)服務(wù)啟動(dòng)
獲取序列號(hào)不能通過Build.SERIAL,需要注冊(cè)android.permission.READ_PHONE_STATE然后使用Build.getSerial() 獲取序列號(hào)相關(guān)功能

安全相關(guān)

運(yùn)行在9.0受到影響 可能受到影響的功能
SSLSocket出錯(cuò)不返回NullPointerException,改成返回IOException https網(wǎng)絡(luò)錯(cuò)誤處理
加密函數(shù)Cipher.getInstance("AES/CBC/PKCS7PADDING", "BC") Cipher.getInstance("AES/CBC/PKCS7PADDING",Security.getProvider("BC")) SecureRandom.getInstance("SHA1PRNG", "Crypto");移除 加密功能
Android secure encrypted files移除 移動(dòng)app到sdcard功能
Target在9.0受到影響 可能受到影響的功能
DNS客戶端需要根據(jù)系統(tǒng)使用加密DNS查找與系統(tǒng)相同的主機(jī)名,或改由系統(tǒng)解析程序 DNS自解析功能
默認(rèn)要求使用https,如果需要使用http需要設(shè)置cleartextTrafficPermitted="true"詳見 所有http網(wǎng)絡(luò)請(qǐng)求
webview的數(shù)據(jù)包括cookies和caches不允許多進(jìn)程共享 多進(jìn)程使用webview
不用通過設(shè)置全局Unix權(quán)限共享數(shù)據(jù)文件,不用應(yīng)用的文件共享需要使用ContentProvider 應(yīng)用間文件共享

國(guó)際化相關(guān)

運(yùn)行在9.0受到影響 可能受到影響的功能
java.text.SimpleDateFormat 使用zzzz格式、java.text.DateFormatSymbols.getZoneStrings()格式、NumberFormat.getInstance(ULocale, PLURALCURRENCYSTYLE).parse(String)格式修改 時(shí)區(qū)、貨幣顯示相關(guān)功能

網(wǎng)絡(luò)相關(guān)

運(yùn)行在9.0受到影響 可能受到影響的功能
NetworkCapabilities支持返回NET_CAPABILITY_NOT_VPN vpn設(shè)置功能
Apache HTTP client不能使用system ClassLoader加載,若要使用需要實(shí)現(xiàn)自定義ClassLoader 使用舊Apache Http client網(wǎng)絡(luò)功能
Target在9.0受到影響 可能受到影響的功能
NetworkStatsManager能獲取非當(dāng)前正在使用的流量情況 網(wǎng)絡(luò)使用統(tǒng)計(jì)
ConnectivityManager.getMultipathPreference() 可以獲取是否超過了移動(dòng)流量使用限制 網(wǎng)絡(luò)使用情況提醒
Apache Http背去除,要使用需要加上<uses-library android:name="org.apache.http.legacy" android:required="false"/>或者想apache.http相關(guān)類包通過jar方式引入 使用舊Apache Http client網(wǎng)絡(luò)功能

界面相關(guān)

運(yùn)行在9.0受到影響 可能受到影響的功能
通過非activity的context啟動(dòng)activity強(qiáng)制要求intent帶上FLAG_ACTIVITY_NEW_TASK 后臺(tái)啟動(dòng)頁(yè)面
屏幕旋轉(zhuǎn)方式由原來的“自動(dòng)旋轉(zhuǎn)”和“縱向”改為“自動(dòng)旋轉(zhuǎn)”和“固定旋轉(zhuǎn)” 屏幕旋轉(zhuǎn)功能
Target在9.0受到影響 可能受到影響的功能
長(zhǎng)或?qū)挒?的view不再可以獲取焦點(diǎn),新開頁(yè)面不默認(rèn)獲取焦點(diǎn) 交互過程通過特殊焦點(diǎn)實(shí)現(xiàn)的功能
webview可以支持帶透明度的8位顏色css webview css 顏色透明度功能
webview中document的root元素滾動(dòng)位置得到支持 webview 相關(guān)
暫停掛起app的通知會(huì)在app resumed之后重新通知 通知相關(guān)

設(shè)備相關(guān)

運(yùn)行在9.0受到影響 可能受到影響的功能
多攝像頭支持getCameraIdList()前后攝像頭切換需要選擇合適的攝像頭 攝像頭相關(guān)功能

其他

運(yùn)行在9.0受到影響 可能受到影響的功能
UTF-8解碼更加嚴(yán)格按照Unicode標(biāo)準(zhǔn)詳見 UTF-8解碼相關(guān)的功能

實(shí)用參考地址

權(quán)限組級(jí)別

Android 8 (API level 26)

官方行為變更文檔

后臺(tái)限制

運(yùn)行在8.0受到影響 可能受到影響的功能
后臺(tái)應(yīng)用通過startService()方法啟動(dòng)服務(wù),
包括IntentService會(huì)受到限制并拋出IllegalStateException異常,
需要改成使用 JobScheduler 或者JobIntentService
所有啟動(dòng)后臺(tái)服務(wù)的行為,包括但不限于后臺(tái)下載、后臺(tái)數(shù)據(jù)更新、后臺(tái)初始化等等
前臺(tái)服務(wù)啟動(dòng)不能通過啟動(dòng)后臺(tái)服務(wù)再將其轉(zhuǎn)換為前臺(tái),
需要通過startForegroundService()方法,
并在5s內(nèi)調(diào)用startForeground()方法顯示前臺(tái)通知,否則會(huì)ANR
所有前臺(tái)服務(wù),包括音樂播放功能、其他有通知的服務(wù)
自定義action廣播以及其他系統(tǒng)非指向性的廣播接收受到限制,
可通過manifests注冊(cè)指向性廣播或者通過Context.registerReceiver()動(dòng)態(tài)注冊(cè),
系統(tǒng)性的廣播事件可考慮通過JobScheduler配置實(shí)現(xiàn)
例如軟件安裝后的廣播處理以及網(wǎng)絡(luò)變化通知處理功能
后臺(tái)應(yīng)用獲取位置受到限制,包括FusedLocationProviderApi
GnssMeasurement、GnssNavigationMessage、
WifiManager.startScan()、LocationManager,需要使用前臺(tái)服務(wù)保持應(yīng)用前臺(tái)狀態(tài)
后臺(tái)動(dòng)作檢測(cè)功能、后臺(tái)需要用到地理位置的功能例如后臺(tái)導(dǎo)航之類

隱私&權(quán)限相關(guān)

運(yùn)行在8.0受到影響 可能受到影響的功能
ANDROID_ID從之前的僅與設(shè)備相關(guān),改為與應(yīng)用簽名、設(shè)備、設(shè)備登錄用戶相關(guān)。 使用ANDROID_ID的功能
獲取系統(tǒng)屬性net.hostname將返回null wifi hostname獲取功能
Target在8.0受到影響 可能受到影響的功能
系統(tǒng)屬性net.dns*不再支持 通過系統(tǒng)屬性獲取dns功能
需要獲取DNS信息需要ACCESS_NETWORK_STATE權(quán)限,通過
NetworkRequest或者NetworkCallback獲取
DNS獲取功能
獲取序列號(hào)不能通過Build.SERIAL,需要注冊(cè)android.permission.READ_PHONE_STATE然后使用Build.getSerial() 獲取序列號(hào)相關(guān)功能
LauncherApps獲取不同用戶的應(yīng)用信息時(shí),會(huì)當(dāng)做沒有任何應(yīng)用安裝,而不是拋出異常 桌面啟動(dòng)器相關(guān)功能
相同權(quán)限組的其他權(quán)限會(huì)在真正需要時(shí)才被自動(dòng)授予,之前是整個(gè)權(quán)限組同時(shí)授予 權(quán)限授予相關(guān)

安全相關(guān)

運(yùn)行在8.0受到影響 可能受到影響的功能
不再支持SSLv3 使用SSLv3的地方
當(dāng)HTTPS使用錯(cuò)誤的TLS協(xié)議與服務(wù)交互時(shí),不再使用其他TLS協(xié)議重試 HTTPS相關(guān)
在bionic之外的系統(tǒng)調(diào)用將被禁止 bionic系統(tǒng)調(diào)用
WebView被運(yùn)行在多進(jìn)程空間 WebView間數(shù)據(jù)共享
APKs安裝路徑可能會(huì)被修改 APKs管理
判斷是否能安裝應(yīng)用需使用PackageManager.canRequestPackageInstalls(),
INSTALL_NON_MARKET_APPS失效
應(yīng)用安裝
8.0系統(tǒng)默認(rèn)禁止應(yīng)用安裝未知應(yīng)用 應(yīng)用安裝功能
Thread.UncaughtExceptionHandler 會(huì)記錄在stacktrace中,但不會(huì)殺死應(yīng)用 線程異常處理
Target在8.0受到影響 可能受到影響的功能
registerContentObserver(Uri, boolean, ContentObserver)中的Uri必須使用ContentProvider注冊(cè) 以Uri來通知變化的功能
network_security_config.xml 配置禁止明文傳輸將同樣影響WebView Https功能
AccountManager不能只通過申明GET_ACCOUNTS來獲取賬號(hào),需要調(diào)用
AccountManager.newChooseAccountIntent()讓用戶選擇,
再通過AccountManager.getAccounts()來獲取
Account Services相關(guān)
native庫(kù)若包含可執(zhí)行文件則不會(huì)加載 native庫(kù)相關(guān)
JNI調(diào)用會(huì)檢查反射的類或方法是否存在,否則會(huì)拋出異常 JNI調(diào)用
DexFile API已經(jīng)過時(shí),建議使用系統(tǒng)默認(rèn)PathClassLoader 或者 BaseDexClassLoader。
如果需要用到DexFile,不應(yīng)該進(jìn)行壓縮,否則會(huì)解壓消耗內(nèi)存。
多線程加載相同類由最先加載的類的加載器決定。
Dex 加載相關(guān)

國(guó)際化相關(guān)

運(yùn)行在8.0受到影響 可能受到影響的功能
Currency.getDisplayName()Currency.getSymbol()、
Locale.getDisplayScript()
默認(rèn)調(diào)用Locale.getDefault(Category.DISPLAY)
國(guó)際化顯示
Currency.getDisplayName(null)將會(huì)拋出異常 國(guó)際化單位顯示
對(duì)于SimpleDateFormat的時(shí)區(qū)獲取由原來在設(shè)備第一次啟動(dòng)時(shí)候獲取,改為每次實(shí)時(shí)獲取 時(shí)區(qū)顯示
升級(jí)ICU到58版本 國(guó)際化單位標(biāo)準(zhǔn)

網(wǎng)絡(luò)相關(guān)

運(yùn)行在8.0受到影響 可能受到影響的功能
無正文的 OPTIONS 請(qǐng)求具有 Content-Length: 0 頭部 options請(qǐng)求相關(guān)
HttpURLConnection會(huì)保證請(qǐng)求最后帶上“/” HttpURLConnection
ProxySelector.setDefault()設(shè)置的代理僅處理scheme/host/port,不會(huì)處理請(qǐng)求參數(shù) 代理設(shè)置相關(guān)功能
不再支持空lable的URI 使用URI相關(guān)功能
HttpsURLConnection不會(huì)執(zhí)行不安全的TLS/SSL協(xié)議版本回退 HttpsURLConnection
隧道Https協(xié)議改變,具體見Networking and HTTP(S) connectivity 隧道Https
如果DatagramSocket.connect()返回錯(cuò)誤,DatagramSocket.send()也會(huì)返回錯(cuò)誤 socket相關(guān)
InetAddress.isReachable() 會(huì)在會(huì)退到TCP Echo協(xié)議之前嘗試ICMP協(xié)議,若不可達(dá)會(huì)消耗更多時(shí)間 IP地址判斷是否可達(dá)等網(wǎng)絡(luò)功能
在支持設(shè)備上wifi連接當(dāng)有強(qiáng)度大且已經(jīng)保存的網(wǎng)絡(luò)時(shí)可以自動(dòng)切換 需保證網(wǎng)絡(luò)切換不會(huì)影響應(yīng)用功能

界面相關(guān)

運(yùn)行在8.0受到影響 可能受到影響的功能
TYPE_PHONETYPE_PRIORITY_PHONE、
TYPE_SYSTEM_ALERTTYPE_SYSTEM_OVERLAY、
TYPE_SYSTEM_ERROR這些類型的窗口都會(huì)顯示在TYPE_APPLICATION_OVERLAY之下
懸浮球、快速查詞等需要彈窗彈窗的地方
使用鍵盤導(dǎo)航時(shí),獲取焦點(diǎn)的view將會(huì)加上ripple高亮,
如果不需要這種默認(rèn)的高亮,
需要設(shè)置android:defaultFocusHighlightEnabled
或者setDefaultFocusHighlightEnabled(false)
鍵盤導(dǎo)航
webview中WebSettings.getSaveFormData()返回false,
WebSettings.setSaveFormData()沒有任何作用,
WebViewDatabase.clearFormData()沒有任何作用,
WebViewDatabase.hasFormData()返回false
網(wǎng)頁(yè)相關(guān)
Target在8.0受到影響 可能受到影響的功能
TYPE_PHONE、TYPE_PRIORITY_PHONE、
TYPE_SYSTEM_ALERT、TYPE_SYSTEM_OVERLAY
TYPE_SYSTEM_ERROR
不能用在alert window上,必須使用
TYPE_APPLICATION_OVERLAY
懸浮球、快速查詞等需要彈窗彈窗的地方
可點(diǎn)擊的View默認(rèn)擁有可獲取焦點(diǎn)屬性 View焦點(diǎn)顯示
Notificaiton通知必須指定Notificaiton Channels,否則不會(huì)顯示通知,詳見notifications 通知相關(guān)

設(shè)備相關(guān)

運(yùn)行在8.0受到影響 可能受到影響的功能
藍(lán)牙ScanRecord.getBytes()返回長(zhǎng)度不受限制 藍(lán)牙相關(guān)功能
Target在8.0受到影響 可能受到影響的功能
音頻獲取焦點(diǎn)時(shí)會(huì)自動(dòng)降低其他音頻音量,現(xiàn)在支持暫停而不是降低音量,詳見automatic ducking 音頻播放相關(guān)功能
當(dāng)來電時(shí),自動(dòng)靜音音頻播放 音頻播放相關(guān)功能
需要使用AudioAttributes實(shí)現(xiàn)音頻回放功能,AudioTrack過期 音頻回放功能
音量按鍵事件會(huì)優(yōu)先給前臺(tái)activity,如果前臺(tái)activity不處理會(huì)給最近一次播放音頻的應(yīng)用 音量控制

其他

運(yùn)行在8.0受到影響 可能受到影響的功能
應(yīng)用快捷方式不能通過com.android.launcher.action.INSTALL_SHORTCUT創(chuàng)建,
需要使用ShortcutManager,具體如何創(chuàng)建可以看這篇文章
快捷方式創(chuàng)建功能
無障礙功能中雙擊動(dòng)作轉(zhuǎn)換為點(diǎn)擊動(dòng)作、
能識(shí)別TextView中的ClickableSpan
無障礙功能
findViewById() 返回類型由View改為<T extends View> T 覆蓋findViewById() 的地方需要相應(yīng)修改
從2019年1月7日起,將無法通過
LAST_TIME_CONTACTED
/TIMES_CONTACTED
/LAST_TIME_USED
/TIMES_USED
獲取聯(lián)系人使用情況
聯(lián)系人聯(lián)系情況獲取功能
AbstractCollection.removeAll(java.util.Collection)
/AbstractCollection.retainAll(java.util.Collection)
當(dāng)傳入?yún)?shù)為null時(shí)會(huì)報(bào)NullPointerException
集合操作
Target在8.0受到影響 可能受到影響的功能
瀏覽器ua會(huì)包含OPR有可能導(dǎo)致判斷是否Opera瀏覽器失效 根據(jù)ua判斷瀏覽器
Collections.sort()改為在List.sort()基礎(chǔ)上實(shí)現(xiàn),之前是恰好相反。
如果在List.sort()中調(diào)用Collections.sort()會(huì)產(chǎn)生死循環(huán)
集合排序
在遍歷的過程中進(jìn)行排序,現(xiàn)在使用無論使用List.sort()還是Collections.sort()都會(huì)報(bào)錯(cuò) 集合排序
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,667評(píng)論 25 709
  • 用兩張圖告訴你,為什么你的 App 會(huì)卡頓? - Android - 掘金 Cover 有什么料? 從這篇文章中你...
    hw1212閱讀 13,881評(píng)論 2 59
  • 現(xiàn)在刷著朋友圈,要是哪陣子看不到微商發(fā)的小廣告,估計(jì)大多數(shù)人會(huì)以為是不是自己的網(wǎng)絡(luò)出了問題。 漸漸地,微商成了我們...
    雪落硯閱讀 443評(píng)論 3 2
  • 如果你忘了我 我只能說沒關(guān)系 如果你真的忘了我 我也只能說沒關(guān)系 身命中的人來了去,去了又來 而我始終忘不了 有那...
    納蘭秋琪閱讀 274評(píng)論 0 0
  • 血染江山的畫 怎敵你眉間一點(diǎn)朱砂 覆了天下也罷 始終不過一場(chǎng)繁華 聽了許多古風(fēng)歌發(fā)現(xiàn)有些歌詞還是很美的 鴻雁托舊書...
    歸虞閱讀 3,699評(píng)論 0 8

友情鏈接更多精彩內(nèi)容