티스토리 뷰

핸드폰에서 웹 url을 공유받아서 누르면 내가 설치된 앱으로 바로 이동되는 기능은 누구나 사용해봤을 것이다.

또는 해당 웹이 웹뷰로 뜨더라도, 페이지 내에 있는 '앱 열기' 버튼으로도 바로 이동할 수 있다

(ex. 카카오톡으로 공유받은 유투브 링크, 인스타그램의 오픈카톡 링크)

이러한 기능들은 딥링크 또는 Android 의 App links 또는 iOS의 Universal Links로 처리되어있다. 

오늘은 먼저, Android 의 App Links에 대한 내용을 정리해보겠다.


Android dEvelopers문서에는 링크를 처리하는 방식엔 크게 아래와같은 3가지가 있다고 안내되어있다.

Deep links & Web links & App links

Android developers

구분 딥링크  웹링크 앱링크
기본 스킴 커스텀스킴
ex) myapp://
https 링크 https 링크 + 도메인-앱 검증
Manifest 선언 <intent-filter>
<data android:scheme="myapp" …>
<intent-filter>
<data android:scheme="https" android:host="example.com">
<intent-filter android:autoVerify="true">
<data android:scheme="https" android:host="example.com">
도메인 소유 검증 X X 필요
/.well-known/assetlinks.json 에 패키지명·SHA‑256 지문 등록
앱 설치 O
선택 시 동작
실행 가능한 앱 목록 (Resolver) 노출 실행 가능한 앱 목록 (Resolver) 노출 앱이 설치된 경우 바로 실행 (12+)

앱 설치 X
선택 시 동작
오류 또는 무응답 (등록된 앱만 열 수 있음) 브라우저로 url 열림 브라우저로 url 열림
웹뷰 내
선택 시 동작
스킴처리 불가 -> 타임아웃 처리 필요 동일 브라우저 유지 동일 브라우저 유지 (동일 출처 정책)
주요 용도 앱 내부에서 화면 이동  검증없이 웹 url 처리 공유, 광고 url (UX 최적화)

 

사실상 커스텀스킴과 https링크는 용도가 다르기 때문에 구현하려는 기능의 목적에 따라 선택해서 사용하면 된다.

앱 링크는 기존의 웹링크에 인증 절차를 추가한것이라고 볼 수 있다.

 

App Links

그렇다면 Android App Links 를 사용함으로써 얻을 수 있는 이점은 어떤게 있을까?

  • 개선된 UX 제공
    • url을 등록해놓은 앱으로 선택창 (Resolver)없이 바로 이동시켜줌 -> 사용자 절차 간편
    • 앱이 없으면 동일 url이 브라우저로 열림 -> 앱 설치 유도 가능
  • 보안 강화
    • 앱 설치 시점에 도메인 - 앱 간 검증이 이루어져 다른 앱에서 링크를 가로챌 수 없음
  • 데이터 전달 용이
    • intent.data에 전체 http uri를 전송함 -> 앱에서 url을 쿼리 파라미터를 복원해 앱 내 페이지 복원/유도 가능

앱 링크의 구현방식은 매우 간단하다.

기존 웹링크를 사용하고 있다면, manifest에 코드 한줄을 추가하고 검증에 필요한 json 파일을 업로드하면 된다.

링크를 처음 연동하더라도, 앱 링크를 처리할 Activity를 생성 후 위와 동일한 작업을 하면 된다.

 

1. Manifest 구성

<application>
  // 화면 노출 없는 link 처리 담당 acitivity
  <activity android:name=".link.DeepLinkEntryActivity"
    android:exported="true"
    android:launchMode="singleTask"
    android:theme="@android:style/Theme.NoDisplay"
    android:noHistory="true">
    
    <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:host="*.example.com" />
    </intent-filter>
    
  </activity>
</application>
  • autoVerify="true" :  앱이 intent-filter에 선언된 url 도메인에 포함되는지 여부를 확인하도록 시스템에 알려줌
  • action - VIEW : 브라우저, 다른 앱에서 ACTION_VIEW로 넘어오는 외부 Intent를 허용
  • category - DEFAULT : 암시적 인텐트(컴포넌트를 지정하지 않은 인텐트)에 응답할 수 있도록 허용
  • category - BROWSABLE : 웹 브라우저가 intent-filter에 접근하는 것을 허용
  • data : 앱에서 허용한 url 구성요소

