Android App Links 검증 실패 원인, assetlinks.json·동적 규칙 점검법
AI를 활용하여 생성한 이미지입니다.
Android App Links가 제대로 연결되면 웹 URL을 눌렀을 때 앱이 해당 주소를 처리할 수 있어요. 그런데 manifest만 고쳐서는 해결되지 않는 경우가 많아요. Android는 웹사이트의 /.well-known/assetlinks.json을 읽어 앱과 도메인의 관계를 확인하고, 앱 서명 지문과 manifest의 URL 범위까지 함께 판단해요.[1]
검증 구조를 세 부분으로 나눠요
| 확인 대상 | 실패하면 나타나는 현상 | 확인할 것 |
|---|---|---|
| 웹 서버 | 도메인 검증 실패 | /.well-known/assetlinks.json의 공개 응답, JSON 문법, HTTPS |
| 앱 서명 | 파일은 읽히지만 연결되지 않음 | 패키지 이름과 실제 배포 서명의 SHA-256 지문 |
| 앱 manifest | 일부 경로만 앱에서 열림 | scheme, host, path 범위와 intent filter |
| 사용자 상태 | 검증 후에도 브라우저가 열림 | 도메인 검증 상태와 기본 링크 열기 설정 |
assetlinks.json은 앱이 그 도메인의 링크를 처리할 권한이 있다고 공개 선언하는 파일이에요. 여러 앱이 한 호스트의 서로 다른 경로를 맡을 수도 있고, 한 앱이 여러 웹사이트를 맡을 수도 있어요.[1] 파일에 넣는 패키지 이름이나 지문은 개발자가 기억한 값이 아니라 Play Console의 앱 서명 정보와 현재 빌드에 사용한 인증서에서 확인해야 해요.
Android 15 동적 규칙에서 놓치기 쉬운 점
Android 15(API 35) 이상에서는 assetlinks.json에 동적 규칙을 추가해 경로, fragment, query parameter를 서버 쪽에서 제어할 수 있어요. 기기는 이 파일을 주기적으로 읽어 manifest의 정적 규칙과 합쳐요.[1] Android 14 이하 기기는 새 동적 규칙 필드를 무시하고 기존 manifest 규칙을 사용해요.[1]
동적 규칙은 manifest의 범위를 넓힐 수 없어요. manifest가 선언하지 않은 호스트나 경로를 서버 파일만으로 추가할 수 없다는 뜻이에요.[1] 파일의 필드가 비어 있거나 잘못된 형식이면 동적 규칙 전체가 버려지고 정적 규칙으로 돌아갈 수 있으므로, JSON을 수정할 때는 최소 단위로 배포하세요.[1]
dynamic_app_link_components:
- {"/": "/products/*"}
- {"/": "/internal/*", "exclude": true}
- {"/": "*"}
제외 규칙 뒤에 나머지를 허용하는 catch-all 규칙을 둘지 신중하게 결정해야 해요. 문서 예시처럼 특정 경로를 제외한 뒤 "/": "*"로 나머지를 허용할 수 있지만, 마지막 허용 규칙을 빼면 의도보다 넓은 URL이 앱에서 제외될 수 있어요.[1] 규칙 순서는 단순한 목록 정렬이 아니라 실제 URL 판정 순서로 다뤄야 합니다.
ADB로 기기 상태를 초기화하고 재검증해요
설정 변경 뒤 브라우저를 몇 번 여는 것만으로는 현재 상태를 알기 어려워요. 테스트 기기에서 기존 링크 상태를 초기화하고 다시 검증한 뒤 결과를 읽어보세요. Android 공식 문서가 제시하는 기본 순서는 다음과 같아요.[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 15 이상에서는 서버 파일 변경이 모든 기기에 즉시 적용되지 않을 수 있고, 공식 문서는 캐시와 백그라운드 재검증 때문에 최대 7일이 걸릴 수 있다고 안내해요.[2] 개발 중에는 테스트 기기에서 재검증을 반복하되, 운영 사용자에게 즉시 반영된다고 약속하면 안 돼요.
특정 URL 하나만 따로 진단하는 법
도메인은 verified인데 특정 경로만 브라우저로 열린다면 manifest의 path와 동적 규칙이 충돌했을 가능성이 있어요. Android 공식 테스트 문서는 다음 명령으로 URL 처리 후보와 검증 결과를 확인하는 흐름을 설명해요.[3]
adb shell am start --debug-link -a android.intent.action.VIEW -d "https://example.com/products/42"
진단 결과에는 대상 앱, manifest intent filter가 일치한 항목, 도메인 검증 상태, 동적 규칙과 allow/exclude 판정이 표시돼요.[3] 이 출력은 “앱이 설치돼 있다”와 “이 URL을 앱이 처리할 수 있다”를 구분하는 데 유용해요. 단순히 패키지가 설치된 것을 검증 성공으로 세지 마세요.
자주 틀리는 배포 점검표
- 서버가 JSON 파일을 다른 MIME 형식이나 로그인 페이지로 응답하지 않는지 확인해요.
- 패키지 이름이 debug 빌드와 release 빌드에서 달라지지 않는지 비교해요.
- Play App Signing을 사용한다면 로컬 키가 아니라 실제 배포 서명 지문을 사용해요.[1]
- manifest의 host와 서버 파일의 도메인이 정확히 같은지 확인해요.
- 동적 규칙이 manifest에 없는 범위를 확장하려고 하지 않는지 살펴봐요.
- 규칙을 바꾼 뒤 기기 상태 초기화, 재검증, URL별 테스트를 모두 실행해요.
이전 글에서 다룬 ADB 무선 디버깅의 페어링과 해제 절차는 Android 무선 디버깅 점검 글에서 이어서 확인할 수 있어요. App Links 문제는 네트워크 연결 자체보다 서명, manifest 범위, 서버 파일, 기기 캐시 중 어느 층에서 실패했는지 찾는 작업에 가까워요.