23

背景

应用程序使用 Intents 打开其他应用程序,有时使用专门的 Intents。

一个例子是这个 Intent,从 WhatsApp 中选择一个联系人:

val WHATSAPP_PACKAGE_NAME = "com.whatsapp"
val whatsAppPickIntent = Intent(Intent.ACTION_PICK).setPackage(WHATSAPP_PACKAGE_NAME)

这通常工作正常。当您希望启动应用程序时也是如此:

val launchIntent=packageManager.getLaunchIntentForPackage(WHATSAPP_PACKAGE_NAME)

问题

最近我得知一个相对较新的功能,允许用户拥有同一个应用程序的多个实例。它可能在其他设备上可用,但在 OnePlus 设备上它被称为“并行应用程序”。这是 2 个 WhatsApp 实例的示例,每个实例都分配给不同的电话号码:

在此处输入图像描述

问题是,这可能会破坏 Intent 与应用程序的单个实例一起工作的方式。现在 Intent 不知道该去哪个应用程序。启动器现在为 WhatsApp 显示 2 个图标:

在此处输入图像描述

如果您选择通过普通启动器图标(左侧)启动 WhatsApp,它会显示以下对话框:

在此处输入图像描述

工作正常,但如果您选择使用选择器意图,您仍然会看到此对话框,但是当您从对话框中选择一个项目时,它不会让您真正对它做任何事情(打开和关闭应用程序),而显示吐司“不支持文件格式”。

我试过的

由于我没有该设备,我试图通过互联网阅读有关它的信息,但我只找到了与用户相关的信息,例如:

我决定尝试进一步调查它,通过向告诉我的人发送一个 APK,尝试查看下一个代码是否会起作用:

    val whatsAppPickIntent = Intent(Intent.ACTION_PICK).setPackage(WHATSAPP_PACKAGE_NAME)
    val queryIntentActivities: List<ResolveInfo> = packageManager.queryIntentActivities(whatsAppPickIntent, 0)
    button2.setOnClickListener {
        intent = Intent(Intent.ACTION_PICK)
        val resolveInfo = queryIntentActivities[0]
        toast("number of possible choices:" + queryIntentActivities.size)
        intent.component = ComponentName(resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name)
        startActivity(intent)
    }

将显示的 toast 告诉我只有一个可以处理意图的东西,实际上,当我使用它时,我会得到相同的对话框来选择要使用的实例。就像在最初的意图中一样,它失败了,同样的吐司。

编辑:后来我尝试了下一件事:我要求在启用该功能之前和之后显示什么是 ResolveInfo 属性,方法是使用以下代码:

    val launchIntent = packageManager.getLaunchIntentForPackage(WHATSAPP_PACKAGE_NAME)
    val whatsAppPickIntent = Intent(Intent.ACTION_PICK).setPackage(WHATSAPP_PACKAGE_NAME)
    var queryIntentActivities: List<ResolveInfo> = packageManager.queryIntentActivities(whatsAppPickIntent, 0)
    var sb = StringBuilder()
    queryIntentActivities[0].dump(object : Printer {
        override fun println(x: String?) {
            if (x != null)
                sb.append(x)
        }
    }, "")
    val pickResult = "pick result:packageName:\"" + queryIntentActivities[0].activityInfo.packageName + "\" name:\"" + queryIntentActivities[0].activityInfo.name + "\"\n\n" + "extended:" + sb.toString()
    sb = StringBuilder()
    queryIntentActivities = packageManager.queryIntentActivities(launchIntent, 0)
    queryIntentActivities[0].dump(object : Printer {
        override fun println(x: String?) {
            if (x != null)
                sb.append(x)
        }
    }, "")
    val launchResult = "launch result:packageName:\"" + queryIntentActivities[0].activityInfo.packageName + "\" name:\"" + queryIntentActivities[0].activityInfo.name + "\"\n\n" + "extended:" + sb.toString()
    val body = pickResult + "\n\n" + launchResult
    val emailIntent = Intent(Intent.ACTION_SENDTO, Uri.fromParts("mailto", "", null))
    emailIntent.putExtra(Intent.EXTRA_SUBJECT, "whatsApp investigation")
    emailIntent.putExtra(Intent.EXTRA_TEXT, body)
    startActivity(Intent.createChooser(emailIntent, "Send email..."))

结果是两者都是一样的,好像一切都很好。这是打开/关闭时的结果(完全相同):