앱 링크 사용을 위한 intent-filter는 반드시 activity 내부에 선언되야한다.

  • autoVerify 값은 <activity>내부에만 선언이 가능 (Service·Receiver 불가)
  • ACTION_VIEW + BROWSABLE 인텐트는 Activity 전용 (Service·Receiver 불가)
  • 외부 앱, 웹에서 들어오는 URI는 화면을 보여주는 컴포넌트가 처리해야하는 원칙

 

2. json 파일 업로드

// https://example.com/.well-known/assetlinks.json
[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app", // 고정 값
    "package_name": "com.example", // 앱의 package 정보
    "sha256_cert_fingerprints": // SHA256 지문
    ["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"]
  }
}]

이제 manifest에 선언한 호스트 경로에 정해진 형식의 json 파일만 업로드하면 끝난다.

만약 앱에서 여러 도메인을 선언해놓았다면, 모든 도메인에 assetlinks.json 파일 업로드가 필요하다.

파일 내에는 json array 값이 들어가있기 때문에, 해당 도메인에서 허용하는 앱이 여러개라면 package_name 값만 바꿔서 배열 내 요소를 추가해주면 된다.

 

 

3. Activity에서 url 처리

 

Activity가 필요하다는 것이 꼭 사용자에게 해당 화면을 보여줘야한다는 뜻은 아니다.

url 처리를 전담하는 Activity 클래스를 생성해 로직 처리 후 즉시 finish 시켜주면, 화면 노출 없이 링크를 처리할 수 있다.

class DeepLinkEntryActivity : Activity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        handleIntent(intent)
    }

    override fun onNewIntent(intent: Intent?) { // singleTask 재호출
        super.onNewIntent(intent)
        handleIntent(intent)
    }

    /** 딥링크 URL → 토큰 파싱 → 메인 화면으로 전달 */
    private fun handleIntent(i: Intent?) {
        val data: Uri? = i?.data

        val ref = data?.getQueryParameter("ref") // ex) ?ref=user1
        // 전역 싱글톤·ViewModel·Nav Args 등 필요에 맞게 전달
        val toMain = Intent(this, MainActivity::class.java).apply {
            putExtra("invite_ref", ref)
            addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or
                     Intent.FLAG_ACTIVITY_SINGLE_TOP)
        }
        startActivity(toMain)
        finish()
    }
}

 

 

여기까지 해주면 아래와 같은 흐름으로 앱 링크가 동작한다

 

앱 설치 시점

  1. 1. PackageManager가 manifest의 <intent-filter android:autoVerify="true"> 와 scheme=https, host=… 정보 기록
  2. https://<host>/.well‑known/assetlinks.json 파일을 확인해 서명, 패키지 비교
  3. 검증 통과 시, Selection state 초기값을 결정 (해당 도메인을 허용한 앱이 한개라면 즉시 enable 처리)
  4. /data/system_ce/0/domain_verifications/domain_verification.db 파일에 검증 결과와 앱 허용 여부(verification_state, user_state) 값 캐싱

URL 선택 시점

  1. url이 선택된 앱(브라우저, 메일 등)에서  암시적 Intent(action=VIEW, data=https://…) 생성
  2. PackageManager에서 해당 도메인을 허용한 intent-filter 매칭
  3. domain_verification.db에 캐싱된 정보 확인
  4. 선택된 앱의 Entry Activity(BROWSABLE, VIEW) 런칭
  5. 필요 시, Activity에서는 intent.data 로 전체 URL을 전달받아 쿼리 획득 가능

 

 


 

참고 자료

 

Android 앱 링크 처리하기  |  App architecture  |  Android Developers

이 페이지는 Cloud Translation API를 통해 번역되었습니다. Android 앱 링크 처리하기 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 그림 1. 딥 링크, 웹 링크, Androi

developer.android.com

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2026/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
글 보관함