The Android Developer Challenge is back! Submit your idea before December 2.

Android 앱 링크 인증하기

Android 앱 링크는 사용자가 앱을 선택할 필요 없이, 웹사이트의 URL을 클릭하면 Android 앱에서 해당 콘텐츠가 바로 열리도록 하는 특별한 유형의 딥 링크립니다.

앱에 Android 앱 링크를 추가하려면 HTTP URL을 사용해 앱 콘텐츠를 여는 인텐트 필터를 정의하고(앱 콘텐츠 딥 링크 만들기의 설명 참고) 앱과 웹사이트 URL을 모두 소유하고 있음을 확인합니다(이 가이드의 설명 참고). 시스템에서 개발자의 URL 소유권이 확인되면 URL 인텐트를 앱에 자동으로 라우팅합니다.

앱과 웹사이트를 모두 소유하고 있음을 확인하려면 다음 단계를 따라야 합니다.

  • manifest에서 자동 앱 링크 확인을 요청합니다. 이렇게 하면 앱이 인텐트 필터에 사용된 URL 도메인에 포함되는지 여부를 확인하도록 Android 시스템에 신호를 보냅니다.
  • 다음 위치에서 디지털 애셋 링크 JSON 파일을 호스팅하여 웹사이트와 인텐트 필터 사이의 관계를 선언합니다.
    https://domain.name/.well-known/assetlinks.json
    .

