Android App Links가 브라우저로 열릴 때: 딥링크 검증 순서

핵심 요약
Android 링크가 앱 대신 브라우저로 열릴 때 intent-filter, assetlinks.json, Play App Signing 인증서와 ADB 검증 상태를 순서대로 확인하는 방법을 설명합니다.

검수 범위
소유한 HTTPS 도메인을 Android 앱과 연결하는 App Links를 대상으로 합니다. 임의의 커스텀 URI 스킴이나 iPhone Universal Links는 검증 방식이 다르며, ADB 수동 재검증 명령은 Android 12 이상을 기준으로 설명합니다.

웹페이지의 HTTPS 링크를 눌렀는데 설치된 앱이 아니라 브라우저가 열리면 앱의 화면 이동 코드부터 고치기 쉽습니다. 하지만 Android App Links는 앱 코드, 매니페스트, 웹 서버의 assetlinks.json, 앱 서명, 기기별 검증 상태가 모두 맞아야 동작합니다. 먼저 운영체제가 도메인을 앱에 연결했는지 확인하고, 그다음 앱 내부 라우팅을 점검해야 원인을 빠르게 나눌 수 있습니다.

일반 딥링크와 App Links를 구분하기

myapp://product/42 같은 커스텀 스킴은 Android의 일반 딥링크입니다. 여러 앱이 같은 스킴을 선언할 수 있어 앱 선택 화면이 나타날 수 있습니다. Android App Links는 소유한 웹사이트의 https:// 주소와 앱을 Digital Asset Links로 검증합니다. 검증에 성공하면 사용자가 해당 링크를 눌렀을 때 앱의 대응 화면으로 바로 연결할 수 있습니다.

앱이 설치되지 않은 기기에서는 같은 HTTPS 주소가 정상 웹페이지로 열려야 합니다. 따라서 점검용 URL도 앱에서만 존재하는 가짜 주소보다 실제 웹 콘텐츠로 연결되는 주소를 사용하는 편이 좋습니다.

증상으로 점검 위치 좁히기

관찰한 증상 먼저 확인할 곳 판단 기준
항상 브라우저로 열림 도메인 검증 상태와 사용자 기본 열기 설정 pm get-app-links 결과가 verified인지 확인
일부 도메인만 실패 호스트별 assetlinks.json www와 비www, 하위 도메인을 각각 점검
앱은 열리지만 엉뚱한 화면이 나옴 앱 내부 URL 파싱과 라우팅 OS 검증보다 경로·쿼리 매핑 문제일 가능성이 큼
디버그 빌드만 실패 SHA-256 인증서 지문 debug, upload, Play App Signing 인증서를 구분
특정 경로만 브라우저로 열림 매니페스트 경로와 동적 규칙 host는 검증됐지만 URL 규칙에서 제외됐는지 확인

1단계: 매니페스트의 intent-filter 확인

App Links로 검증할 Activity에는 VIEW action, DEFAULTBROWSABLE category, http 또는 https scheme, 소유한 host가 필요합니다. 자동 검증을 요청하려면 android:autoVerify="true"를 지정합니다.

<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" />
    </intent-filter>
</activity>

운영 링크가 https://www.example.com/...인데 매니페스트에는 example.com만 있으면 서로 다른 host로 처리됩니다. 실제로 배포하는 URL 목록을 먼저 만들고, scheme·host·path 조건과 대조하세요. 테스트용이나 소유하지 않은 도메인을 운영 매니페스트에 남겨두지 않는 것도 중요합니다.

2단계: assetlinks.json 응답 확인

각 host는 다음 위치에서 앱과의 연결 정보를 제공해야 합니다.

https://example.com/.well-known/assetlinks.json

파일에는 앱의 application ID와 실제 설치 파일을 서명한 인증서의 SHA-256 지문이 들어갑니다.

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

브라우저에서 JSON이 보이는 것만으로 충분하지 않습니다. 다음 조건을 응답 헤더까지 확인합니다.

  • HTTPS 주소가 HTTP 200을 직접 반환하는가
  • Content-Typeapplication/json인가
  • 301 또는 302 리디렉션 없이 파일이 바로 열리는가
  • 선언한 모든 host와 하위 도메인에 각각 파일이 있는가
  • JSON 문법, package name, SHA-256 지문이 정확한가
curl -i https://example.com/.well-known/assetlinks.json

Play App Signing을 사용하는 앱은 로컬 keystore의 업로드 키와 사용자의 기기에 설치되는 앱의 서명 인증서가 다를 수 있습니다. 이 경우 Play Console의 앱 서명 인증서 지문을 사용해야 합니다. 로컬 debug 빌드까지 같은 도메인으로 시험하려면 debug 인증서 지문을 별도로 허용할지 개발 환경 정책을 먼저 정하세요.

3단계: 기기의 도메인 검증 상태 확인

