Android App Links 검증 실패 원인, assetlinks.json·동적 규칙 점검법

자연광 아래 놓인 무브랜드 안드로이드 스마트폰과 웹 주소를 상징하는 빈 카드, 옆에 놓인 소형 개발 장치

AI를 활용하여 생성한 이미지입니다.

웹 주소를 눌렀을 때 앱이 열리지 않으면 manifest의 intent-filter만 고치는 것으로는 부족할 때가 많습니다. Android App Links는 앱의 선언과 웹 서버의 /.well-known/assetlinks.json, 앱을 서명한 인증서의 SHA-256 지문, 기기 안의 검증 상태를 함께 봅니다.[1] 따라서 “앱이 설치돼 있다”와 “이 URL을 앱이 처리할 권한을 검증받았다”는 서로 다른 상태예요.

실패 지점을 네 층으로 나누세요

층 확인 대상 실패할 때의 단서
웹 서버 HTTPS, 공개 경로, JSON 문법, 응답 내용 도메인 검증이 실패하거나 로그인 페이지가 반환됩니다.
앱 서명 패키지 이름과 실제 배포 인증서의 SHA-256 지문 파일은 읽히지만 앱과 도메인의 관계가 맞지 않습니다.
manifest scheme, host, path 범위와 intent filter 검증된 도메인에서도 특정 URL만 브라우저로 열립니다.
기기 상태 현재 앱 링크 검증 결과와 사용자 기본 설정 서버를 고친 뒤에도 이전 상태가 남아 있습니다.

assetlinks.json은 해당 웹사이트가 특정 Android 앱에 링크 처리를 허용한다고 공개 선언하는 파일입니다. 파일에 넣을 패키지 이름과 지문은 기억해서 적지 말고, Play Console의 앱 서명 정보와 현재 배포 빌드에 실제 사용한 인증서에서 확인하세요. debug 키와 release 키, 로컬 서명과 Play App Signing 서명이 다르면 개발 기기에서는 되는데 배포 버전에서 실패하는 상황이 생길 수 있습니다.[1]

서버 파일을 먼저 독립적으로 확인하기

  1. 정확한 HTTPS 도메인에서 /.well-known/assetlinks.json을 요청합니다.
  2. 로그인 화면, 리디렉션, 오류 페이지가 아니라 공개 JSON이 반환되는지 확인합니다.
  3. JSON 문법과 패키지 이름, 인증서 지문이 현재 앱과 일치하는지 비교합니다.
  4. manifest의 host가 파일을 제공하는 도메인과 한 글자까지 같은지 봅니다.
  5. 서버 파일을 바꾼 뒤에는 테스트 기기에서 다시 검증합니다.

여러 앱이 한 호스트의 서로 다른 경로를 맡거나, 한 앱이 여러 웹사이트를 맡는 구성도 가능합니다.[1] 이때 모든 앱과 경로를 한 선언에 무작정 합치기보다 어떤 앱이 어느 호스트와 경로를 담당하는지 표로 관리하세요. staging 도메인과 production 도메인을 혼동하는 실수도 자주 생기므로 빌드 변형별 manifest와 서버 파일을 나란히 비교하는 편이 좋습니다.

Android 15 동적 규칙의 범위

Android 15(API 35) 이상에서는 assetlinks.json의 동적 규칙으로 경로, fragment, query parameter 조건을 서버 쪽에서 제어할 수 있습니다. 기기는 이 파일을 읽어 manifest의 정적 규칙과 결합합니다. Android 14 이하 기기는 새 동적 규칙 필드를 무시하고 기존 manifest 규칙을 사용합니다.[1]

중요한 제한은 동적 규칙이 manifest가 선언하지 않은 호스트나 더 넓은 경로를 새로 열 수 없다는 점입니다.[1] 서버 파일만 수정해 manifest 범위를 확장하려고 하면 기대한 결과가 나오지 않아요. 반대로 JSON 형식이 잘못되거나 필드가 비어 있으면 동적 규칙 전체가 버려지고 정적 규칙으로 돌아갈 수 있으므로, 작은 변경 단위로 배포하세요.

{
  "dynamic_app_link_components": [
    {"/": "/products/*"},
    {"/": "/internal/*", "exclude": true},
    {"/": "*"}
  ]
}

특정 경로를 제외한 뒤 마지막 catch-all 규칙으로 나머지를 허용하는 구성은 강력하지만, 순서와 범위를 잘못 읽으면 내부 URL까지 앱으로 보낼 수 있습니다. 제외 규칙과 허용 규칙을 실제 URL 예시로 표로 만든 뒤 적용하세요. Android 14 이하 사용자는 이 동적 규칙을 보지 못한다는 점도 배포 계획에 포함해야 합니다.[1]

ADB로 상태를 초기화하고 다시 검증하기

