티스토리 뷰

Deep Link, Universal Link, App Link를 간단하게 훑어보자.

 

Deep link - 딥링크

모바일 애플리케이션을 자동으로 열어 앱 내의 특정화면으로 보낼 수 있는 링크

  • 앱 연결의 소요 시간을 단축하고, UX를 개선할 수 있음
  • URL 매개변수를 이용해 토큰/미리 채워진 양식 등의 데이터를 전달할 수 있음

 

Deep link를 선택하면

  • iOS: 앱을 열 것인지 묻는 메시지가 표시되거나
  • Android: 사용할 앱을 묻는 대화상자가 표시되거나

 

Deep link 주소의 구조는 일반적인 https 구조가 아닌 custom한 링크를 가짐

  • custom_scheme://host/path?param=x
  • scheme 부분만 다를 뿐 나머지는 https에서 사용하는 주소처럼 동일하게 설정할 수 있음

 

 

Universal and App links

Universal link(iOS), App link(Android)는 일반적인 Deep link와 다름

  • 웹과 앱을 다 서빙한다는 전제
  • 앱이 설치되어있지 않다면 Depp link 주소로는 아무 것도 서빙할 수 없음.
    • 오류 페이지 같은 페이지만 서빙할 수 있을 것.

 

Universal link(iOS), App link(Android)는 실제 모바일 웹 URL과 바인딩 됨

  • 모바일 웹으로 접속할 때, 앱이 설치되어 있지 않으면 모바일 웹으로 컨텐츠가 서빙됨.
    • 당연한 것 같지만, Deep link에서는 이게 불가능함. Deep link 용 스킴/주소가 필요했던 것.
  • 바인딩 된다는 것은 앱/애플리케이션에 도메인이 할당된다는 것.
    • iOS에서는 연관 도메인 권한을 추가하고, Android에서는 새로운 인텐트 필터를 추가하는 등 애플리케이션 코드에서 몇 가지 추가 설정을 수행해야 함.
  • 앱 - 서버에서 전달하는 Link를 위한 파일을 통해 연결됨.
    • 양방향 인증이 되어 조금 더 안전함.

 

그럼, 사용 예제가 Deep link와 무엇이 다른가?

  • 사실 사용 예제는 Deep link와 같음. 사용자로 하여금 웹 페이지에서 앱으로 끌고 올 수 있다는 것.
  • Web fallback이 지원된다는 것 (앱이 없으면 웹으로 간다)
    • 즉, 앱이 설치되어있지 않아도 모바일 웹 주소로 같은 컨텐츠를 서빙할 수 있다.
    • 위에서 말했듯 Deep link 주소로는 앱이 없다면 할 수 있는 것이 없다.
  • 같은 주소로 웹 서비스, 앱 서비스 둘 다 지원할 수 있다는 것이 사용자로 하여금 더 좋은 UX를 제공할 수 있음.

 

어떻게 사용할 수 있을까?

  • 앞서 이야기했듯 서버에서 Link를 위한 파일을 제공해야 함
    • iOS: apple-app-site-association 파일 (줄여서 AASA 파일이라고도 함)
    • Android: assetlinks.json 파일
  • 그리고 해당 파일들은 아래의 주소로 제공되어야 함
    • iOS: https://my-app.com/.well-known/apple-app-site-association
    • Android: https://my-app.com/.well-known/assetlinks.json

 

  • 주의할 점
    • Content-Typeapplication/json으로 전달되어야 한다.
    • AASA 파일은 확장자가 없다. apple-app-site-association.json으로 표기하지 않도록 주의.

 

 

 

[iOS] apple-app-site-association (AASA) - 유니버셜 링크

특징

  • AASA 파일에는 연결할 주소들을 다 명시해야 한다.
    • 좀 있다 이야기 할 것이지만, iOS와 다르게 Android는 내부 애플리케이션 코드에서 path를 명시한다.
  • AASA 파일의 확장자는 존재하지 않지만, Json 형식으로 작성해야 한다.

 

예제 파일을 보자