Android 12 이상에서는 설치된 앱의 검증 상태를 초기화하고 다시 요청할 수 있습니다. 아래의 PACKAGE_NAME을 실제 application ID로 바꿉니다.

adb shell pm set-app-links --package PACKAGE_NAME 0 all
adb shell pm verify-app-links --re-verify PACKAGE_NAME

# 검증 에이전트가 요청을 마칠 때까지 잠시 기다린 뒤 확인
adb shell pm get-app-links PACKAGE_NAME

결과에서 도메인이 verified면 시스템 검증에 성공한 것입니다. none은 아직 결과가 기록되지 않았을 수 있으므로 인터넷 연결을 확인하고 몇 분 뒤 다시 봅니다. legacy_failure 또는 제조사별 1024 이상의 오류 코드가 나오면 웹 서버 응답, 인증서 지문, 네트워크를 다시 확인합니다.

사용자가 설정에서 “지원되는 링크 열기”를 껐거나 다른 앱을 선택했다면 검증 성공과 실제 열기 동작이 다를 수 있습니다. 사용자 상태까지 보려면 다음 명령을 함께 사용합니다.

adb shell pm get-app-links --user cur PACKAGE_NAME

4단계: 실제 URL을 강제로 실행해 보기

도메인 상태와 별도로 특정 URL이 intent-filter에 맞는지 확인합니다.

adb shell am start 
  -a android.intent.action.VIEW 
  -c android.intent.category.BROWSABLE 
  -d "https://example.com/products/42"

이 명령으로 앱이 열리지만 원하는 상세 화면으로 이동하지 않으면 URL에서 path, query, fragment를 읽어 앱의 화면 경로로 변환하는 코드가 문제일 가능성이 큽니다. 반대로 브라우저가 열리면 앱 내부 라우터를 수정하기 전에 검증 상태와 매니페스트 일치 여부를 먼저 해결합니다.

Android 버전에 따라 달라지는 부분

  • Android 11 이하: 매니페스트에 선언한 여러 host 중 하나라도 연결 파일이 맞지 않으면 전체 검증이 실패할 수 있으므로 선언 범위를 작게 유지합니다.
  • Android 12 이상: 업데이트된 도메인 검증 방식과 수동 재검증 명령을 사용할 수 있습니다.
  • Android 15 이상: assetlinks.json의 Dynamic App Links 규칙으로 경로·쿼리·fragment 동작을 조정할 수 있습니다. 다만 동적 규칙은 매니페스트가 허용한 host 범위를 넓힐 수 없습니다.

Android 15 이상의 백그라운드 재검증은 모든 기기에 즉시 반영되지 않을 수 있습니다. 공식 문서는 변경 전파에 최대 7일이 걸릴 수 있다고 안내합니다. Android 14 이하에서는 파일 변경이 보통 앱 설치 또는 업데이트 때 다시 반영되므로, 운영 반영과 한 기기에서 강제로 재검증한 결과를 구분해서 기록하세요.

자주 놓치는 원인

  1. www 주소 불일치: example.comwww.example.com은 별도 host입니다.
  2. 리디렉션: assetlinks.json 요청을 다른 주소로 보내면 검증에 실패할 수 있습니다.
  3. 서명 지문 혼동: debug 키, upload 키, Play App Signing 키를 구분하지 않은 경우입니다.
  4. application ID 불일치: 제품 flavor나 build type에 따라 package name이 달라진 경우입니다.
  5. 경로 제한: host는 맞지만 pathPrefix 또는 동적 제외 규칙이 테스트 URL을 막는 경우입니다.
  6. 사용자 선택: 기기의 기본 링크 열기 설정에서 앱이 비활성화된 경우입니다.

출시 전에 남길 검증 기록

  • 테스트한 앱 버전과 application ID
  • debug 또는 release 여부와 사용한 서명 인증서 종류
  • 검증할 전체 host 목록과 대표 URL
  • assetlinks.json의 상태 코드·Content-Type·리디렉션 여부
  • pm get-app-links 결과
  • 앱 미설치, 새 설치, 업데이트 설치에서의 링크 동작
  • 앱이 열린 뒤 목표 화면과 뒤로가기 동작

링크 문제는 “앱이 열렸는가”만 확인하면 재발하기 쉽습니다. 웹 서버 연결, 운영체제 검증, URL 매칭, 앱 내부 이동을 네 단계로 나눠 결과를 남기면 담당 팀이 달라도 같은 기준으로 원인을 찾을 수 있습니다.


검증 기준과 참고 자료

이 글은 2026-09-09에 Android 공식 문서를 기준으로 App Links의 설정, 서버 연결, 기기 검증 명령과 버전별 차이를 검수했습니다. 제조사별 검증 에이전트와 Android 버전에 따라 결과 반영 시간과 설정 화면 이름은 달라질 수 있습니다.

관련 글