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

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: зачем вызывать Activity из другого приложения?

Представьте, что вы создаете приложение для заметок, и хотите дать пользователю возможность сделать фото прямо из вашего интерфейса. Или, допустим, ваш мессенджер должен открывать контакты из адресной книги. В обоих случаях вам нужно запустить Activity из другого приложения в Android.

Эта задача — один из самых популярных вопросов на Stack Overflow (тысячи просмотров и сотни голосов). И не зря: если сделать это неправильно, приложение может упасть с ActivityNotFoundException или, что ещё хуже, создать угрозу безопасности. В этом туториале мы разберём все нюансы на языке Kotlin, чтобы вы могли смело интегрировать внешние экраны в свои проекты.

Кстати, вы на сайте PythonLib, где мы часто говорим о Python, но сегодня — особый случай. Android-разработка на Kotlin — это мощный навык, который отлично сочетается с бэкендом на Python. Поехали!

Что такое Intent и почему это ключ к решению?

В Android Intent — это сообщение, которое говорит системе: «Эй, мне нужно сделать что-то с таким-то действием». Для запуска Activity из другого приложения используются два подхода:

  • Явный Intent — вы точно знаете, какой компонент хотите запустить (например, com.example.target.MainActivity). Работает только если у вас есть доступ к коду этого приложения.
  • Неявный Intent — вы описываете, что хотите сделать (например, «открыть карту по координатам»), а система сама находит подходящее приложение. Это более гибкий и безопасный способ для вызова внешнего Activity.

Мы сосредоточимся на неявных Intent, так как они чаще всего используются для межпроцессного взаимодействия Android.

Базовый пример: открываем карту по координатам

Начнём с простого примера, который демонстрирует, как запустить Activity из другого приложения для отображения карты.

// Kotlin
val gmmIntentUri = Uri.parse("geo:55.7558,37.6173?z=15")
val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri)
mapIntent.setPackage("com.google.android.apps.maps")

// Проверяем, есть ли приложение, которое может обработать Intent
if (mapIntent.resolveActivity(packageManager) != null) {
    startActivity(mapIntent)
} else {
    // Показываем пользователю сообщение об ошибке
    Toast.makeText(this, "Google Карты не установлены", Toast.LENGTH_SHORT).show()
}

Что здесь происходит? Мы создаём Intent с действием ACTION_VIEW и URI, содержащим координаты. Затем с помощью setPackage мы явно указываем, что хотим использовать Google Карты (хотя это необязательно — система может предложить выбор). Самое важное — проверка через resolveActivity. Это спасает от краша, если нужное приложение отсутствует на устройстве.

Сценарий: вызываем камеру и получаем результат

Теперь перейдём к более сложному кейсу — запуск Activity из другого приложения с ожиданием результата. Классический пример: сделать фото и получить его в своём приложении.

// Kotlin
private const val REQUEST_IMAGE_CAPTURE = 1

private fun dispatchTakePictureIntent() {
    val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
    // Проверяем, что камера доступна
    if (takePictureIntent.resolveActivity(packageManager) != null) {
        startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)
    } else {
        // Обработка ошибки: камера не найдена
    }
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == Activity.RESULT_OK) {
        val imageBitmap = data?.extras?.get("data") as Bitmap
        // Теперь у вас есть фото! Используйте его.
        imageView.setImageBitmap(imageBitmap)
    }
}

Обратите внимание: startActivityForResult (и его современная альтернатива — ActivityResultLauncher, о которой ниже) позволяет получить данные обратно. Без этого вы бы просто открыли камеру, но не смогли бы забрать снимок. Это ключевой момент для вызова внешнего Activity с обменом данными.

Современный подход: Activity Result API (Kotlin)

Начиная с AndroidX Activity 1.2.0, Google рекомендует использовать Activity Result API вместо устаревшего startActivityForResult. Он безопаснее, чище и отлично работает с Kotlin.

// Kotlin
private val takePictureLauncher = registerForActivityResult(
    ActivityResultContracts.TakePicturePreview()
) { bitmap: Bitmap? ->
    // Обработка результата
    bitmap?.let {
        imageView.setImageBitmap(it)
    }
}

// Запуск камеры
private fun capturePhoto() {
    takePictureLauncher.launch(null)
}

Этот код делает то же самое, что и предыдущий пример, но без лишнего шаблонного кода. Activity Result API автоматически обрабатывает lifecycle и проверки, что делает запуск Activity из другого приложения более надёжным.

Безопасность: защита от ActivityNotFoundException

Самая распространённая ошибка новичков — пропуск проверки наличия Activity. Без неё ваше приложение упадёт с ActivityNotFoundException, если целевое приложение не установлено. Всегда используйте resolveActivity или queryIntentActivities:

// Kotlin
val intent = Intent(Intent.ACTION_SEND).apply {
    type = "text/plain"
    putExtra(Intent.EXTRA_TEXT, "Привет, мир!")
}

val activities = packageManager.queryIntentActivities(intent, 0)
if (activities.isNotEmpty()) {
    startActivity(Intent.createChooser(intent, "Поделиться через"))
} else {
    // Ни одно приложение не может обработать этот Intent
}

Обратите внимание на Intent.createChooser — это обязательный элемент для неявных Intent, когда пользователь должен выбрать из нескольких приложений. Без него система может выбрать приложение по умолчанию без диалога, что сбивает с толку.

Практический пример: интеграция с контактами

Давайте соберём всё вместе и создадим функцию, которая открывает контакты и возвращает номер телефона. Это реальный сценарий для запуска Activity из другого приложения в Android.

// Kotlin
private val pickContactLauncher = registerForActivityResult(
    ActivityResultContracts.PickContact()
) { uri: Uri? ->
    uri?.let {
        // Получаем данные из контент-провайдера
        val cursor = contentResolver.query(it, null, null, null, null)
        cursor?.use { c ->
            if (c.moveToFirst()) {
                val nameIndex = c.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)
                val name = c.getString(nameIndex)
                contactNameTextView.text = name
            }
        }
    }
}

private fun openContacts() {
    pickContactLauncher.launch(null)
}

Этот код использует специальный контракт Pick

Блоги

Рекомендаций по книгам