Android 14 解决打开app出现不兼容弹窗的问题

应用安装到 Android 14 上,出现如下提示

This app isn't compatible with the latest version of Android. Check for an update or contact the app's developer.

通过源码找原因。

提示的字符

根据字符找到 ./frameworks/base/core/res/res/values/strings.xml

复制代码
<!-- Message displayed in dialog when app is 32 bit on a 64 bit system. [CHAR LIMIT=NONE] -->
<string name="deprecated_abi_message">This app isn\'t compatible with the latest version of Android. Check for an update or contact the app\'s developer.</string>

对应的中文 ./frameworks/base/core/res/res/values-zh-rCN/strings.xml

复制代码
<string name="deprecated_abi_message" msgid="6820548011196218091">"此应用与最新版 Android 不兼容。请检查是否有更新,或与应用开发者联系。"</string>

DeprecatedAbiDialog

弹窗UI在 ./frameworks/base/services/core/java/com/android/server/wm/DeprecatedAbiDialog.java

复制代码
package com.android.server.wm;

import android.app.AlertDialog;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.view.Window;
import android.view.WindowManager;

import com.android.internal.R;

class DeprecatedAbiDialog extends AppWarnings.BaseDialog {
    DeprecatedAbiDialog(final AppWarnings manager, Context context,
            ApplicationInfo appInfo) {
        super(manager, appInfo.packageName);

        final PackageManager pm = context.getPackageManager();
        final CharSequence label = appInfo.loadSafeLabel(pm,
                PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX,
                PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE
                        | PackageItemInfo.SAFE_LABEL_FLAG_TRIM);
        final CharSequence message = context.getString(R.string.deprecated_abi_message);

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

        // Ensure the content view is prepared.
        mDialog = builder.create();
        mDialog.create();

        final Window window = mDialog.getWindow();
        window.setType(WindowManager.LayoutParams.TYPE_PHONE);

        // DO NOT MODIFY. Used by CTS to verify the dialog is displayed.
        window.getAttributes().setTitle("DeprecatedAbiDialog");
    }
}

AppWarnings

调用到 DeprecatedAbiDialog 的是 ./frameworks/base/services/core/java/com/android/server/wm/AppWarnings.java

showDeprecatedAbiDialogIfNeeded

很显然,如果设备是64位的,但是app只有32位的so库,就会出现这个弹窗。

还可以看到,可以通过调试的方法,关闭这个弹窗检测。

setprop debug.wm.disable_deprecated_abi_dialog true

复制代码
    /**
     * Shows the "deprecated abi" warning, if necessary. This can only happen is the device
     * supports both 64-bit and 32-bit ABIs, and the app only contains 32-bit libraries. The app
     * cannot be installed if the device only supports 64-bit ABI while the app contains only 32-bit
     * libraries.
     *
     * @param r activity record for which the warning may be displayed
     */
    public void showDeprecatedAbiDialogIfNeeded(ActivityRecord r) {
        final boolean isUsingAbiOverride = (r.info.applicationInfo.privateFlagsExt
                & ApplicationInfo.PRIVATE_FLAG_EXT_CPU_OVERRIDE) != 0;
        if (isUsingAbiOverride) {
            // The abiOverride flag was specified during installation, which means that if the app
            // is currently running in 32-bit mode, it is intended. Do not show the warning dialog.
            return;
        }
        // The warning dialog can also be disabled for debugging purpose
        final boolean disableDeprecatedAbiDialog = SystemProperties.getBoolean(
                "debug.wm.disable_deprecated_abi_dialog", false);
        if (disableDeprecatedAbiDialog) {
            return;
        }
        final String appPrimaryAbi = r.info.applicationInfo.primaryCpuAbi;
        final String appSecondaryAbi = r.info.applicationInfo.secondaryCpuAbi;
        final boolean appContainsOnly32bitLibraries =
                (appPrimaryAbi != null && appSecondaryAbi == null && !appPrimaryAbi.contains("64"));
        final boolean is64BitDevice =
                ArrayUtils.find(Build.SUPPORTED_ABIS, abi -> abi.contains("64")) != null;
        if (is64BitDevice && appContainsOnly32bitLibraries) {
            mUiHandler.showDeprecatedAbiDialog(r);
        }
    }

showDeprecatedAbiDialogUiThread

handle 的处理,调用到 showDeprecatedAbiDialogUiThread

复制代码
	/**
     * Handles messages on the system process UI thread.
     */
    private final class UiHandler extends Handler {
        private static final int MSG_SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG = 1;
        private static final int MSG_HIDE_UNSUPPORTED_DISPLAY_SIZE_DIALOG = 2;
        private static final int MSG_SHOW_UNSUPPORTED_COMPILE_SDK_DIALOG = 3;
        private static final int MSG_HIDE_DIALOGS_FOR_PACKAGE = 4;
        private static final int MSG_SHOW_DEPRECATED_TARGET_SDK_DIALOG = 5;
        private static final int MSG_SHOW_DEPRECATED_ABI_DIALOG = 6;

        public UiHandler(Looper looper) {
            super(looper, null, true);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                //...
                case MSG_SHOW_DEPRECATED_ABI_DIALOG: {
                    final ActivityRecord ar = (ActivityRecord) msg.obj;
                    showDeprecatedAbiDialogUiThread(ar);
                } break;
            }
        }

        //...
    }

    /**
     * Shows the "deprecated abi" warning for the given application.
     * <p>
     * <strong>Note:</strong> Must be called on the UI thread.
     *
     * @param ar record for the activity that triggered the warning
     */
    @UiThread
    private void showDeprecatedAbiDialogUiThread(ActivityRecord ar) {
        if (mDeprecatedAbiDialog != null) {
            mDeprecatedAbiDialog.dismiss();
            mDeprecatedAbiDialog = null;
        }
        if (ar != null && !hasPackageFlag(
                ar.packageName, FLAG_HIDE_DEPRECATED_ABI)) {
            mDeprecatedAbiDialog = new DeprecatedAbiDialog(
                    AppWarnings.this, mUiContext, ar.info.applicationInfo);
            mDeprecatedAbiDialog.show();
        }
    }

