Как работает функция "параллельных приложений" на устройствах OnePlus 3 и как мы можем правильно использовать Intents с ними?
Фон
Приложения используют Intents для открытия других приложений, иногда со специализированными Intents.
Одним из примеров является это намерение, чтобы выбрать контакт из 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, каждый из которых назначен на свой номер телефона:
Дело в том, что это может нарушить работу Intents с одним экземпляром приложения. Теперь Intent не знает, к какому приложению обращаться. Панель запуска показывает 2 иконки для WhatsApp:
Если вы решите запустить 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)
}
Тост, который будет показан, говорит, что у меня есть только одна вещь, которая может обработать намерение, и действительно, когда я его использую, я получаю тот же диалог для выбора, какой экземпляр использовать. И, как в оригинальном намерении, он терпит неудачу с тем же тостом.
РЕДАКТИРОВАТЬ: Позже я попробовал следующее: я попросил показать, каковы свойства 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"), который требует, чтобы вы выбрали контакт, когда эта функция включена. Оказывается, это не может справиться с этим хорошо. Он спрашивает, в каком приложении создать виджет: оригинал или клон. Если вы выбираете оригинал, все в порядке. Если вы выбираете клон, он добавляет виджет все хорошо и хорошо, но при нажатии на него, он идет в главное окно приложения вместо того, чтобы идти к человеку.
Вопросы
Как я могу отличить основной экземпляр от "клонированного"? Я имею в виду, как Intent может быть направлено на один (основной) экземпляр целевого приложения? Я спрашиваю об обоих представленных материалах (запуск и сборщик).
Как эта функция вообще работает? Где сейчас хранятся личные данные каждого экземпляра? У каждого из них есть процесс с другим именем?
У других устройств других производителей есть эта функция? Работает ли там так же, как здесь?
Почему мы видим всплывающее сообщение, если пользователь выбрал приложение для таргетинга? Может быть, это ошибочная функция, которая будет работать только для целей запуска?
Есть ли хотя бы способ узнать, что в данном приложении (с указанием имени пакета) эта функция включена для него?