인스턴트 앱(Instant App) 특정 웹 링크 연결

참고링크 :

https://developer.android.com/training/app-links/deep-linking

https://developer.android.com/training/app-links/verify-site-associations

https://developers.google.com/digital-asset-links/tools/generator

인스턴트 앱을 만들기는 했으나, 실제 Google Play 배포까지는 또 다른 문제들이 있음.

인스턴트 앱에서 사용할 URL의 실제 웹 링크 소유자 확인이 가능해야 등록이 가능함.

Google Digital Asset Link 참조 : https://developers.google.com/digital-asset-links/

앱 콘텐츠에 대한 딥 링크 만들기

링크 클릭시나 프로그래밍 요청으로 웹 URI 인텐트가 호출되면 안드로이드 시스템에서 아래 동작을 순차적으로 시도함.

  1. URI가 지정된 경우 URI 처리 가능한 사용자 기본 설정 앱을 실행
  2. URI를 처리할 수 있는 앱 실행
  3. 다이얼로그에서 선택 가능한 앱들에서 사용자가 선택

수신 링크를 위한 인텐트 필터 추가

<action> : ACTION_VIEW 인텐트 액션 지정.

<data> : 하나 이상의 <data> 태그 추가.

각 태그는 URI 형식을 나타내며, 최소한 android:scheme 속성이 포함되어야 함.

속성들을 이용하여 URI 유형을 구체화 할 수 있음. android:path, pathPattern, pathPrefix 등

<category> : BROWSABLE 카테고리 포함. Intent 필터가 웹 브라우저에서 접근하기 위해 필요함.

DEFAULT 카테고리도 포함. 앱이 암시적 인텐트에도 응답할 수 있음.

이 방법이 아니라면 인텐트가 앱 구성 요소명을 지정하는 경우에만 적용이 가능함.

<activity
    android:name="com.example.android.GizmosActivity"
    android:label="@string/title_gizmos" >
    <intent-filter android:label="@string/filter_view_http_gizmos">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <!-- Accepts URIs that begin with "http://www.example.com/gizmos” -->
        <data android:scheme="http"
              android:host="www.example.com"
              android:pathPrefix="/gizmos" />
        <!-- note that the leading "/" is required for pathPrefix-->
    </intent-filter>
    <intent-filter android:label="@string/filter_view_example_gizmos">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <!-- Accepts URIs that begin with "example://gizmos” -->
        <data android:scheme="example"
              android:host="gizmos" />
    </intent-filter>
</activity>

위 2개의 인텐트 필터는 <data> 요소에 의해서만 서로 다름.

동일한 필터에 여러 개의 <data> 요소를 포함할 수 있지만 고유한 URL을 선언하려는 경우 별도의 필터로 만들어야 함.

아래의 경우 https://www.example.com 이나 app://open.my.app 만 지원하는 것처럼 보임.

하지만 실제로는 app://www.example.com 이나 https://open.my.app 형식도 지원하게 됨.

<intent-filter>
  ...
  <data android:scheme="https" android:host="www.example.com" />
  <data android:scheme="app" android:host="open.my.app" />
</intent-filter>

보다 자세한 내용은 developer 문서를...

수신 인텐트에서 데이터 읽기

시스템이 인텐트 필터를 통해 액티비티를 시작한다면, 인텐트가 제공하는 데이터를 사용할 수 있음.

getData()나 getAction() 메소드를 호출하여 사용함. 일반적으로 onCreate()나 onStart() 시기에 사용함.

딥 링크 테스트

adb(Android Debug Bridge)를 통해서 액티비티 매니저 툴로 인텐트 필터 URI 지정한 앱을 테스트할 수 있음.

$ adb shell am start -W -a android.intent.action.VIEW -d <URI> <PACKAGE>
$ adb shell am start -W -a android.intent.action.VIEW -d "example://gizmos" com.example.android

Android 앱 링크 확인