다음 리소스에서 관련 정보를 찾을 수 있습니다.

  • Android 스튜디오에서 URL 및 앱 색인 생성 지원
  • 명령문 목록 만들기
  • 딥 링크와 앱 링크의 차이

    딥 링크는 사용자가 Android 앱의 특정 활동으로 바로 이동할 수 있게 하는 인텐트 필터입니다. 이 링크 중 하나를 클릭하면 특정 URL을 처리할 수 있는 여러 앱(내가 개발한 앱 포함) 중 하나를 사용자에게 선택하게 하는 명확성 대화상자가 열릴 수 있습니다. 예를 들어 그림 1에서는 사용자가 지도 링크를 클릭했을 때 지도나 Chrome 중 어느 것을 사용하여 링크를 열지 묻는 명확성 대화상자를 보여줍니다.

    그림 1. 명확성 대화상자

    Android 앱 링크는 개발자의 웹사이트에 속한다는 것이 확인된, 웹사이트 URL 기반의 딥 링크입니다. 이 링크 중 하나를 클릭하면 설치되어 있는 앱이 즉시 열리며, 명확성 대화상자는 표시되지 않습니다. 하지만 사용자는 이 링크를 처리하는 기본설정을 나중에 변경할 수 있습니다.

    다음 표에서는 차이점을 더 구체적으로 설명합니다.

    딥 링크앱 링크
    인텐트 URL 스키마 http, https, 맞춤 스키마 http 또는 https 필요
    인텐트 작업 모든 작업 필요: android.intent.action.VIEW
    인텐트 카테고리 모든 카테고리 필요: android.intent.category.BROWSABLEandroid.intent.category.DEFAULT
    링크 확인 없음 HTTPS로 웹사이트에서 제공되는 디지털 애셋 링크 파일 필요
    사용자 환경 어느 앱에서 링크를 열 것인지 묻는 명확성 대화상자가 사용자에게 표시될 수 있음 대화상자 없음. 내 앱이 열려 웹사이트 링크를 처리함
    호환성 모든 Android 버전 Android 6.0 이상

    앱 링크 인증 요청

    앱의 링크 처리 인증을 사용 설정하려면 다음 manifest 코드 스니펫과 같이 앱 manifest의 웹 URL 인텐트 필터 중 하나에서 android:autoVerify="true"를 설정합니다(android.intent.action.VIEW 인텐트 작업 및 android.intent.category.BROWSABLE 인텐트 카테고리가 포함된 앱 manifest에서).

        <activity ...>
    
            <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="http" android:host="www.example.com" />
                <data android:scheme="https" />
            </intent-filter>
    
        </activity>
        

    인텐트 필터 중 하나에 android:autoVerify="true"가 있는 경우 Android 6.0 이상을 실행하는 기기에 앱을 설치하면 시스템이 앱의 인텐트 필터에서 URL과 연관된 모든 호스트를 확인하려고 시도합니다. 이러한 확인 절차는 다음과 같습니다.

    1. 시스템에서 다음이 포함된 모든 인텐트 필터를 검사합니다.
      • 작업: android.intent.action.VIEW
      • 카테고리: android.intent.category.BROWSABLEandroid.intent.category.DEFAULT
      • 데이터 스키마: http 또는 https
    2. Android는 위의 인텐트 필터에 있는 고유한 호스트 이름별로 디지털 애셋 링크에 상응하는 웹사이트를 https://hostname/.well-known/assetlinks.json에서 쿼리합니다.

    시스템에서는 manifest에 있는 모든 호스트에 일치하는 디지털 애셋 링크가 발견되는 경우에만 앱을 지정 URL 패턴의 기본 핸들러로 설정합니다.

    여러 호스트에서 앱 링크 지원

    시스템은 각 웹 도메인에서 호스팅되는 디지털 애셋 링크 파일에 대해 앱의 웹 URL 인텐트 필터의 데이터 요소에서 지정한 모든 호스트를 확인할 수 있어야 합니다. 인증이 실패하면 앱은 앱의 인텐트 필터에서 정의된 URL 패턴 중 어느 것에 대해서도 기본 핸들러로 인증되지 않습니다. 그러면 시스템은 기본적으로 표준 동작을 사용하여 인텐트를 해결합니다(앱 콘텐츠 딥 링크 만들기의 설명 참고).

    예를 들어 다음 인텐트 필터가 사용된 앱은 https://www.example.com/.well-known/assetlinks.jsonhttps://www.example.net/.well-known/assetlinks.json 모두에서 assetlinks.json 파일이 발견되지 않는 경우 인증에 실패합니다.

        <application>
    
          <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="http" android:host="www.example.com" />
              <data android:scheme="https" />
            </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" android:host="www.example.net" />
            </intent-filter>
          </activity>
    
        </application>
        

    동일한 인텐트 필터의 모든 <data> 요소가 함께 병합되어 결합된 속성의 모든 변형을 나타낸다는 점을 기억하세요. 예를 들어 위에서 첫 번째 인텐트 필터에는 HTTPS 스키마만 선언하는 <data> 요소가 있습니다. 하지만 이 요소는 인텐트 필터가 http://www.example.comhttps://www.example.com을 모두 지원하도록 다른 <data> 요소와 결합됩니다. 따라서, URI 스키마와 도메인의 특정 조합을 정의하려면 별도의 인텐트 필터를 만들어야 합니다.

    여러 하위 도메인에서 앱 링크 지원

    디지털 애셋 링크 프로토콜은 인텐트 필터에 있는 하위 도메인을 별도의 고유 호스트로 취급합니다. 따라서 인텐트 필터에 서로 다른 하위 도메인을 가진 여러 호스트가 나열된 경우에는 각 도메인별로 유효한 assetlinks.json을 게시해야 합니다. 예를 들어 다음 인텐트 필터는 허용되는 인텐트 URL 호스트로 www.example.commobile.example.com을 포함합니다. 따라서 유효한 assetlinks.jsonhttps://www.example.com/.well-known/assetlinks.jsonhttps://mobile.example.com/.well-known/assetlinks.json에서 모두 게시해야 합니다.

        <application>
          <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" android:host="www.example.com" />
              <data android:scheme="https" android:host="mobile.example.com" />
            </intent-filter>
          </activity>
        </application>
        

    예를 들어 *.example.com과 같이 와일드 카드를 사용해 호스트 이름을 선언하는 경우에는 루트 호스트 이름(example.com)에 assetlinks.json 파일을 게시해야 합니다. 예를 들어 다음 인텐트 필터가 사용된 앱은 assetlinks.json 파일이 다음 위치에서 게시된 경우 example.com의 모든 하위 이름(예: foo.example.com)과 관련된 인증을 통과합니다. https://example.com/.well- known/assetlinks.json

        <application>
          <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" android:host="*.example.com" />
            </intent-filter>
          </activity>
        </application>
        

    웹사이트 연결 선언하기

    디지털 애셋 링크 JSON 파일을 웹사이트에 게시하여 웹사이트와 연결된 Android 앱을 나타내고 앱의 URL 인텐트를 인증해야 합니다. JSON 파일은 다음 필드를 사용하여 연관된 앱을 식별합니다.

    • package_name: 앱의 build.gradle 파일에서 선언한 애플리케이션 ID입니다.
    • sha256_cert_fingerprints: 앱 서명 인증서의 SHA256 지문 파일입니다. 다음 명령어를 사용하여 자바 keytool을 통해 지문 파일을 생성할 수 있습니다.
          $ keytool -list -v -keystore my-release-key.keystore
          
      이 필드는 디버그 빌드나 프로덕션 빌드와 같이 다양한 버전의 앱을 지원하는 데 사용할 수 있는 여러 지문 파일을 지원합니다.

    다음 예제 assetlinks.json 파일은 com.example Android 앱에 링크 열기 권한을 부여합니다.

        [{
          "relation": ["delegate_permission/common.handle_all_urls"],
          "target": {
            "namespace": "android_app",
            "package_name": "com.example",
            "sha256_cert_fingerprints":
            ["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"]
          }
        }]
        

    웹사이트와 여러 앱 연결하기

    동일한 assetlinks.json 파일 내에서 웹사이트와 여러 앱 간의 연결을 선언할 수 있습니다. 다음 파일 목록은 앱 2개와의 개별적인 연결을 선언하는(https://www.example.com/.well-known/assetlinks.json에 위치함) 명령문 파일의 예시입니다.

        [{
          "relation": ["delegate_permission/common.handle_all_urls"],
          "target": {
            "namespace": "android_app",
            "package_name": "com.example.puppies.app",
            "sha256_cert_fingerprints":
            ["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"]
          }
          },
          {
          "relation": ["delegate_permission/common.handle_all_urls"],
          "target": {
            "namespace": "android_app",
            "package_name": "com.example.monkeys.app",
            "sha256_cert_fingerprints":
            ["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"]
          }
        }]
        

    서로 다른 앱이 같은 웹 호스트에서 다른 리소스 링크를 처리할 수 있습니다. 예를 들어 app1이 https://example.com/articles의 인텐트 필터를 선언하고 app2가 https://example.com/videos의 인텐트 필터를 선언할 수 있습니다.

    참고: 한 도메인에 연결된 여러 앱은 동일한 인증서나 서로 다른 인증서로 서명할 수 있습니다.

    여러 웹사이트와 단일 앱 연결하기

    여러 웹사이트 각각의 assetlinks.json 파일에서 웹사이트와 단일 앱의 연결을 선언할 수 있습니다. 다음 파일 목록은 example.com과 app1의 연결 및 example.net과 app1의 연결을 선언하는 방법의 예시입니다. 첫 번째 목록은 example.com과 app1의 연결을 보여줍니다.

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

        [{
          "relation": ["delegate_permission/common.handle_all_urls"],
          "target": {
            "namespace": "android_app",
            "package_name": "com.mycompany.app1",
            "sha256_cert_fingerprints":
            ["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"]
          }
        }]
        

    다음 목록은 example.net과 app1의 연결을 보여줍니다. 이들 파일은 호스팅되는 위치만 서로 다릅니다(.com.net).

    https://www.example.net/.well-known/assetlinks.json

        [{
          "relation": ["delegate_permission/common.handle_all_urls"],
          "target": {
            "namespace": "android_app",
            "package_name": "com.mycompany.app1",
            "sha256_cert_fingerprints":
            ["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"]
          }
        }]
        

    JSON 인증 파일 게시하기

    다음 위치에서 JSON 인증 파일을 게시해야 합니다.

    https://domain.name/.well-known/assetlinks.json

    다음 사항을 확인하세요.

    • assetlinks.json 파일은 콘텐츠 유형 application/json과 함께 제공됩니다.
    • assetlinks.json 파일은 앱의 인텐트 필터에서 데이터 스키마로 HTTPS를 선언했는지 여부에 관계없이 HTTPS 연결을 통해 액세스할 수 있어야 합니다.
    • assetlinks.json 파일은 리디렉션 없이(301 또는 302 리디렉션 없음) 액세스할 수 있어야 하며 봇이 액세스할 수 있어야 합니다(robots.txt에서 /.well-known/assetlinks.json 크롤링을 허용해야 함).
    • 앱 링크에서 여러 호스트 도메인이 지원되는 경우 각 도메인에서 assetlinks.json 파일을 게시해야 합니다. 여러 호스트에서 앱 링크 지원을 참고하세요.
    • manifest 파일에서 공개적인 액세스가 불가능한 개발/테스트 URL(예: VPN을 사용해서만 액세스 가능)에 앱을 게시하지 마세요. 이런 경우에는 빌드 변형을 구성하여 개발 빌드용으로 다른 manifest 파일을 생성하여 일시적으로 해결할 수 있습니다.

    앱 링크 테스트하기

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

    기존 명령문 파일을 테스트하려면 명령문 목록 생성기와 테스터 도구를 사용하면 됩니다.

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

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

    • android:scheme 속성. 값을 http 또는 https로 사용
    • android:host 속성. 도메인 URL 패턴 사용
    • 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://domain.name:optional_port&
           relation=delegate_permission/common.handle_all_urls
        

    URL 인텐트 테스트하기

    앱과 연결된 웹사이트의 목록을 확인하고 호스팅되는 JSON 파일의 유효성을 확인하고 나면 기기에 앱을 설치합니다. 비동기 인증 프로세스가 완료될 때까지 20초 이상 기다립니다. 다음 명령어를 사용하여 시스템에서 앱이 인증되었는지, 올바른 링크 처리 정책이 설정되었는지 확인합니다.

        adb shell am start -a android.intent.action.VIEW \
            -c android.intent.category.BROWSABLE \
            -d "http://domain.name:optional_port"
        

    테스트 과정을 진행하면서 링크 처리의 현재 시스템 설정을 확인할 수 있습니다. 다음 명령어를 사용하여 연결된 기기의 모든 앱에 적용되는 기존 링크 처리 정책을 가져오세요.

        adb shell dumpsys package domain-preferred-apps
        

    또는 다음을 통해서도 동일하게 처리할 수 있습니다.

        adb shell dumpsys package d
        

    참고: 앱이 설치된 후에 시스템이 인증 프로세스를 완료할 수 있도록 20초 이상 기다립니다.

    이 명령어는 기기에서 정의된 각 사용자 또는 프로필의 목록을 반환합니다. 이 목록은 다음 형식의 헤더가 앞에 표시됩니다.

        App linkages for user 0:
        

    이 헤더 다음에는 다음과 같은 형식으로 각 사용자의 링크 처리 설정 목록이 출력됩니다.

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

    이 목록은 사용자별로 어느 앱이 어느 도메인과 연결되어 있는지 나타냅니다.

    • Package - manifest에 선언된 패키지 이름을 기준으로 앱을 식별합니다.
    • Domains - 이 앱이 처리하는 웹 링크의 호스트 목록 전체를 보여줍니다(공백을 구분 기호로 사용함).
    • Status - 이 앱의 현재 링크 처리 설정을 보여줍니다. 인증을 통과했으며 manifest에 android:autoVerify="true"가 포함된 앱에는 always 상태가 표시됩니다. 이 상태 뒤에 붙는 16진수는 사용자 앱 링크 기본설정의 Android 시스템 레코드와 관련이 있습니다. 이 값은 인증 성공 여부는 나타내지 않습니다.

    참고: 인증이 완료되기 전에 사용자가 앱의 앱 링크 설정을 변경한다면 인증이 실패해도 인증이 성공했다고 잘못 표시될 수 있습니다. 그러나 앱에서 지원되는 링크를 사전 요청 없이 열도록 사용자가 명시적으로 설정한 경우 이 인증 실패는 문제가 되지 않습니다. 이는 프로그램 인증이 있든 없든 상관없이 사용자 환경설정이 우선하기 때문입니다. 따라서 인증이 성공한 경우와 마찬가지로 대화상자가 표시되지 않고 링크가 직접 앱으로 연결됩니다.

    테스트 예시

    앱 링크 인증이 성공하려면 시스템은 앱 인텐트 필터에서 지정되어 있고 앱 링크의 기준을 충족하는 모든 웹사이트와 관련하여 앱을 인증할 수 있어야 합니다. 다음 예에서는 여러 앱 링크가 정의된 manifest 구성을 보여줍니다.

        <application>
    
            <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" android:host="www.example.com" />
                    <data android:scheme="https" 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" 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" 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" 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" android:host="example.com" />
                </intent-filter>
              </activity>
    
        </application>
        

    플랫폼이 위의 manifest에서 인증을 시도하는 호스트의 목록은 다음과 같습니다.

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

    플랫폼이 위의 manifest에서 인증을 시도하지 않는 호스트 목록은 다음과 같습니다.

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

    명령문 목록을 자세히 알아보려면 명령문 목록 만들기를 참고하세요.