Как запустить Activity из другого приложения в Android на Kotlin
Понимание проблемы: явные и неявные Intent'ы
Ваша ошибка типична для новичков. Дело в том, что Intent.ACTION_VIEW с простым URI не может "угадать", какое приложение вы хотите открыть. Для запуска Activity из другого приложения нужно использовать либо явный Intent (с указанием конкретного компонента), либо неявный Intent (с действием и данными, которые система сама сопоставит с зарегистрированными Activity).
Вот правильный подход для Kotlin:
1. Запуск Activity по имени пакета (главный экран приложения)
// Получаем PackageManager
val packageManager = packageManager
// Пытаемся получить Intent для запуска главной Activity приложения
val intent = packageManager.getLaunchIntentForPackage("com.example.targetapp")
if (intent != null) {
// Важно: для Activity из другого приложения нужен флаг NEW_TASK
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
} else {
// Приложение не установлено или не имеет главной Activity
Toast.makeText(this, "Приложение не найдено", Toast.LENGTH_SHORT).show()
}
2. Запуск конкретной Activity по ComponentName (явный Intent)
Если вы знаете точное имя пакета и имя класса Activity (например, из документации или декомпиляции), используйте:
val intent = Intent()
intent.component = ComponentName(
"com.example.targetapp", // packageName
"com.example.targetapp.MainActivity" // полное имя класса Activity
)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
try {
startActivity(intent)
} catch (e: ActivityNotFoundException) {
Toast.makeText(this, "Activity не найдена", Toast.LENGTH_SHORT).show()
}
3. Запуск Activity через неявный Intent (по действию)
Например, открыть камеру для фото:
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
if (takePictureIntent.resolveActivity(packageManager) != null) {
// Создаем временный файл для фото
val photoFile = File.createTempFile("photo_", ".jpg", cacheDir)
val photoUri = FileProvider.getUriForFile(this,
"${packageName}.fileprovider", photoFile)
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri)
takePictureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
takePictureIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(takePictureIntent)
}
Почему getLaunchIntentForPackage() возвращает null?
- Приложение не имеет главной Activity (например, сервис или библиотека)
- У приложения нет Activity с
intent-filterкатегорииLAUNCHER - Приложение не установлено на устройстве
Важные флаги (flags)
FLAG_ACTIVITY_NEW_TASK— обязателен при запуске Activity из другого приложения (создает новую задачу)FLAG_ACTIVITY_CLEAR_TOP— если Activity уже запущена, она будет перезапущена (а не создана новая)FLAG_ACTIVITY_SINGLE_TOP— если Activity уже на вершине стека, она не будет создана заново
Проверка наличия Activity
Всегда проверяйте, может ли Intent быть обработан:
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
} else {
// Обработка ошибки
}
Это защитит от краша ActivityNotFoundException.
Альтернативный подход: использование PackageManager для поиска Activity
Если вы не знаете точное имя Activity, но знаете, что она должна обрабатывать определённое действие (например, ACTION_SEND), можно перебрать все Activity в системе:
val intent = Intent(Intent.ACTION_SEND)
intent.type = "text/plain"
val packageManager = packageManager
val activities = packageManager.queryIntentActivities(intent, 0)
if (activities.isNotEmpty()) {
// Показываем диалог выбора приложения
val chooser = Intent.createChooser(intent, "Поделиться через")
chooser.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(chooser)
} else {
Toast.makeText(this, "Нет приложений для этого действия", Toast.LENGTH_SHORT).show()
}
Дополнительный совет: открытие Activity с данными
Для передачи данных в Activity другого приложения используйте putExtra():
val intent = Intent()
intent.component = ComponentName("com.example.notes",
"com.example.notes.EditNoteActivity")
intent.putExtra("note_id", 123)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
Обратите внимание: чтобы это работало, целевая Activity должна быть экспортируемой (иметь android:exported="true" в манифесте). Начиная с Android 12, все Activity должны явно указывать этот атрибут.
Проверка установки приложения
Перед запуском проверьте, установлено ли приложение:
fun isAppInstalled(packageName: String): Boolean {
return try {
packageManager.getPackageInfo(packageName, 0)
true
} catch (e: PackageManager.NameNotFoundException) {
false
}
}
Используйте этот метод для красивого UX — показывайте кнопку "Установить" вместо краша.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги