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 purposefinal 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);}@Overridepublic 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*/@UiThreadprivate 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*/@UiThreadprivate 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*/@UiThreadprivate 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"}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/81740.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux句柄数过多问题排查

以下是Linux句柄数过多问题的排查与解决方法整理&#xff1a; 一、检测句柄使用情况 1‌.查看系统限制‌ 单个进程限制&#xff1a;ulimit -n 系统级总限制&#xff1a;cat /proc/sys/fs/file-max 2‌.统计进程占用量‌ 查看指定进程&#xff1a;lsof -p <PID> | wc -…

matlab插值方法(简短)

在MATLAB中&#xff0c;可以使用interp1函数快速实现插值。以下代码展示了如何使用spline插值方法对给定数据进行插值&#xff1a; x1 [23,56]; y1 [23,56]; X 23:1:56*4; Y interp1(x1,y1,X,spline);% linear、 spline其中&#xff0c;x1和y1是已知数据点&#xff0c;X是…

时间筛掉了不够坚定的东西

2025年5月17日&#xff0c;16~25℃&#xff0c;还好 待办&#xff1a; 《高等数学1》重修考试 《高等数学2》备课 《物理[2]》备课 《高等数学2》取消考试资格学生名单 《物理[2]》取消考试资格名单 职称申报材料 2024年税务申报 5月24日、25日监考报名 遇见&#xff1a;敲了一…

hexo博客搭建使用

搭建 Hexo 演示主题为&#xff1a;Keep 使用 文章 创建新文章 ➜ zymore-blog-keep git:(main) ✗ hexo new "告别H5嵌入&#xff01;uniApp小程序文件下载与分享完整解决方案" INFO Validating config INFO Created: ~/Desktop/HelloWorld/zymore-blog-k…

React组件开发流程-03.1

此章先以一个完整的例子来全面了解下React组件开发的流程&#xff0c;主要是以代码为主&#xff0c;在不同的章节中会把重点标出来&#xff0c;要完成的例子如下&#xff0c;也可从官网中找到。 React组件开发流程 这只是一个通用流程&#xff0c;在熟悉后不需要完全遵从。 …

Cloudflare防火墙拦截谷歌爬虫|导致收录失败怎么解决?

许多站长发现网站突然从谷歌搜索结果中“消失”&#xff0c;背后很可能是Cloudflare防火墙误拦截了谷歌爬虫&#xff08;Googlebot&#xff09;&#xff0c;导致搜索引擎无法正常抓取页面。 由于Cloudflare默认的防护规则较为严格&#xff0c;尤其是针对高频访问的爬虫IP&…

Ubuntu系统安装VsCode

在Linux系统中&#xff0c;可以通过.deb文件手动安装Visual Studio Code&#xff08;VS Code&#xff09;。以下是详细的安装步骤&#xff1a; 下载.deb文件 访问Visual Studio Code的官方网站。 在下载页面中&#xff0c;找到适用于Linux的.deb文件。 根据你的系统架构&…

降本增效双突破:Profinet转Modbus TCP助力包布机产能与稳定性双提升

在现代工业自动化领域&#xff0c;ModbusTCP和Profinet是两种常见的通讯协议。它们在数据传输、设备控制等方面有着重要作用。然而&#xff0c;由于这两种协议的工作原理和应用环境存在差异&#xff0c;直接互联往往会出现兼容性问题。此时&#xff0c;就需要一种能够实现Profi…

Python对JSON数据操作

在Python中&#xff0c;对JSON数据进行增删改查及加载保存操作&#xff0c;主要通过内置的json模块实现。 一、基础操作 1. 加载JSON数据 • 从文件加载 使用json.load()读取JSON文件并转换为Python对象&#xff08;字典/列表&#xff09;&#xff1a; import json with open…

Linux详解基本指令(一)

✨✨ 欢迎大家来到小伞的大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;LInux_st 小伞的主页&#xff1a;xiaosan_blog 制作不易&#xff01;点个赞吧&#xff01;&#xff01;谢谢喵&#xff01;&a…