拓展

来都来的,顺道看到了 DeprecatedTargetSdkVersionDialog 的逻辑处理,

复制代码
    /**
     * Shows the "deprecated target sdk" warning, if necessary.
     *
     * @param r activity record for which the warning may be displayed
     */
    public void showDeprecatedTargetDialogIfNeeded(ActivityRecord r) {
        if (r.info.applicationInfo.targetSdkVersion < Build.VERSION.MIN_SUPPORTED_TARGET_SDK_INT) {
            mUiHandler.showDeprecatedTargetDialog(r);
        }
    }

    /**
     * Shows the "deprecated target sdk version" warning for the given application.
     * <p>
     * <strong>Note:</strong> Must be called on the UI thread.
     *
     * @param ar record for the activity that triggered the warning
     */
    @UiThread
    private void showDeprecatedTargetSdkDialogUiThread(ActivityRecord ar) {
        if (mDeprecatedTargetSdkVersionDialog != null) {
            mDeprecatedTargetSdkVersionDialog.dismiss();
            mDeprecatedTargetSdkVersionDialog = null;
        }
        if (ar != null && !hasPackageFlag(
                ar.packageName, FLAG_HIDE_DEPRECATED_SDK)) {
            mDeprecatedTargetSdkVersionDialog = new DeprecatedTargetSdkVersionDialog(
                    AppWarnings.this, mUiContext, ar.info.applicationInfo);
            mDeprecatedTargetSdkVersionDialog.show();
        }
    }

如果 app 的 targetSdkVersion 版本低于平台支持的最小sdk版本(ro.build.version.min_supported_target_sdk),就会提示:

此应用专为旧版 Android 系统打造。它可能无法正常运行,也不包含最新的安全和隐私保护功能。请检查是否有更新,或与应用开发者联系。

对应的字符是 ./frameworks/base/core/res/res/values/strings.xml 里的 deprecated_target_sdk_message

复制代码
android$ cat ./frameworks/base/core/res/res/values-zh-rCN/strings.xml | grep deprecated_target_sdk_message
    <string name="deprecated_target_sdk_message" msgid="5246906284426844596">"此应用专为旧版 Android 系统打造。它可能无法正常运行,也不包含最新的安全和隐私保护功能。请检查是否有更新,或与应用开发者联系。"</string>
android$
android$ cat ./frameworks/base/core/res/res/values/strings.xml | grep deprecated_target_sdk_message
    <string name="deprecated_target_sdk_message">This app was built for an older version of Android. It might not work properly and doesn\'t include the latest security and privacy protections. Check for an update, or contact the app\'s developer.</string>

最终显示dialog

复制代码
    /**
     * Shows the "deprecated abi" warning for the given application.
     * <p>
     * <strong>Note:</strong> Must be called on the UI thread.
     *
     * @param ar record for the activity that triggered the warning
     */
    @UiThread
    private void showDeprecatedAbiDialogUiThread(ActivityRecord ar) {
        if (mDeprecatedAbiDialog != null) {
            mDeprecatedAbiDialog.dismiss();
            mDeprecatedAbiDialog = null;
        }
        if (ar != null && !hasPackageFlag(
                ar.packageName, FLAG_HIDE_DEPRECATED_ABI)) {
            mDeprecatedAbiDialog = new DeprecatedAbiDialog(
                    AppWarnings.this, mUiContext, ar.info.applicationInfo);
            mDeprecatedAbiDialog.show();
        }
    }

解决办法

使 app 支持64位的库。

修改 app 的 build.gradle , 添加 "arm64-v8a" ,

复制代码
      externalNativeBuild {
            cmake {
                //abiFilters "armeabi-v7a"
                abiFilters "armeabi-v7a","arm64-v8a"
                cppFlags "-std=c++11 -frtti -fexceptions"
                arguments "-DANDROID_STL=c++_static"
            }
        }
        ndk {
            //abiFilters "armeabi-v7a"
            abiFilters "armeabi-v7a","arm64-v8a"
            stl "stlport_shared"
        }
相关推荐
消失的旧时光-19436 分钟前
Android ble和经典蓝牙
android
李少兄1 小时前
IntelliJ IDEA 如何全局配置 Maven?避免每次打开新项目重新配置 (适用于 2024~2025 版本)
android·maven·intellij-idea
小蜜蜂嗡嗡2 小时前
【flutter报错:Build failed due to use of deprecated Android v1 embedding.】
android·flutter·embedding
杨筱毅2 小时前
【底层机制】Android GC -- 为什么要有GC?GC的核心原理?理解GC的意义
android·jvm·gc
用户69371750013842 小时前
⚡Kotlin 五大神器完全解析:let、with、run、apply、also 一次搞懂,面试官都笑了!
android·kotlin
QmDeve3 小时前
Android 使用液态玻璃(LiquidGlass)效果,真实的折射和色散效果
android·github
xhbh6663 小时前
【实战总结】MySQL日志文件位置大全:附查找脚本和权限解决方案
android·adb
Digitally3 小时前
6 种无误的方法:如何备份和恢复华为手机
android
ideaout技术团队4 小时前
android集成react native组件踩坑笔记(Activity局部展示RN的组件)
android·javascript·笔记·react native·react.js
shaominjin1235 小时前
单例模式:设计模式中的“独一无二“之道
android·单例模式·设计模式