Как настроить deep links в Android и открывать нужный экран

Deep links в Android — это ссылки, которые открывают приложение сразу на конкретном экране (товар, профиль, сброс пароля). Делается это через intent-filter в манифесте и разбор intent.data (URI) в коде; для https-ссылок лучше использовать Android App Links с подтверждением домена.

Если у вас есть домен — делайте App Links. Custom scheme (myapp://...) оставьте как резервный вариант для тестов или внутренних интеграций.

Оглавление

ТипПримерКогда выбирать
Custom schememyapp://p/123Нет домена, быстрый старт, внутренние сценарии
Web deep linkhttps://example.com/p/123MVP, когда App Links ещё не готовы (возможен выбор приложения/браузера)
**Android App Links**https://example.com/p/123Продакшен: открытие сразу в приложении после верификации домена

На практике чаще всего поддерживают App Links + fallback (если приложения нет — открывается сайт), а scheme добавляют точечно.

Настройка в AndroidManifest: intent-filter

Минимальная настройка для https:

<activity
    android:name=".MainActivity"
    android:exported="true">

    <intent-filter android:autoVerify="true">
        <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="example.com"
            android:pathPrefix="/p/" />
    </intent-filter>

</activity>
  • VIEW + BROWSABLE — чтобы ссылка открывалась из браузера/мессенджеров.
  • pathPrefix="/p/" — удобно для однотипных страниц (/p/123, /p/456).
  • Если нужно матчингов больше (профиль, сброс пароля), добавляйте отдельные <data> или отдельные intent-filter под разные пути.

Частая причина “из браузера не открывается”: забыли android.intent.category.BROWSABLE. Ещё одна — не указан android:exported="true" у Activity с intent-filter.

Чтобы https://example.com/... открывался без выбора приложения, домен нужно “привязать” к приложению через файл:

/.well-known/assetlinks.json

Пример структуры:

[
  {
    "relation": ["delegate_permission/common.handle_all_urls"],
    "target": {
      "namespace": "android_app",
      "package_name": "com.example.app",
      "sha256_cert_fingerprints": ["AA:BB:CC:...:11"]
    }
  }
]

Важно, чтобы совпали:

  • package_nameapplicationId
  • SHA‑256 отпечаток ↔ реальный ключ подписи релиза (включая случаи, когда подпись выполняется не локально)

Если App Links “не верифицируются” на релизной сборке, чаще всего виноват неправильный SHA‑256 (взяли debug вместо release или перепутали ключ подписи).

Открытие нужного экрана: разбор URI в Kotlin

Ссылка приходит в intent.data. Обрабатывайте и холодный старт, и повторный интент:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        handleDeepLink(intent)
    }

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        handleDeepLink(intent)
    }

    private fun handleDeepLink(intent: Intent) {
        val uri = intent.data ?: return
        val segments = uri.pathSegments

        when (segments.getOrNull(0)) {
            "p" -> segments.getOrNull(1)?.let { openProduct(it) } ?: openHome()
            "u" -> openProfile(segments.getOrNull(1))
            "reset-password" -> openReset(uri.getQueryParameter("token"))
            else -> openHome()
        }
    }
}

Если экран требует авторизацию — делайте “отложенный” переход: сохраните deep link, покажите логин, после успеха выполните навигацию.

Тестирование

Быстрый способ — ADB:

adb shell am start -a android.intent.action.VIEW -d "https://example.com/p/123"

Чтобы исключить выбор приложений, укажите пакет:

adb shell am start -a android.intent.action.VIEW -d "https://example.com/p/123" com.example.app

Дополнительно проверяйте реальные клики из заметок/почты/мессенджеров: они могут добавлять редиректы и параметры, из-за чего меняется итоговый URL.

Частые ошибки

  • intent-filter настроен, но нет BROWSABLE → не открывается из внешних приложений.
  • Не обработан onNewIntent() → при уже запущенном приложении открывается “не тот” экран.
  • Слишком узкий pathPrefix/ошибка в host/scheme → матчинг не срабатывает.
  • App Links не подтверждены: неверный SHA‑256, неправильный путь /.well-known/assetlinks.json, несовпадение package_name.
  • Небезопасная логика: доверие параметрам из URL (токены/ID) без серверной проверки.

FAQ

Можно ли поддерживать и App Links, и custom scheme одновременно?
Да. Обычно App Links — основной канал, scheme — резерв для тестов и частных интеграций.

Почему иногда появляется окно выбора приложения?
Чаще всего App Links не прошли верификацию, либо пользователь ранее выбрал открытие в браузере по умолчанию.

Нужно ли добавлять http, если есть https?
Только если у вас реально остались старые http-ссылки. В остальных случаях лучше вести всё на https и не расширять поверхность ошибок.