android - 有什么方法可以检测到哪些应用程序我可以/不能访问他们的 "app-info"屏幕?

标签 android android-applicationinfo package-info

背景
您可以使用 PackageManager.getInstalledPackages 获取已安装应用程序的列表.
而且,您可以通过以下方式访问每个应用程序的应用程序信息屏幕:

val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:$appPackageName"))
startActivity(intent)
例子:
enter image description here
问题
问题是,我注意到(在有人告诉我之后)对于某些应用程序,您无法访问他们的应用程序信息屏幕。这些应用程序的此类包名称示例:“com.google.android.ext.services”(“Android 服务库”)、“com.google.mainline.tememetry”(“支持组件”)、com.google.android .modulemetadata”(主要组件”)。也许更多。
向 Google 报告后,我是 told :

com.google.android.ext.services is mainline module, so Settings doesn't provide detail app info for it.


我试过的
我尝试查看 PackageInfo 和 ApplicationInfo 的各个领域和功能。
我找到了“isApex”,但它似乎总是错误的,the docs根本无助于理解它是什么(“该包是否为 APEX 包”)。编辑:如果我检查 API 30,它总是错误的。在 API 29 上,它实际上有时设置为 true。举报here .
我还发现了一个名为 "coreApp"的私有(private) bool 字段(我可以通过反射访问),确实有时它是真的,但并不总是当它是真的时,这意味着我无法访问它的应用程序信息屏幕。
这是获取它的代码:
    fun isProbablyCoreApp(packageInfo: PackageInfo): Boolean {
        return try {
            val field = PackageInfo::class.java.getField("coreApp")
            field.getBoolean(packageInfo)
        } catch (e: Throwable) {
            false
        }
    }
问题
  • “主线模块”是什么意思?它是操作系统的一部分,可以自行更新吗?与Android 10及以上的“项目主线”有关?
  • 为什么我无法访问其应用信息?这不是一个真正的应用程序?但如果不是,它怎么会被列为应用程序列表的一部分?
  • 有什么方法可以检测到已安装的应用程序实际上是一个您无法访问其应用程序信息屏幕的模块?操作系统的 UI 如何从其列表中过滤掉这些应用程序?
  • 是否还有更多我无法访问其应用信息屏幕的应用案例?
  • 最佳答案

    调用 startActivity()失败了。理想情况下,我们会将该调用追溯到 Android 系统,并找出它为什么无法获取一些可能导致修复的信息。取而代之的是,我提出以下可能的解决方案。
    我正在假设所有已安装的软件包都可以显示“apps-info”屏幕,除非该软件包是 hidden 的模块。 .
    我查看了一个运行 API 30 的 Android 模拟器,并进行了上述检查。我不相信这个理论在所有情况下都有效。您提到"file"应用程序是一个问题。此应用程序显示为一个模块,但不在您建议的已安装应用程序列表中。更新的代码解决了这个问题。
    我已经组装了一个小应用程序,可以根据上述类别测试是否创建了应用程序信息屏幕。我已将其包含在此处以供进一步查看。代码中的注释解释了应用程序的工作原理。

    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)
        }
    }
    

    关于android - 有什么方法可以检测到哪些应用程序我可以/不能访问他们的 "app-info"屏幕?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64063465/

    相关文章:

    android - 提取我手机上最后安装的应用程序的包名

    android - Android 中的 ApplicationInfo 适配器仅显示具有启动器 Intent 的应用程序

    android-activity - Activity 有一个名为 getTaskId() 的方法。我如何知道此任务 ID 是否与应用程序任务堆栈的任务 ID 匹配?

    hibernate - package-info.java 中的 @GenericGenerator 不工作 JPA

    java - Android中制作一个public类型的人脸方法

    android - BottomSheets 的侧滑画廊?

    android - 关于 "DONT_DELETE_DATA"的一些问题,它是如何工作的,以及应用程序如何使用它

    java - JAXB package-info.java 声明在单独的 Maven 模块中被忽略

    android - 如何控制用户构建中的详细日志?

    android 如何使用 Retrofit 库发布 ByteArray?