前言
進(jìn)行公司車(chē)機(jī)設(shè)備開(kāi)發(fā)時(shí)挽拔,由于屏幕比例比較特殊(1920x720)英融,導(dǎo)致部分應(yīng)用顯示時(shí)左側(cè)和底部有很大的黑邊,使用dumpsys分析黑邊的View摩骨,移除后發(fā)現(xiàn)仍存在屁置,后確定為低版本默認(rèn)比例問(wèn)題焊夸,耗費(fèi)了幾個(gè)小時(shí),記錄下這個(gè)問(wèn)題蓝角。
出現(xiàn)問(wèn)題的條件:
- Android 應(yīng)用:targetSdkVersion < 24 (Android N)阱穗;
- 設(shè)備的分辨率寬高比大于1.86(1.86為Android低版本最大寬高比);
- Android 應(yīng)用的AndroidManifest.xml內(nèi)未設(shè)置android:resizeableActivity="true"屬性使鹅;
問(wèn)題解決方案
問(wèn)題根據(jù)不同的情況有不同的解決方式
- 若擁有應(yīng)用源碼揪阶,則可以直接將targetSdkVersion設(shè)置為大于等于24即可;
- 若擁有應(yīng)用源碼患朱,但不能修改targetSdkVersion版本鲁僚,那么就在
應(yīng)用的AndroidManifest.xml內(nèi)設(shè)置android:resizeableActivity="true"屬性; - 若擁有應(yīng)用源碼裁厅,但不能修改targetSdkVersion版本冰沙,但compileSdkVersion=26時(shí),
可以嘗試在的AndroidManifest.xml內(nèi)設(shè)置android:maxAspectRatio=""="寬高比"屬性执虹; - 若沒(méi)有應(yīng)用源碼拓挥,則需要嘗試修改系統(tǒng)層來(lái)達(dá)到適配的作用,具體修改見(jiàn)如下代碼:
系統(tǒng)層修改
/frameworks/base/core/java/android/content/pm/PackageParser.java
PackageParser在解析APK的AndroidManifest.xml文件時(shí)声畏,有如下代碼:
public class PackageParser {
....
private static final float DEFAULT_PRE_O_MAX_ASPECT_RATIO = 1.86f;
....
private boolean parseBaseApplication(Package owner, Resources res,
XmlResourceParser parser, int flags, String[] outError)
throws XmlPullParserException, IOException {
final ApplicationInfo ai = owner.applicationInfo;
final String pkgName = owner.applicationInfo.packageName;
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifestApplication);
....
// 這里會(huì)去判斷xml內(nèi)是否有設(shè)置android:resizeableActivity屬性
if (sa.hasValueOrEmpty(R.styleable.AndroidManifestApplication_resizeableActivity)) {
if (sa.getBoolean(R.styleable.AndroidManifestApplication_resizeableActivity, true)) {
// 設(shè)置該標(biāo)志位后撞叽,應(yīng)用的Activity可調(diào)整大小
ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE;
} else {
// 設(shè)置該標(biāo)志位后姻成,應(yīng)用的Activity不可調(diào)整大小
ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE;
}
} else if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N) {
// 若應(yīng)用未設(shè)置android:resizeableActivity屬性,且其targetSdkVersion >= Android N (24)
// 設(shè)置該標(biāo)志位后愿棋,應(yīng)用的Activity可調(diào)整大小
ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
- }
+ }else {
+ ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE;
+ }
}
}
根據(jù)以上代碼可以看到科展,默認(rèn)情況下沒(méi)有對(duì)未設(shè)置android:resizeableActivity屬性,且targetSdkVersion < 24的應(yīng)用不會(huì)設(shè)置其Activity可調(diào)整大小糠雨,所以我們需要為這種情況加上對(duì)應(yīng)的配置才睹,即添加上述代碼中的相應(yīng)內(nèi)容。修改后編譯進(jìn)設(shè)備甘邀,即可看到應(yīng)用全屏顯示了琅攘。
問(wèn)題分析
除了上面分析到的沒(méi)有Activity可調(diào)整大小標(biāo)志位導(dǎo)致的無(wú)法全屏問(wèn)題,還有一個(gè)是關(guān)于默認(rèn)最大寬高比(DEFAULT_PRE_O_MAX_ASPECT_RATIO)的問(wèn)題松邪,通過(guò)修改該值也可以實(shí)現(xiàn)應(yīng)用的全屏坞琴,不過(guò)有時(shí)候屏幕比例變化較大時(shí)該值可能要經(jīng)常改動(dòng),有點(diǎn)麻煩逗抑。下面主要是從源碼來(lái)分析下該值是如何起作用的剧辐。
/frameworks/base/core/java/android/content/pm/PackageParser.java
public class PackageParser {
....
private static final float DEFAULT_PRE_O_MAX_ASPECT_RATIO = 1.86f;
....
private void setMaxAspectRatio(Package owner) {
// 對(duì)于 O 之前的應(yīng)用程序默認(rèn)為 (1.86) 16.7:9 縱橫比,對(duì)于 O 及更高版本則未設(shè)置邮府。
float maxAspectRatio = owner.applicationInfo.targetSdkVersion < O
? DEFAULT_PRE_O_MAX_ASPECT_RATIO : 0;
if (owner.applicationInfo.maxAspectRatio != 0) {
// 如果應(yīng)用設(shè)置了android:maxAspectRatio 屬性值荧关,則使用應(yīng)用程序所配置的最大寬高比。
maxAspectRatio = owner.applicationInfo.maxAspectRatio;
} else if (owner.mAppMetaData != null
&& owner.mAppMetaData.containsKey(METADATA_MAX_ASPECT_RATIO)) {
// 未設(shè)置則設(shè)置為默認(rèn)的1.86
maxAspectRatio = owner.mAppMetaData.getFloat(METADATA_MAX_ASPECT_RATIO, maxAspectRatio);
}
for (Activity activity : owner.activities) {
// If the max aspect ratio for the activity has already been set, skip.
if (activity.hasMaxAspectRatio()) {
continue;
}
// 這里可以獲取activity設(shè)置的maxAspectRatio屬性褂傀,若應(yīng)用和activity都設(shè)置了忍啤,則以activity的優(yōu)先
final float activityAspectRatio = activity.metaData != null
? activity.metaData.getFloat(METADATA_MAX_ASPECT_RATIO, maxAspectRatio)
: maxAspectRatio;
// 將最大寬高比設(shè)置給activity
activity.setMaxAspectRatio(activityAspectRatio);
}
}
}
以上就是為何應(yīng)用無(wú)法全屏顯示的原因,以及另外一種修改為何也能生效的原因仙辟。