서버 파일을 수정한 직후 브라우저에서 주소를 몇 번 여는 것만으로는 기기의 검증 결과를 알 수 없습니다. 테스트 기기에서 다음 순서로 기존 상태를 초기화하고 재검증합니다.[2]

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와 실패 상태를 도메인별로 구분하세요. Android 공식 문서는 서버 변경이 캐시와 백그라운드 재검증 때문에 모든 기기에 즉시 반영되지 않을 수 있으며 최대 7일이 걸릴 수 있다고 안내합니다.[2] 개발 기기에서 재검증이 끝났다고 운영 사용자에게 즉시 반영된다고 약속해서는 안 됩니다.

특정 URL만 따로 진단하기

도메인 전체가 verified인데 /products/42만 브라우저에서 열린다면 manifest의 path와 동적 규칙의 충돌을 의심합니다. Android 공식 테스트 문서가 안내하는 다음 명령으로 URL 처리 후보와 규칙 판정을 볼 수 있습니다.[3]

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

진단 결과에서 대상 앱, 일치한 manifest 필터, 도메인 검증 상태, 동적 규칙의 allow·exclude 판정을 따로 읽으세요.[3] 이 출력은 패키지가 설치된 상태와 특정 URL을 처리할 수 있는 상태를 구분하는 데 유용합니다.

배포 전 체크리스트와 예외

  • 파일 요청이 HTTPS에서 공개되고 JSON이 로그인이나 오류 페이지로 바뀌지 않는지 확인합니다.
  • debug·release·Play App Signing 지문을 구분합니다.[1]
  • manifest의 host와 서버 파일의 호스트를 비교합니다.
  • 동적 규칙이 manifest 범위를 넓히려 하지 않는지 확인합니다.
  • 기기 상태 초기화, 재검증, URL별 디버그를 모두 실행합니다.
  • Android 14 이하에서 동적 규칙이 무시될 때의 정적 규칙도 준비합니다.

앱 링크 문제는 네트워크 연결 자체보다 서버 파일, 서명, manifest, 기기 캐시 중 어느 층에서 실패했는지 찾는 작업에 가깝습니다. ADB 페어링과 해제 절차가 필요하다면 Android 무선 디버깅 점검 글에서 별도로 확인하세요.

자주 묻는 질문

앱이 설치돼 있는데 왜 브라우저가 열리나요?

설치 여부는 도메인 검증이나 URL 경로 일치 여부를 대신하지 않습니다. assetlinks.json, 서명 지문, manifest 범위, 기기 상태를 각각 확인하세요.

동적 규칙만 바꾸면 새 경로가 앱에서 열리나요?

manifest가 허용한 범위를 넘어설 수 없습니다.[1] 새 host나 더 넓은 경로가 필요하면 정적 선언과 서버 파일을 함께 검토해야 합니다.

파일을 고쳤는데 바로 반영되지 않아요.

기기 캐시와 백그라운드 검증 지연이 있을 수 있습니다. 개발 기기에서는 상태 초기화와 재검증을 사용하되, 운영 기기의 즉시 반영은 보장하지 마세요.[2]

debug와 release를 섞지 않는 배포 점검

개발 중에는 로컬 debug 키로 서명한 앱을 설치하고, 실제 배포판은 Play App Signing 인증서로 서명하는 경우가 있습니다. 이때 서버의 assetlinks.json에 debug 지문만 넣으면 개발 환경은 열리지만 스토어에서 받은 앱은 검증되지 않을 수 있어요. 반대로 운영 지문만 넣고 로컬 테스트 앱을 확인하면 개발자가 실패 원인을 서버 문제로 오해할 수 있습니다.[1]

앱 변형 서버 파일에서 비교할 값 테스트 방법
debug 현재 debug 패키지와 인증서 지문 개발 기기에서 검증 후 URL별 테스트
release 배포 패키지와 실제 배포 서명 지문 스토어 설치본 또는 같은 서명으로 만든 테스트본
staging staging host와 staging manifest production 파일과 섞이지 않는지 확인

운영 서버 파일을 바꿀 때는 이전 선언을 바로 지우기보다 배포에 필요한 앱과 경로가 모두 포함됐는지 확인한 뒤 작은 변경으로 공개하세요. JSON이 깨지거나 리디렉션이 생기면 여러 앱이 동시에 영향을 받을 수 있습니다. 변경 전 파일, 변경 시각, 검증한 기기와 명령 결과를 남겨 두면 문제가 생겼을 때 원복 지점을 찾기 쉽습니다. 문제가 계속되면 Android 공식 문제 해결 문서의 항목도 함께 확인하세요.[4]

경로 규칙을 표로 검토하세요

예를 들어 /products/*는 앱에서 열고 /internal/*은 제외하려는 경우, 실제 테스트 URL을 각각 하나씩 준비합니다. /products/42, /internal/42, 규칙에 없는 /help를 비교하면 catch-all이 어느 경로까지 적용되는지 눈으로 확인할 수 있습니다. 이 예시 URL은 진단용 형식일 뿐 실제 서비스 도메인을 대신하지 않으므로, 운영 테스트에서는 자신의 호스트로 바꾸세요.

Sources

  1. [1] Configure website associations and dynamic rules | Android Developers
  2. [2] Verify App Links | Android Developers
  3. [3] Test App Links | Android Developers
  4. [4] Troubleshoot App Links | Android Developers

함께 읽을 글