앱 링크 테스트

앱 연결 기능을 구현할 때는 연결 기능을 테스트하여 시스템이 앱을 웹사이트와 연결하고 URL 요청을 예상대로 처리할 수 있는지 확인해야 합니다.

기존 상태 파일을 테스트하려면 상태 파일 목록 생성기 및 테스터 도구를 사용하면 됩니다.

다음 섹션에서는 앱 링크 인증을 수동으로 테스트하는 방법을 설명합니다. 원하는 경우 Play 딥 링크 도구 또는 Android 스튜디오 앱 링크 어시스턴트에서 확인을 테스트할 수 있습니다.

인증할 호스트 목록 확인하기

테스트할 때 시스템에서 앱에 관해 확인해야 하는 연결된 호스트 목록을 확인해야 합니다. 상응하는 인텐트 필터에 다음 속성과 요소가 포함된 모든 URL의 목록을 만듭니다.

  • 값이 http 또는 https인 android:scheme 속성
  • 도메인 URL 패턴이 있는 android:host 속성
  • android.intent.action.VIEW 작업 요소
  • android.intent.category.BROWSABLE 카테고리 요소

이 목록을 사용하여 각 이름이 지정된 호스트 및 하위 도메인에 디지털 애셋 링크 JSON 파일이 제공되는지 확인합니다.

디지털 애셋 링크 파일 확인하기

각 웹사이트에서 Digital Asset Links API를 사용하여 디지털 애셋 링크 JSON 파일이 올바르게 호스팅되고 정의되어 있는지 확인합니다.

https://digitalassetlinks.googleapis.com/v1/statements:list?
   source.web.site=https://<var>domain.name</var>:<var>optional_port</var>&amp;
   relation=delegate_permission/common.handle_all_urls

동적 앱 링크의 경우 관계 확장 프로그램도 확인할 수 있습니다.

https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://www.example.com&relation=delegate_permission/common.handle_all_urls&return_relation_extensions=true

테스트 프로세스의 일환으로 링크 처리를 위한 현재 시스템 설정을 확인할 수 있습니다. 다음 명령어를 사용하여 연결된 기기의 모든 앱에 대한 기존 링크 처리 정책 목록을 가져옵니다.

adb shell dumpsys package domain-preferred-apps

다음 명령어는 동일한 작업을 수행합니다.

adb shell dumpsys package d

이 명령어는 기기에 정의된 각 사용자 또는 프로필의 목록을 반환하며, 그 앞에는 다음 형식의 헤더가 있습니다.

App linkages for user 0:

이 헤더 다음에 출력은 다음 형식을 사용하여 해당 사용자의 링크 처리 설정을 나열합니다.

Package: com.android.vending
Domains: play.google.com market.android.com
Status: always : 200000002

이 목록은 해당 사용자의 어떤 도메인에 어떤 앱이 연결되어 있는지 보여줍니다.

  • Package - 매니페스트에 선언된 패키지 이름으로 앱을 식별합니다.
  • Domains - 이 앱이 처리하는 웹 링크의 전체 호스트 목록을 표시합니다. 공백을 구분자로 사용합니다.
  • Status - 이 앱의 현재 링크 처리 설정을 표시합니다. 인증을 통과하고 매니페스트에 android:autoVerify="true"가 포함된 앱은 always 상태를 표시합니다. 이 상태 뒤의 16진수는 사용자의 앱 연결 환경설정에 관한 Android 시스템의 기록과 관련이 있습니다. 이 값은 확인 성공 여부를 나타내지 않습니다.

테스트 예시

앱 링크 인증이 성공하려면 시스템이 앱 링크 기준을 충족하는 지정된 인텐트 필터에 지정한 각 웹사이트에서 앱을 인증할 수 있어야 합니다. 다음 예시에서는 여러 앱 링크가 정의된 매니페스트 구성을 보여줍니다.

<activity android:name="MainActivity">
        <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" />
            <data android:scheme="https" />
            <data android:host="www.example.com" />
            <data android:host="mobile.example.com" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data android:scheme="https" />
            <data android:host="www.example2.com" />
        </intent-filter>
    </activity>

    <activity android:name="SecondActivity">
        <intent-filter>
            <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" />
            <data android:host="account.example.com" />
        </intent-filter>
    </activity>

      <activity android:name="ThirdActivity">
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:scheme="https" />
            <data android:host="map.example.com" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data android:scheme="market" />
            <data android:host="example.com" />
        </intent-filter>
      </activity>

</application>

플랫폼이 이전 매니페스트에서 확인하려고 시도하는 호스트 목록은 다음과 같습니다.

www.example.com
mobile.example.com
www.example2.com
account.example.com

플랫폼이 이전 매니페스트에서 확인을 시도하지 않는 호스트 목록은 다음과 같습니다.

map.example.com (it does not have android.intent.category.BROWSABLE)
market://example.com (it does not have either an "http" or "https" scheme)

문 목록에 대한 자세한 내용은 문 목록 만들기를 참조하세요.

Android 17부터는 활동 관리자 (am start) 명령어와 함께 --debug-link 플래그를 사용하여 시스템이 특정 URL을 확인하는 방법을 진단할 수 있습니다. 이 도구는 의도와 일치하는 후보 앱의 세부적인 분석과 함께, 확인 중에 평가된 앱 매니페스트 및 assetlinks.json 파일 (동적 앱 링크의 경우)의 특정 규칙을 제공합니다.

