如何解决有什么方法可以检测我无法/无法访问其“应用程序信息”屏幕的应用程序?
背景
您可以使用PackageManager.getInstalledPackages获取已安装应用程序的列表。
而且,您可以通过以下方式访问每个应用程序的应用程序信息屏幕:
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,Uri.parse("package:$appPackageName"))
startActivity(intent)
示例:
问题
问题是,我注意到(在某人告诉我之后),对于某些应用程序,您无法访问其应用程序信息屏幕。这些应用程序的此类软件包名称的示例:“ com.google.android.ext.services”(“ Android服务库”),“ com.google.mainline.tememetry”(“支持组件”),com.google.android .moduleMetadata”(“主要组件”)。也许更多。
向Google报告后,我是told:
com.google.android.ext.services是主线模块,因此“设置”不会为其提供详细的应用信息。
我尝试过的事情
我试图查看PackageInfo和ApplicationInfo的各个字段和功能。
我已经找到了“ isApex”,但是它似乎总是错误的,the docs根本就不了解它的含义(“该程序包是否为APEX程序包”)。编辑:如果我在API 30上进行检查,则始终为false。在API 29上,实际上有时将其设置为true。已报告here。
我还找到了一个名为“ coreApp”的私有布尔字段(可以通过反射到达),确实有时是正确的,但并非总是如此,这意味着我无法访问它的app-信息屏幕。
这是获得它的代码:
fun isProbablyCoreApp(packageInfo: PackageInfo): Boolean {
return try {
val field = PackageInfo::class.java.getField("coreApp")
field.getBoolean(packageInfo)
} catch (e: Throwable) {
false
}
}
问题
- “主模块”是什么意思?它是操作系统的一部分,可以自行更新吗?与Android 10及更高版本的“项目主线”相关吗?
- 为什么我无法访问其应用信息?这不是一个真正的应用程序?但是,如果没有,它怎么会被列为应用程序列表的一部分?
- 是否有任何方法可以检测到已安装的应用程序实际上是您无法访问其应用程序信息屏幕的模块?操作系统的用户界面如何从列表中过滤掉那些应用程序?
- 是否还有更多我无法访问其应用信息屏幕的应用案例?
解决方法
对startActivity()
的调用失败。理想情况下,我们将跟踪该调用到Android系统中,并找出为什么它无法获取可能导致修复的信息。取而代之的是,我提出以下方案作为可能解决方案。
我正在假设所有已安装的软件包都可以显示“ apps-info”屏幕,除非该软件包是hidden的模块。
我看过一个运行API 30的Android模拟器,并且前面已经提到了。我不相信这种理论在所有情况下都是有效的。您提到“文件”应用是一个问题。该应用程序显示为模块,但未显示在您建议的已安装应用程序列表中。更新的代码解决了这个问题。
我整理了一个小应用程序,可以根据上述类别测试是否创建了应用程序信息屏幕。我将其包括在此处以作进一步查看。代码中的注释说明了该应用程序的工作方式。
class MainActivity : AppCompatActivity() {
private var mActivitiesStarted = 1 // This activity counts.
@RequiresApi(Build.VERSION_CODES.Q)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val modulesByPackageName = packageManager.getInstalledModules(MATCH_ALL)
.asSequence()
.filter { it.packageName != null } // packageName can be null according to the docs.
.associate { moduleInfo -> Pair(moduleInfo.packageName,moduleInfo.isHidden) }
// Comment/uncomment code in different paths to start apps-info activities for the
// various categories of packages/modules.
val installedByPackageName = mutableSetOf<String>()
packageManager.getInstalledPackages(0).forEach {
installedByPackageName.add(it.packageName)
when (modulesByPackageName[it.packageName]) {
true -> {
// Package is a module that is hidden. We should not be able to get to apps-info.
// Unfortunately,for testing,the activity will start but the apps-info
// screen will not display. This condition cannot be tested through a count
// of activities.
Log.d(
"MainActivity","<<<<Can't reach app-info for ${it.packageName} (hidden module)"
)
// This will fail to display but the activity will start.
// startAppsInfo(it.packageName)
}
false -> {
// Package is a module that is not hidden. We should be able to get to apps-info.
Log.d(
"MainActivity","<<<<Can reach app-info for ${it.packageName} (not hidden module)"
)
// This should be successful.
startAppsInfo(it.packageName)
mActivitiesStarted++
}
else -> {
// Package is not a module. We should be able to get to apps-info.
Log.d(
"MainActivity","<<<<Can reach app-info for ${it.packageName} (not module)"
)
// This should be successful.
startAppsInfo(it.packageName)
mActivitiesStarted++
}
}
}
// Look at modules that are not hidden but do not appear in the installed packages list.
// This should pick up modules like com.google.android.documentsui (Files).
modulesByPackageName.filter { !it.value && !installedByPackageName.contains(it.key) }
.forEach {
Log.d(
"MainActivity","<<<<Can reach app-info for ${it.key} (module but not in installed packages)"
)
// This should be successful.
startAppsInfo(it.key!!)
mActivitiesStarted++
}
// Check that we started the number of activities that we expected. Post to ensure that
// all activities start and can be counted.
Handler(Looper.getMainLooper()).post {
val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
// getRunningTasks is deprecated,but it still returns tasks for the current app.
val runningTasks = activityManager.getRunningTasks(Integer.MAX_VALUE)
val numActivities = runningTasks[0].numActivities
Log.d(
"MainActivity","<<<<activitiesStarted=$mActivitiesStarted numActivities=$numActivities"
)
}
}
private fun startAppsInfo(appPackageName: String) {
val intent = Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,Uri.parse("package:$appPackageName")
)
startActivity(intent)
}
}
,
“主模块”的含义可能在这里解释:Modular System Components。
如果这些应该是唯一具有这种(非通用应用程序)行为的程序,则可以通过其程序包名称来识别它们。这些将是所有要过滤的软件包名称:
com.google.android.adbd
com.android.runtime.release.apex
com.android.captiveportallogin
com.google.android.cellbroadcast
com.android.conscrypt
com.android.resolv
com.android.documentsui
com.android.ext.services
com.google.android.ipsec
com.android.media.swcodec
com.android.media
com.google.android.mediaprovider
com.android.modulemetadata
com.android.networkstack.permissionconfig
com.android.networkstack
com.google.android.neuralnetworks
com.android.permissioncontroller
com.android.sdkext
com.google.android.os.statsd
com.google.mainline.telemetry
com.google.android.tethering
com.android.tzdata
com.google.android.wifi.apex
目前我没有时间进行概念验证,但信息似乎可靠。isApex
仅应针对其中的某些true
(如文档所建议的那样),因此不能用于标识它们,但包名称是可以使用的可靠标准。
字符串比较可能不是预期的答案,但是还有更好的标准吗?
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。