Avatar ·

Как запустить Activity из другого приложения в Android на Kotlin

Всем привет! Я начинающий Android-разработчик на Kotlin, и у меня возникла проблема. Мне нужно, чтобы моё приложение запускало какое-то другое приложение на устройстве, например, камеру, карты или сторонний мессенджер. Я читал про Intent, но не до конца понимаю, как правильно это сделать. Я пробовал написать такой код, но он не работает — приложение просто вылетает или ничего не происходит: ```kotlin val intent = Intent() intent.action = Intent.ACTION_VIEW intent.data = Uri.parse("package:com.example.targetapp") startActivity(intent) ``` Я знаю, что для запуска другого приложения нужно знать его package name, но как его получить? И что делать, если приложение не установлено? Ещё я слышал про явные и неявные интенты — в чём разница? Мне нужно подробное объяснение: как найти package name целевого приложения, как составить правильный Intent, как обработать случай, когда приложение отсутствует, и как передать данные в запускаемое Activity. Желательно с примерами на Kotlin, так как я пишу на нём. Заранее спасибо за помощь! <<>>

1. Основы: явные и неявные интенты

В Android есть два типа Intent для запуска Activity:

  • Явный (Explicit Intent) — вы точно знаете package name и class name целевого Activity. Используется для запуска Activity внутри вашего приложения или когда вы знаете точное имя компонента другого приложения.
  • Неявный (Implicit Intent) — вы описываете действие (например, просмотр веб-страницы или съёмка фото), а система сама находит подходящее приложение. Это более гибкий и безопасный способ для запуска сторонних приложений.

2. Как узнать package name другого приложения

Самый простой способ — скачать приложение Package Name Viewer из Google Play или использовать ADB-команду:

adb shell pm list packages | grep частичное_имя_приложения

Например, для Google Карт: com.google.android.apps.maps, для Камеры: com.android.camera (или com.google.android.GoogleCamera на Pixel).

3. Запуск Activity с явным Intent (когда знаете package name)

Пример запуска приложения Камера:

val launchIntent = packageManager.getLaunchIntentForPackage("com.android.camera")
if (launchIntent != null) {
    startActivity(launchIntent)
} else {
    // Приложение не установлено
    Toast.makeText(this, "Камера не найдена", Toast.LENGTH_SHORT).show()
    // Можно открыть Google Play для установки
    try {
        startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=com.android.camera")))
    } catch (e: ActivityNotFoundException) {
        startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=com.android.camera")))
    }
}

Метод getLaunchIntentForPackage() возвращает Intent для запуска главного Activity приложения. Всегда проверяйте на null — это лучшая практика.

4. Запуск Activity с неявным Intent (рекомендуемый способ)

Неявные интенты не требуют знания package name. Вы просто указываете действие. Вот несколько примеров:

Открыть URL в браузере

val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://pythonlib.ru"))
startActivity(intent)

Открыть местоположение в Картах

val gmmIntentUri = Uri.parse("geo:55.751244,37.618423?z=10")
val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri)
if (mapIntent.resolveActivity(packageManager) != null) {
    startActivity(mapIntent)
} else {
    // Карты не установлены
    Toast.makeText(this, "Приложение карт не найдено", Toast.LENGTH_SHORT).show()
}

Сделать фото

val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
if (takePictureIntent.resolveActivity(packageManager) != null) {
    startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)
} else {
    // Камера недоступна
}

Отправить текст в другое приложение (например, мессенджер)

val sendIntent = Intent().apply {
    action = Intent.ACTION_SEND
    putExtra(Intent.EXTRA_TEXT, "Привет! Это сообщение из моего приложения")
    type = "text/plain"
}
startActivity(Intent.createChooser(sendIntent, "Поделиться через"))

5. Важные моменты

  • Всегда проверяйте наличие приложения с помощью resolveActivity() или getLaunchIntentForPackage(). Если приложение не установлено, вызов startActivity() вызовет ActivityNotFoundException.
  • Используйте Intent.createChooser() для неявных интентов — это позволит пользователю выбрать приложение, если их несколько.
  • Для передачи данных используйте putExtra(). Например, для ACTION_SEND передавайте текст, для ACTION_VIEW — URI.
  • В Android 11+ появились ограничения на запрос package name других приложений. Если вам нужно получить список установленных приложений, добавьте в манифест запрос <queries>.

6. Полный пример с обработкой ошибок

fun launchApp(packageName: String) {
    try {
        val intent = packageManager.getLaunchIntentForPackage(packageName)
        if (intent != null) {
            startActivity(intent)
        } else {
            // Приложение не найдено — предлагаем установить
            showInstallDialog(packageName)
        }
    } catch (e: Exception) {
        Log.e("AppLauncher", "Ошибка запуска: ${e.message}")
        Toast.makeText(this, "Не удалось запустить приложение", Toast.LENGTH_SHORT).show()
    }
}

private fun showInstallDialog(packageName: String) {
    AlertDialog.Builder(this)
        .setTitle("Приложение не установлено")
        .setMessage("Хотите установить его из Google Play?")
        .setPositiveButton("Да") { _, _ ->
            val playStoreIntent = Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=$packageName"))
            startActivity(playStoreIntent)
        }
        .setNegativeButton("Нет", null)
        .show()
}
<<>>

Альтернативный подход: использование Deep Links и App Links

Если вы разрабатываете приложение, которое должно запускаться из других приложений, лучше использовать Deep Links (глубокие ссылки). Это стандартный механизм Android, который позволяет запускать определённый экран вашего приложения по URL.

Как это работает:

  1. В манифесте вашего приложения добавьте intent-filter для Activity, которое хотите открывать:
<activity android:name=".TargetActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data
            android:scheme="https"
            android:host="myapp.example.com"
            android:pathPrefix="/open" />
    </intent-filter>
</activity>

Запуск из другого приложения:

val deepLink = "https://myapp.example.com/open?user_id=123"
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(deepLink))
startActivity(intent)

Преимущества этого подхода:

  • Независимость от package name — вы работаете через URL, который легко запомнить.
  • Единый интерфейс — можно открыть и в браузере, если приложение не установлено (с помощью android:autoVerify="true").
  • Безопасность — система проверяет, что URL принадлежит вашему приложению (через Digital Asset Links).
  • Гибкость — можно передавать параметры прямо в URL (query parameters).

Этот метод особенно полезен, если вы создаёте SDK или библиотеку, которая должна взаимодействовать с другими приложениями, не раскрывая внутренние package name.