Node-Red通过Profinet转ModbusTCP采集西门子PLC数据配置案例

一、内容简介 本篇内容主要介绍Node-Red通过node-red-contrib-modbus插件与ModbusTCP设备进行通讯&#xff0c;这里Profinet转ModbusTCP网关作为从站设备&#xff0c;Node-Red作为主站分别从0地址开始读取10个线圈状态和10个保持寄存器&#xff0c;分别用Modbus-Read、Modbus-…

React方向:react的基本语法-数据渲染

1、安装包(js库) yarn add babel-standalone react react-dom 示例图.png 2、通过依赖包导入js库文件 <script src"../node_modules/babel-standalone/babel.js"></script> <script src"../node_modules/react/umd/react.development.js"&g…

k8s部署grafana

部署成功截图&#xff1a; 要在 Kubernetes (K8s) 集群中拉取 Grafana 镜像并创建 Grafana 容器&#xff0c;您可以按照以下步骤使用命令行完成操作。下面是完整的命令步骤&#xff0c;包括如何创建 Deployment 和 Service&#xff0c;以及如何将 Grafana 容器暴露给外部。1. 创…

基于注意力机制与iRMB模块的YOLOv11改进模型—高效轻量目标检测新范式

随着深度学习技术的发展,目标检测在自动驾驶、智能监控、工业质检等场景中得到了广泛应用。针对当前主流目标检测模型在边缘设备部署中所面临的计算资源受限和推理效率瓶颈问题,YOLO系列作为单阶段目标检测框架的代表,凭借其高精度与高速度的平衡优势,在工业界具有极高的应…

uniapp运行到微信开发者工具报错“更改appid失败touristappidError:tourist appid”

原因分析 因为项目还没配置自己的 小程序 AppID&#xff0c;导致微信开发者工具拒绝运行。 解决办法&#xff1a;在 HBuilderX 中设置 AppID 打开你的项目 在左侧找到并点击 manifest.json 文件 切换到上方的 tab&#xff1a;「小程序配置」标签页 找到微信小程序区域&#…

使用Thrust库实现异步操作与回调函数

文章目录 使用Thrust库实现异步操作与回调函数基本异步操作插入回调函数更复杂的回调示例注意事项 使用Thrust库实现异步操作与回调函数 在Thrust库中&#xff0c;你可以通过CUDA流(stream)来实现异步操作&#xff0c;并在适当的位置插入回调函数。以下是如何实现的详细说明&a…

mysql-Java手写分布式事物提交流程

准备 innodb存储引擎开启支持分布式事务 set global innodb_support_axon分布式的流程 详细流程&#xff1a; XA START ‘a’; 作用&#xff1a;开始一个新的XA事务&#xff0c;并分配一个唯一的事务ID ‘a’。 说明&#xff1a;在这个命令之后&#xff0c;所有后续的SQL操…

算法练习:19.JZ29 顺时针打印矩阵

错误原因 总体思路有&#xff0c;但不够清晰&#xff0c;一直在边调试边完善。这方面就养成更好的构思习惯&#xff0c;以及涨涨经验吧。 分析&#xff1a; 思路&#xff1a;找规律 两个坑&#xff1a; 一次循环的后半段是倒着遍历的是矩阵不是方阵&#xff0c;要考虑行列…

计算机组成与体系结构:缓存设计概述(Cache Design Overview)

目录 Block Placement&#xff08;块放置&#xff09; Block Identification&#xff08;块识别&#xff09; Block Replacement&#xff08;块替换&#xff09; Write Strategy&#xff08;写策略&#xff09; 总结&#xff1a; 高速缓存设计包括四个基础核心概念&#xf…

Tomcat多应用部署与静态资源路径问题全解指南

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家、CSDN平台优质创作者&#xff0c;高级开发工程师&#xff0c;数学专业&#xff0c;10年以上C/C, C#, Java等多种编程语言开发经验&#xff0c;拥有高级工程师证书&#xff1b;擅长C/C、C#等开发语言&#xff0c;熟悉Java常用开…