Android14中《此应用专为旧版 Android 系统打造...》弹窗

问题

测试机升级到Android14后,当打开应用时,会出现一个弹窗,弹窗信息如下图:

刚开始点击确认之后,后面并不会出现也就没去管,然而,在我执行benchmark的Startup测试的时候,每次都会提醒而影响测试。这事必须得解决。

原因

通过搜索,很多文章都提到一个方法showDeprecatedTargetDialogIfNeeded()。可以根据这个方法展开去了解。

定位

这是一个简单的定位过程:

  1. 打开platform_frameworks_base这个仓库。
  2. 作为Android开发者,都知道硬编码的字符串是存在res目录下的strings.xml文件中,笔者系统默认英文,直接找默认的文件即可,目录为platform_frameworks_base/core/res/res/values/strings.xml,不同语言根据不同目录去找。
  3. 在strings.xml文件中找对对应字符串的那行 <string name="deprecated_target_sdk_message">This app was built for an older version...,从而得知key为deprecated_target_sdk_message
  4. 使用Github Command Palette查找key,找到对应使用的代码。搜索结果右边有个Paths的section可以看到只有一个是java代码的,点击它便可看到调用的代码。
  5. 这时候你应该看到DeprecatedTargetSdkVersionDialog.java文件了,双击该类名,右侧可以看到References(引用),点击调用方法进入对应代码块。
  6. 这时候你应该是在AppWarnings.java文件中,继续根据引用链,最后也一样找到showDeprecatedTargetDialogIfNeeded()方法

为什么会出现这个弹窗

 public void showDeprecatedTargetDialogIfNeeded(ActivityRecord r) {
    if (r.info.applicationInfo.targetSdkVersion < Build.VERSION.MIN_SUPPORTED_TARGET_SDK_INT) {
        mUiHandler.showDeprecatedTargetDialog(r);
    }
}

根据applicationInfo.targetSdkVersionBuild.VERSION.MIN_SUPPORTED_TARGET_SDK_INT判断是否执行警告弹窗代码,那这两个玩意是什么呢?

// 来自
/**
 * The minimum SDK version this application targets.  It may run on earlier
 * versions, but it knows how to work with any new behavior added at this
 * version.  Will be {@link android.os.Build.VERSION_CODES#CUR_DEVELOPMENT}
 * if this is a development build and the app is targeting that.  You should
 * compare that this number is >= the SDK version number at which your
 * behavior was introduced.
 */
public int targetSdkVersion;

// 来自Build.java
public static final int MIN_SUPPORTED_TARGET_SDK_INT = SystemProperties.getInt(
                "ro.build.version.min_supported_target_sdk", 0);

注释很清楚,applicationInfo.targetSdkVersion就是我们配置的min SDK。而MIN_SUPPORTED_TARGET_SDK_INT是一个System配置中key为ro.build.version.min_supported_target_sdk的属性,其中Android14中配置为28
ro.build.version.min_supported_target_sdk in line42

为什么只提醒一次

以下是两个相关代码块,注释部分则可以表示同一个包只会出现一次弹窗的原因

DeprecatedTargetSdkVersionDialog(final AppWarnings manager, Context context,
            ApplicationInfo appInfo) {
    super(manager, appInfo.packageName);
    ...
    final CharSequence message = context.getString(R.string.deprecated_target_sdk_message);

    final AlertDialog.Builder builder = new AlertDialog.Builder(context)
            .setPositiveButton(R.string.ok, (dialog, which) ->
            // 设置 package flag
                manager.setPackageFlag(
                        mPackageName, AppWarnings.FLAG_HIDE_DEPRECATED_SDK, true))
            .setMessage(message)
            .setTitle(label);

    ...
}

@UiThread
private void showDeprecatedTargetSdkDialogUiThread(ActivityRecord ar) {
    if (mDeprecatedTargetSdkVersionDialog != null) {
        mDeprecatedTargetSdkVersionDialog.dismiss();
        mDeprecatedTargetSdkVersionDialog = null;
    }
    // 根据package flag 判断是否弹出
    if (ar != null && !hasPackageFlag(
            ar.packageName, FLAG_HIDE_DEPRECATED_SDK)) {
        mDeprecatedTargetSdkVersionDialog = new DeprecatedTargetSdkVersionDialog(
                AppWarnings.this, mUiContext, ar.info.applicationInfo);
        mDeprecatedTargetSdkVersionDialog.show();
    }
}

解决问题

我们知道这个弹窗的流程并了解其判断条件了,解决问题自然简单,简单把我们min SDK改成28或更高就可以了。再执行benchmark测试,没有再出现这个弹窗,问题解决。