안드로이드 앱 링크는 웹 URL이 앱의 특정 컨텐츠로 바로 연결되도록 해주는 특별한 타입의 딥 링크임.

안드로이드 앱 링크를 앱에 추가하려면 HTTP URL을 사용해 인텐트 필터를 정의하고,

앱과 웹 사이트 URL을 모두 소유하고 있는지 확인이 필요함.

시스템이 사용자의 URL 소유권을 확인하면 자동으로 해당 URL 인텐트를 앱으로 라우팅함.

앱과 웹 소유권을 확인하기 위한 단계

딥 링크와 앱 링크의 차이점

딥 링크는 앱의 특정 활동을 직접 입력할 수 있도록 하는 인텐트 필터임.

이러한 링크 중 하나를 클릭하면 사용자가 주어진 URL을 사용할 수 있는 여러 앱 중 하나를 선택할 수 있음.

안드로이드 앱 링크는 웹에 속한 것으로 확인된 웹 URL을 기반으로 하는 딥 링크임.

이 중 하나를 클릭하면 앱이 즉시 열리며, 앱 선택 화면이 나타나지 않음.

사용자가 링크 처리에 대한 선호도를 변경할 수도 있음.

Deep linksApp links
Intent URL schemehttphttps, or a custom schemeRequires http or https
Intent actionAny actionRequires android.intent.action.VIEW
Intent categoryAny categoryRequires android.intent.category.BROWSABLE and android.intent.category.DEFAULT
Link verificationNoneRequires a Digital Asset Links file served on you website with HTTPS
User experienceMay show a disambiguation dialog for the user to select which app to open the linkNo dialog; your app opens to handle your website links
CompatibilityAll Android versionsAndroid 6.0 and higher

앱 링크 확인 요청하기

앱의 링크 처리 확인을 활성화하려면 앱 매니페스트에서 아래를 포함하는 웹 URL 인텐트 필터 중 하나에서 android:autoVerify="true" 설정을 함.

  • <action> : android.intent.action.VIEW
  • <category> : android.intent.category.BROWSABLE, android.intent.category.DEFAULT
  • <data> : http 또는 https
<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과 연결된 호스트를 확인함.

안드로이드 시스템은 위의 인텐트 필터의 각각의 고유한 호스트 이름에 대해 Digital Asset Links 파일을 쿼리함.

ex) https://hostname/.well-known/assetlinks.json

여러 호스트를 위한 앱 링크 지원시

시스템이 매니페스트의 모든 호스트에 대해 일치하는 Digital Asset Links 파일을 찾은 경우에만 앱이 지정된 URL 패턴의 기본 처리기로 설정됨.

<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>

위의 경우 https://www.example.com/.well-known/assetlinks.json 과 https://www.example.net/.well-known/assetlinks.json이 없을 경우 앱 인텐트 필터 확인이 실패함.

여러 서브 도메인을 위한 앱 링크 지원시

Digital Asset Links 프로토콜은 인텐트 필터의 서브 도메인을 유니크한 개별 호스트로 취급함.

서브 도메인이 호스트가 다를 경우 각 도메인에 유효한 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>

위의 경우 https://www.example.com/.well-known/assetlinks.json 와 https://mobile.example.com/.well-known/assetlinks.json가있어야 함.

호스트 명에 와일드카드(ex. *.example.com)를 선언한 경우 루트 호스트에 assethosts.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>

위의 경우 https://example.com/.well-known/assetlinks.json 가 있어야 함.

웹 사이트 연결 선언

Digital Asset Links JSON 파일은 웹 사이트와 연결된 앱을 표시하고 앱 URL 인텐트를 확인하기 위해 게시함.