{
  "applinks": {
      "details": [
           {
             "appIDs": [ "ABCDE12345.com.example.app", "ABCDE12345.com.example.app2" ],
             "components": [
               {
                  "#": "no_universal_links",
                  "exclude": true,
                  "comment": "Matches any URL whose fragment equals no_universal_links and instructs the system not to open it as a universal link"
               },
               {
                  "/": "/buy/*",
                  "#": "payment_method=SOME",
                  "comment": "Matches any URL whose path starts with /buy/"
               },
               {
                  "/": "/help/website/*",
                  "?": { "lang": "?*" },
                  "exclude": true,
                  "comment": "Matches any URL whose path starts with /help/website/ and instructs the system not to open it as a universal link"
               },
               {
                  "/": "/????/help/*",
                  "?": { "articleNumber": "????" },
                  "comment": "Matches any URL whose path starts with /help/ and which has a query item with name 'articleNumber' and a value of exactly 4 characters"
               }
             ]
           }
       ]
   },
   "webcredentials": {
      "apps": [ "ABCDE12345.com.example.app" ]
   },
    "appclips": {
        "apps": ["ABCED12345.com.example.MyApp.Clip"]
    }
}
  • Universal link에 대한 설정 값들은 applinks key 아래에 위치한다.
  • apps는 왜 빈 배열일까? iOS 12 이하 지원을 위해서는 빈 배열로 제공해야 한다고 함.
  • appID, appIDs는 앱 ID를 작성하면 된다. Apple 개발자 페이지에서 확인할 수 있음.
  • components 부분에서 어떤 경로를 앱으로 연결할지 구성할 수 있음.
    • 오래된 버전에서는 paths를 통해 인식했었는데, 이젠 components로 다양하게 설정이 가능해졌음.
  • components 내에서 path마다 패턴을 지원하고, /, #, comment 등 여러 옵션을 지원.
    • /: URL path pattern (default: * (everything))
    • ?: URL query parameter pattern (default: *)
    • #: URL fragment pattern (default: *)
    • exclude: stop pattern matching pattern (default: false)
    • comment: information about URLs
    • 하위 필드에 대한 자세한 내용은 공식문서를 참조하자.
  • 참고) WWDC에서도 나왔었다.

 

어떻게 동작할까?

  • 애플리케이션이 설치되거나 업데이트 될 때, iOS는 서버에서 이 파일을 다운로드하고 유효성을 검사함
    • iOS 14 / macOS BigSur부터는 이러한 파일을 캐시하는 Apple CDN을 도입해 CDN에 없는 경우에만 서버에서 다운로드 함
  • 설정된 도메인에 요청하는 경우, OS 단에서 앱을 연결해주는 것으로 이해함

 

주의

  • iOS Universal link의 경우, 구앱까지 함께 트리거 될 수 있다는 것에 주의하자.
    • 예시로, 이번에 새롭게 AASA 파일에 특정 endpoint를 추가했다고 하자.
    • 단순하게는 "이제 새로운 앱에서 이 endpoint에 맞게 뷰를 띄워주겠지" 라고 생각하기 쉬운데, 그것도 맞지만 "구앱에서도 동작한다"는 것을 주의해야 한다. 다시 말하면 구앱이 설치된 iOS 환경에서 추가한 endpoint를 웹에서 접근할 때 구앱이 켜진다는 것이다.
    • 고로, 앱 개발자 단에서 Universal link를 적용 시에 만약 Universal link로 트리거 되었는데 매핑되어 있지 않은 endpoint라면 웹 뷰 또는 웹 브라우저로 띄워주도록 하는 방어코드를 추가하는 것이 좋을 것 같다.

 

 

[Android] assetlinks.json - 앱 링크

위에서 이야기했듯 Android assetlinks.json은 Apple과 달리 연결 구성 설정들을 애플리케이션 코드에서 처리하게 된다.

  • 그렇기에 assetlinks.json에는 도메인에 해당되는 앱 정보만 들어가게 된다.

 

예제 파일을 보자

[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.binux.test",
    "sha256_cert_fingerprints": 
    ["22:9D:F9:72:D3:14:99:50:D8:EE:B9:12:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:A3:4F:DE:15:F5"]
  }
}]
  • package_nameAndroidManifest 파일과 동일해야만 함.
  • sha256_cert_fingerprints는 앱 서명 인증서의 SHA256 지문을 의미한다.
    • keytool 등을 이용해 fingerprint를 만들어적용해야 한다.
      • example - my-key는 알맞게 수정해 활용
        keytool -list -v -keystore my-key.keystore

 

다수의 앱과 연결하고 싶다면, 한 assertlinks.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"]
    }
}]

 

Android 측에서 이를 이용하기 위한 용도로 intent-filter를 사용해야 한다.

<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="my_domain.app"
      android:pathPrefix="/my_path"/>
</intent-filter>

<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="my_domain.app"
      android:pathPrefix="/my_second_path"/>
</intent-filter>
  • Android 개발은 잘 모르기에 자세한 내용은 공식문서를 참고하자.
320x100
반응형
댓글
반응형
250x250
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함