특정 URL의 링크 확인을 테스트하려면 터미널 창에서 다음 명령어를 실행합니다.

adb shell am start --debug-link -a android.intent.action.VIEW -d "https://xyz.com/foo"

진단 출력은 App Link Resolution Debug 헤더 아래에 출력되며 해결 프로세스를 이해하는 데 도움이 되는 다음 섹션이 포함되어 있습니다.

  • 타겟 세부정보: 패키지 이름과 타겟 활동으로 일치하는 각 후보 앱을 식별합니다.
  • 인텐트 필터 일치 (AndroidManifest.xml): 매니페스트 인텐트 필터의 어떤 정적 속성 (예: scheme, host, path, pathPrefix, pathPattern)이 URI와 일치하는지 보여줍니다.
  • 앱 링크 확인: 현재 도메인 확인 상태 (예: STATE_SUCCESS)를 표시합니다.
  • 동적 앱 링크: 앱이 assetlinks.json 파일에서 동적 앱 링크 일치 규칙을 사용하는 경우 이 섹션에는 URI에 대해 평가된 모든 규칙이 나열됩니다. 각 규칙은 일치하는 URI 필터 (예: 경로 프리픽스 또는 패턴)와 allow 필드를 나타냅니다.
    • allow = 0: 허용/포함 규칙 (allow: true). 이 규칙이 일치하면 앱에서 URI를 열 수 있습니다.
    • allow = 1: 차단/제외 규칙 (allow: false / exclude: true). 이 규칙이 일치하면 앱에서 URI를 열 수 없습니다.
    • 참고: 빈 필터 문자열 (filter =)은 도메인의 모든 경로와 일치하는 빈 경로 프리픽스를 나타냅니다 (와일드 카드 또는 포괄적 역할).

디버그 출력 예시

assetlinks.json 파일에 동적 규칙을 정의하여 /foo*를 제외하고 다른 모든 경로를 허용하는 https://xyz.com 도메인과 연결된 앱 (com.example.xyzapp)을 생각해 보세요.

[
  {
    "relation": [
      "delegate_permission/common.handle_all_urls"
    ],
    "target": {
      "namespace": "android_app",
      "package_name": "com.example.xyzapp",
      "sha256_cert_fingerprints": ["..."]
    },
    "relation_extensions": {
      "delegate_permission/common.handle_all_urls": {
        "dynamic_app_link_components": [
          {"/": "/foo*", "exclude": true},
          {"/": "*"}
        ]
      }
    }
  }
]

--debug-link를 사용하여 URL https://xyz.com/foo을 진단할 때:

adb shell am start --debug-link -a android.intent.action.VIEW -d "https://xyz.com/foo"

이 명령어는 다음 진단 분석을 출력합니다.

--- App Link Resolution Debug ---

URI: https://xyz.com/foo
Resolution: Ambiguous (Multiple apps or Browser fallback)
This usually happens when multiple apps can handle the link and no default is set.

All Matching Candidates:

Target:
  Package: com.example.xyzapp
  Activity: com.example.xyzapp.MainActivity

  Intent Filter Match (AndroidManifest.xml)
    Scheme: 'https' matched android:scheme="https"
    Host: 'xyz.com' matched android:host="xyz.com"

App Link Verification:
  Verification status: STATE_SUCCESS
  Dynamic App Links:
    -> Matched Rule 0: UriRelativeFilterGroup { allow = 1, uri_filters = {UriRelativeFilter { uriPart = PATH, patternType = PREFIX, filter = /foo }},  }
    -> Matched Rule 1: UriRelativeFilterGroup { allow = 0, uri_filters = {UriRelativeFilter { uriPart = PATH, patternType = PREFIX, filter =  }},  }

Target:
  Package: org.chromium.webview_shell
  Activity: org.chromium.webview_shell.WebViewBrowserActivity

  Intent Filter Match (AndroidManifest.xml)
    Scheme: 'https' matched android:scheme="https"

---------------------------------

Starting: Intent { act=android.intent.action.VIEW dat=https://xyz.com/foo }

이 예시에서 시스템은 assetlinks.json의 두 가지 동적 앱 링크 규칙을 평가했습니다.

  • 규칙 0 (allow = 1, filter = /foo): {"/": "/foo*", "exclude": true}에서 생성된 이 규칙은 /foo 경로 프리픽스로 시작하는 URL을 차단하는 제외 규칙(allow: false)입니다.
  • 규칙 1 (allow = 0, filter =): {"/": "*"}에서 생성된 이 규칙은 빈 경로 프리픽스 (filter =)가 있는 포함 규칙 (allow: true)으로, xyz.com 아래의 모든 경로와 일치합니다 (모두 포함).

이 시나리오에서 해결 방법이 작동하는 방식:

  1. 규칙 0과 규칙 1은 모두 URL https://xyz.com/foo과 일치합니다.
  2. 동적 앱 링크 규칙은 위에서 아래로 순서대로 평가됩니다(첫 번째 일치 규칙이 적용됨).
  3. 규칙 0은 문 목록에서 먼저 표시되고 제외 규칙 (allow = 1)이므로 일반 허용 규칙 (규칙 1)보다 우선 적용됩니다.
  4. 따라서 앱이 https://xyz.com/foo 처리에서 제외되어 시스템이 브라우저로 대체되거나 명확성 대화상자가 표시됩니다.