最近項(xiàng)目升級(jí)targetSdkVersion,下面記錄下升級(jí)過程中遇到的問題:
問題1、targetSdkVersion 升級(jí)到27或以上,http資源或圖片訪問不了,報(bào)錯(cuò)Cleartext HTTP traffic to xxx not permitted
原因:Google官方要求android P及上設(shè)備網(wǎng)絡(luò)請(qǐng)求強(qiáng)制使用加密的請(qǐng)求,若使用非加密的明文http請(qǐng)求,會(huì)導(dǎo)致網(wǎng)絡(luò)請(qǐng)求失敗,https請(qǐng)求不受影響。
解決方法:
方法1 、將targetSdkVersion降到27或以下
方法2、將資源或網(wǎng)絡(luò)請(qǐng)求改成https
方法 3、在AndroidManifest application標(biāo)簽下配置android:usesCleartextTraffic="true"
問題2:targetSdkVersion 升級(jí)到 29及以上,在android Q的手機(jī)訪問相冊(cè)為空白,即使是有讀寫外存的權(quán)限,依然會(huì)拋出了類似下面的FileNotFoundException異常,Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied)
原因:androidQ(29)及以上默認(rèn)開啟了分區(qū)存儲(chǔ)機(jī)制。
解決方法:
1、方案一:把應(yīng)用的 targetSdkVersion設(shè)置為29以下(臨時(shí)過渡)
2、方案二:在AndroidManifest.xml的Application標(biāo)簽下設(shè)置 android:requestLegacyExternalStorage=“true”(臨時(shí)過渡)

3、方案三:通過Android SAF存儲(chǔ)訪問框架來(lái)訪問
4、方案四:分區(qū)存儲(chǔ)適配(官方推薦)
問題3:androidQ 沒有判斷是否有READ_PHONE_STATE權(quán)限,直接調(diào)用((TelephonyManager) context.
getSystemService(context.TELEPHONY_SERVICE)).getDeviceId() 會(huì)崩潰,升級(jí)之前只是會(huì)返回null。
解決方案:調(diào)用之前加權(quán)限判斷或try catch處理,或根據(jù)api版本判斷是否獲取deviceID(因?yàn)閍ndroid10即使有權(quán)限也獲取不到deviceid了)。
問題4. targetSdkVersion 升級(jí)到 27及以上,在android8.0設(shè)備上,透明主題的Activity配置固定方向后報(bào)"Only fullscreen activities can request orientation",targetSdkVersion26正常。
異常分析:
Entry ent = AttributeCache.instance().get(packageName,realTheme, com.android.internal.R.styleable.Window, userId);
final boolean translucent = ent != null && (ent.array.getBoolean(com.android.internal.R.styleable.Window_windowIsTranslucent, false)|| (!ent.array.hasValue(
com.android.internal.R.styleable.Window_windowIsTranslucent) && ent.array.getBoolean(com.android.internal.R.styleable.Window_windowSwipeToDismiss,false)));
fullscreen = ent != null && !ent.array.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating, false) && !translucent;
fullscreen = ent != null && !ActivityInfo.isTranslucentOrFloating(ent.array);
noDisplay = ent != null && ent.array.getBoolean(com.android.internal.R.styleable.Window_windowNoDisplay, false);
if (ActivityInfo.isFixedOrientation(requestedOrientation) && !fullscreen && appInfo.targetSdkVersion > O) {
throw new IllegalStateException("Only fullscreen activities can request orientation");
}
從以上27源碼可以看出同時(shí)滿足3個(gè)條件就會(huì)拋出異常
1、ActivityInfo.isFixedOrientation(requestedOrientation) 設(shè)置了固定方向
2、appInfo.targetSdkVersion > O appInfo.targetSdkVersion>26
3 、非全屏,包含一下三種情況均認(rèn)為非全屏
“windowIsTranslucent”為true;
“windowIsTranslucent”為false,但“windowSwipeToDismiss”為true;
“windowIsFloating“為true;
解決方案:
方案一:去除AndroidManifest中的固定方向設(shè)置
方案二:targetSdkVersion設(shè)置26
方案三:activity設(shè)置非透明
方案四:通過反射,讓系統(tǒng)繞過屏幕方向的檢測(cè),設(shè)置屏幕不固定
@Override
protected void onCreate(Bundle savedInstanceState) {
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O && isTranslucentOrFloating()) {
fixOrientation();
}
}
private boolean isTranslucentOrFloating(){
boolean isTranslucentOrFloating = false;
try {
int [] styleableRes = (int[]) Class.forName("com.android.internal.R$styleable").getField("Window").get(null);
final TypedArray ta = obtainStyledAttributes(styleableRes);
Method m = ActivityInfo.class.getMethod("isTranslucentOrFloating", TypedArray.class);
m.setAccessible(true);
isTranslucentOrFloating = (boolean)m.invoke(null, ta);
m.setAccessible(false);
} catch (Exception e) {
e.printStackTrace();
}
return isTranslucentOrFloating;
}
private boolean fixOrientation(){
try {
Field field = Activity.class.getDeclaredField("mActivityInfo");
field.setAccessible(true);
ActivityInfo o = (ActivityInfo)field.get(this);
o.screenOrientation = -1;
field.setAccessible(false);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}