解决Android 应用targetSdkVersion小于24(Android N)运行在高版本设备无法全屏的BUG

前言

进行公司车机设备开发时,由于屏幕比例比较特殊(1920x720),导致部分应用显示时左侧和底部有很大的黑边,使用dumpsys分析黑边的View,移除后发现仍存在,后确定为低版本默认比例问题,耗费了几个小时,记录下这个问题。

出现问题的条件:

  1. Android 应用:targetSdkVersion < 24 (Android N);
  2. 设备的分辨率宽高比大于1.861.86为Android低版本最大宽高比);
  3. Android 应用的AndroidManifest.xml内未设置android:resizeableActivity="true"属性;

问题解决方案

问题根据不同的情况有不同的解决方式

  1. 若拥有应用源码,则可以直接将targetSdkVersion设置为大于等于24即可;
  2. 若拥有应用源码,但不能修改targetSdkVersion版本,那么就在
    应用的AndroidManifest.xml内设置android:resizeableActivity="true"属性;
  3. 若拥有应用源码,但不能修改targetSdkVersion版本,但compileSdkVersion=26时,
    可以尝试在的AndroidManifest.xml内设置android:maxAspectRatio=""="宽高比"属性;
  4. 若没有应用源码,则需要尝试修改系统层来达到适配的作用,具体修改见如下代码:

系统层修改

/frameworks/base/core/java/android/content/pm/PackageParser.java
PackageParser在解析APKAndroidManifest.xml文件时,有如下代码:

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);
        ....
        
        // 这里会去判断xml内是否有设置android:resizeableActivity属性
        if (sa.hasValueOrEmpty(R.styleable.AndroidManifestApplication_resizeableActivity)) {
            if (sa.getBoolean(R.styleable.AndroidManifestApplication_resizeableActivity, true)) {
                // 设置该标志位后,应用的Activity可调整大小
                ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE;
            } else {
                // 设置该标志位后,应用的Activity不可调整大小
                ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE;
            }
        } else if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N) {
            // 若应用未设置android:resizeableActivity属性,且其targetSdkVersion >= Android N (24)
            // 设置该标志位后,应用的Activity可调整大小
            ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
-       }
+        }else {
+            ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE;
+        }
      
    }
    
}

根据以上代码可以看到,默认情况下没有对未设置android:resizeableActivity属性,且targetSdkVersion < 24的应用不会设置其Activity可调整大小,所以我们需要为这种情况加上对应的配置,即添加上述代码中的相应内容。修改后编译进设备,即可看到应用全屏显示了。

问题分析

除了上面分析到的没有Activity可调整大小标志位导致的无法全屏问题,还有一个是关于默认最大宽高比(DEFAULT_PRE_O_MAX_ASPECT_RATIO)的问题,通过修改该值也可以实现应用的全屏,不过有时候屏幕比例变化较大时该值可能要经常改动,有点麻烦。下面主要是从源码来分析下该值是如何起作用的。
/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) {
        // 对于 O 之前的应用程序默认为 (1.86) 16.7:9 纵横比,对于 O 及更高版本则未设置。
        float maxAspectRatio = owner.applicationInfo.targetSdkVersion < O
                ? DEFAULT_PRE_O_MAX_ASPECT_RATIO : 0;

        if (owner.applicationInfo.maxAspectRatio != 0) {
            // 如果应用设置了android:maxAspectRatio 属性值,则使用应用程序所配置的最大宽高比。
            maxAspectRatio = owner.applicationInfo.maxAspectRatio;
        } else if (owner.mAppMetaData != null
                && owner.mAppMetaData.containsKey(METADATA_MAX_ASPECT_RATIO)) {
            // 未设置则设置为默认的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设置的maxAspectRatio属性,若应用和activity都设置了,则以activity的优先
            final float activityAspectRatio = activity.metaData != null
                    ? activity.metaData.getFloat(METADATA_MAX_ASPECT_RATIO, maxAspectRatio)
                    : maxAspectRatio;
            // 将最大宽高比设置给activity
            activity.setMaxAspectRatio(activityAspectRatio);
        }
    }
}

以上就是为何应用无法全屏显示的原因,以及另外一种修改为何也能生效的原因。


 

在uniapp开发Android应用时,遇到"fail targetSdkVersion设置>=29后在Android 10+系统设备上不支持当前路径,需要更改为应用运行路径"的问题,主要是由于从API 29(Android 10)开始,Android引入了更严格的文件访问权限控制。要解决这个问题,你可以按照以下步骤操作: 1. **更新`targetSdkVersion`**:确保你的项目`build.gradle`(Module: app)中的`android`部分设置了适当的`targetSdkVersion`,通常建议保持在最新版本或兼容版本,例如`targetSdkVersion 30`或`android.compileSdkVersion 30`。 ```groovy android { compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } // ...其他配置... defaultConfig { // 更改这里 minSdkVersion '21' targetSdkVersion 30 // 其他配置项... } } ``` 2. **处理存储路径**:使用Android的`ContextCompat.getExternalFilesDir()` 或 `getExternalCacheDir()` 方法获取外部存储的指定目录,而不是硬编码绝对路径。这样可以在Android API 29及以上系统中动态获取受支持的路径。 ```java File cacheDirectory = getApplicationContext().getExternalCacheDir(); String cachePath = cacheDirectory.getAbsolutePath(); ``` 3. **申请权限**:如果应用程序需要读取或写入特定路径,记得在`AndroidManifest.xml`中添加`READ_EXTERNAL_STORAGE` 和/或 `WRITE_EXTERNAL_STORAGE` 权限,并在运行时请求权限。 ```xml <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> ``` 4. **处理用户反馈**:对于API 29及更高版本,当提示用户权限不足时,引导用户去设置页面允许应用访问外部存储。 完成上述步骤后,你的uniapp应用应该能在Android 10+设备上正常运行,同时遵循最新的安全规范。如果你的应用仍存在问题,记得检查日志和官方文档以获得更精确的解决方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值