pick result:packageName:"com.whatsapp" name:"com.whatsapp.ContactPicker"
extended:priority=0 preferredOrder=0 match=0x108000 specificIndex=-1 isDefault=falseActivityInfo:  name=com.whatsapp.ContactPicker  packageName=com.whatsapp  enabled=true exported=true directBootAware=false  taskAffinity=com.whatsapp targetActivity=null persistableMode=PERSIST_ROOT_ONLY  launchMode=0 flags=0x3 theme=0x7f110173  screenOrientation=-1 configChanges=0xfb3 softInputMode=0x0  lockTaskLaunchMode=LOCK_TASK_LAUNCH_MODE_DEFAULT  resizeMode=RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION  ApplicationInfo:    name=com.whatsapp.AppShell    packageName=com.whatsapp    labelRes=0x7f100473 nonLocalizedLabel=null icon=0x7f080c15 banner=0x0    className=com.whatsapp.AppShell    processName=com.whatsapp    taskAffinity=com.whatsapp    uid=10099 flags=0x3 privateFlags=0x1010 theme=0x7f110164    requiresSmallestWidthDp=0 compatibleWidthLimitDp=0 largestWidthLimitDp=0    sourceDir=/data/app/com.whatsapp-NaKTLVhiNTh4zEGhFdkxrg==/base.apk    seinfo=default:targetSdkVersion=26    seinfoUser=:complete    dataDir=/data/user/0/com.whatsapp    deviceProtectedDataDir=/data/user_de/0/com.whatsapp    credentialProtectedDataDir=/data/user/0/com.whatsapp    enabled=true minSdkVersion=15 targetSdkVersion=26 versionCode=452238 targetSandboxVersion=1    supportsRtl=true    fullBackupContent=true    category=4

launch result:packageName:"com.whatsapp" name:"com.whatsapp.Main"

extended:priority=0 preferredOrder=0 match=0x0 specificIndex=-1 isDefault=falseActivityInfo:  name=com.whatsapp.Main  packageName=com.whatsapp  labelRes=0x7f10044c nonLocalizedLabel=null icon=0x0 banner=0x0  enabled=true exported=true directBootAware=false  taskAffinity=com.whatsapp targetActivity=null persistableMode=PERSIST_ROOT_ONLY  launchMode=0 flags=0x3 theme=0x0  screenOrientation=-1 configChanges=0xfb3 softInputMode=0x0  lockTaskLaunchMode=LOCK_TASK_LAUNCH_MODE_DEFAULT  resizeMode=RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION  ApplicationInfo:    name=com.whatsapp.AppShell    packageName=com.whatsapp    labelRes=0x7f100473 nonLocalizedLabel=null icon=0x7f080c15 banner=0x0    className=com.whatsapp.AppShell    processName=com.whatsapp    taskAffinity=com.whatsapp    uid=10099 flags=0x3 privateFlags=0x1010 theme=0x7f110164    requiresSmallestWidthDp=0 compatibleWidthLimitDp=0 largestWidthLimitDp=0    sourceDir=/data/app/com.whatsapp-NaKTLVhiNTh4zEGhFdkxrg==/base.apk    seinfo=default:targetSdkVersion=26    seinfoUser=:complete    dataDir=/data/user/0/com.whatsapp    deviceProtectedDataDir=/data/user_de/0/com.whatsapp    credentialProtectedDataDir=/data/user/0/com.whatsapp    enabled=true minSdkVersion=15 targetSdkVersion=26 versionCode=452238 targetSandboxVersion=1    supportsRtl=true    fullBackupContent=true    category=4

所以我想检查一下其他内容:尝试放置 WhatsApp 的小部件快捷方式(称为“whatsApp 聊天”),当此功能打开时,需要您选择联系人。事实证明,它不能很好地处理它。它询问将小部件创建到哪个应用程序:原始或克隆。如果你选择原版,一切都很好。如果您选择克隆,它会很好地添加小部件,但是当单击它时,它会转到应用程序的主窗口,而不是转到人。

问题

  1. 如何区分主实例和“克隆”实例?我的意思是,如何将 Intent 定向到目标应用程序的单个实例(主要实例)?我问这个关于我提出的两个意图(启动和选择器)。

  2. 这个功能是如何工作的?现在每个实例的私有数据保存在哪里?他们每个人都有一个进程,但名称不同吗?

  3. 其他 OEM 的其他设备是否有此功能?它在那里的工作方式和这里一样吗?

  4. 如果用户选择了要定位的应用程序,为什么我们会看到 toast 消息?它是否可能是一个错误的功能,仅适用于启动意图?

  5. 至少有一种方法可以知道给定的应用程序(给定它的包名称)是否启用了此功能?

4

0 回答 0