JSON 파일은 아래 필드들을 사용.

  • package_name : 앱의 build.gradle 에 선언된 앱 ID

  • sha256_cert_fingerprints : 앱의 서명 인증서의 SHA256 fingerprints. 아래 명령으로 얻을 수 있음.

    $ keytool -list -v -keystore my-release-key.keystore

    이 필드는 여러 fingerprints를 지원하며, 디버그와 프로덕션 빌드와 같은 버전의 앱을 지원하는데 사용함.

[{
  "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 파일에서 여러 앱과 연결을 선언할 수 있음.

인스턴트 앱의 경우 각 웹사이트 도메인에 하나의 인스턴트 앱만 지정 가능

[{
  "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"]
  }
}]

서로 다른 앱이 동일한 웹 호스트에서 여러 리소스에 대한 링크 처리 가능함.

ex) app1은 https://example.com/articles에 대한 인텐트 필터를 선언하고 app2는 https://example.com/videos에 대한 인텐트 필터를 선언 할 수 있음.

여러 웹 사이트를 단일 앱과 연결

여러 웹 사이트는 각가의 assetlinks.json 파일에서 동일한 앱을 선언할 수 있음.

아래는 app1과 example.com 및 example.net의 연결을 선언하는 예제임.

  1. 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"] } }]

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

```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 파일의 content-type을 application/json 형식으로 제공.
  • assetlinks.json 파일은 앱의 인텐트 필터가 HTTPS를 데이터 스킴으로 선언하는지 여부와 관계없이 HTTPS 연결을 통해 액세스할 수 있어야 함.
  • assetlinks.json 파일은 리다이렉션(301 또는 302 리다이렉션 아님) 없이 액세스할 수 있어야 함. 로봇(robots.txt) 에 assetlinks.json파일 크롤링을 허용해야 함.
  • 앱 링크가 여러 호스트 도메인을 지원하는 경우 각 도메인에 assetlinks.json 파일을 게시해야 함.
  • 매니페스트 파일에 dev/test URL이 있는 앱을 공개하지 말 것. 예를 들어 공개 키를 사용하여 액세스 할 수 없는 경우(VPN에서만 액세스 할 수 있는 URL 등) 이러한 경우 빌드 variants를 구성하여 dev 빌드에 대한 다른 매니페스트 파일 생성.

앱 링크 테스트

앱 연결 기능 구현시 시스템이 앱과 웹 사이트를 연결하고 URL 요청을 처리할 수 있는지 확인.

기존 명령문 파일을 테스트 하려면 Statement List Generator and Tester 툴을 사용.

https://developers.google.com/digital-asset-links/tools/generator

확인한 호스트 리스트 확인

앱에서 확인해야 하는 관련 호스트 목록을 확인.

인텐트 필터에 다음 속성 및 요소가 포함된 모든 URL 목록을 만듬.

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

이 목록을 사용하여 각 호스트 및 하위 도메인에 Digital Asset Links JSON 파일이 제공되는지 확인.

Digital Asset Links 파일 확인

각 웹 사이트에 대해 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 : 매니페스트에 선언된 패키지 명으로 연결된 앱 표시
  • Domains : 앱이 웹 링크를 처리하는 호스트의 전체 목록 표시. 빈 칸으로 구분.
  • Status : 앱의 현재 링크 처리 설정 표시. 인증을 통과했고, 매니페스트에 android:autoVerify=true 가 포함된 앱은 always를 표시함. 이 이후의 16진수는 시스템의 사용자 앱 연결 환경설정에 대한 기록이며, 이 값이 확인이 성공했는지 여부를 나타내지는 않음.

테스트

앱의 인텐트 필터를 지정하고 앱 링크 기준을 충족하는 모든 웹 사이트로 앱을 인증할 수 있어야 함.

<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>

플랫폼에서 위 목록에서 확인하려는 호스트 목록은 아래와 같음.

확인하지 않으려는 호스트 목록은 아래와 같음.

  • map.example.com (android.intent.category.BROWSABLE 없음)
  • market://example.com (http나 https 스킴이 없음.)


+ Recent posts