Android에서 딥 링크는 앱 내의 특정 대상으로 직접 이동할 수 있게 하는 링크입니다.
앱에서 명시적 딥 링크와 암시적 딥 링크라는 두 가지 유형의 딥 링크를 지원할 수 있습니다. 딥 링크를 구현하는 방법은 앱에서 사용하는 그래프
유형—XML or programmatic—에 따라 다릅니다.
명시적 딥 링크 만들기
명시적 딥 링크는 PendingIntent를 사용하여 사용자를 앱 내 특정 위치로 이동시키는 딥 링크의 단일 인스턴스입니다. 예를 들어 명시적 딥 링크를 알림 또는 앱 위젯의 일부로 표시할 수 있습니다.
사용자가 명시적 딥 링크를 통해 앱을 열면 작업 백 스택이 삭제되고 딥 링크 대상으로 대체됩니다. 그래프를 중첩할 때 각 중첩 수준의 시작 대상, 즉 계층 구조에 있는 각 <navigation> 요소의 시작 대상도 스택에 추가됩니다.
즉, 사용자가 딥 링크 대상에서 뒤로 버튼을 누르면 마치 진입점에서 앱에 들어간 것처럼 탐색 스택을 다시 위로 탐색합니다.
프로그래매틱 그래프
탐색 그래프가 프로그래매틱 방식으로 정의된 경우 (탐색 Compose 또는 Kotlin DSL에서 일반적임) TaskStackBuilder를 사용하여 딥 링크 PendingIntent를 만드는 것이 좋습니다.
val id = "exampleId"
val context = LocalContext.current
val deepLinkIntent = Intent(
Intent.ACTION_VIEW,
"https://www.example.com/profile/$id".toUri(),
context,
MyActivity::class.java
)
val pendingIntent: PendingIntent? = TaskStackBuilder.create(context).run {
addNextIntentWithParentStack(deepLinkIntent)
getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
}
XML 그래프
아래 예와 같이 NavDeepLinkBuilder
클래스를 사용하여 PendingIntent,
를 구성할 수 있습니다. 제공된 컨텍스트가 Activity가 아니라면 생성자는 실행할 기본 활동으로 PackageManager.getLaunchIntentForPackage()를 사용합니다(사용 가능한 경우).
Kotlin
val pendingIntent = NavDeepLinkBuilder(context) .setGraph(R.navigation.nav_graph) .setDestination(R.id.android) .setArguments(args) .createPendingIntent()
Java
PendingIntent pendingIntent = new NavDeepLinkBuilder(context) .setGraph(R.navigation.nav_graph) .setDestination(R.id.android) .setArguments(args) .createPendingIntent();
기본적으로 NavDeepLinkBuilder는 명시적 딥 링크를 앱의 매니페스트에 선언된 기본 실행 Activity로 시작합니다. NavHost가 다른 활동에 있다면 딥 링크 빌더를 만들 때 구성요소 이름을 지정해야 합니다.
Kotlin
val pendingIntent = NavDeepLinkBuilder(context) .setGraph(R.navigation.nav_graph) .setDestination(R.id.android) .setArguments(args) .setComponentName(DestinationActivity::class.java) .createPendingIntent()
Java
PendingIntent pendingIntent = new NavDeepLinkBuilder(context) .setGraph(R.navigation.nav_graph) .setDestination(R.id.android) .setArguments(args) .setComponentName(DestinationActivity.class) .createPendingIntent();
ComponentName이 있으면 빌더로 직접 전달할 수 있습니다.
Kotlin
val componentName = ... val pendingIntent = NavDeepLinkBuilder(context) .setGraph(R.navigation.nav_graph) .setDestination(R.id.android) .setArguments(args) .setComponentName(componentName) .createPendingIntent()
Java
ComponentName componentName = ...; PendingIntent pendingIntent = new NavDeepLinkBuilder(context) .setGraph(R.navigation.nav_graph) .setDestination(R.id.android) .setArguments(args) .setComponentName(componentName) .createPendingIntent();
기존 NavController가 있으면 NavController.createDeepLink()를 사용하여 딥 링크를 만들 수도 있습니다.
암시적 딥 링크 만들기
암시적 딥 링크는 앱의 특정 대상을 참조합니다. 딥 링크가 호출되면(예: 사용자가 링크를 클릭한 경우) Android는 참조 대상에 앱을 열 수 있습니다.
딥 링크는 URI, 인텐트 작업, MIME 유형과 일치할 수 있습니다. 단일 딥 링크에는 여러 일치 유형을 지정할 수 있습니다. 단, 일치되는 유형의 우선순위는 URI 인수가 가장 높고 그다음 작업, MIME 유형순입니다.
프로그래매틱 그래프
탐색 그래프를 프로그래매틱 방식으로 정의하는 경우 (탐색 Compose 또는 Kotlin DSL 사용) 코드에서 딥 링크를 정의합니다.
Compose
탐색 Compose에서 deepLinks 매개변수를 사용하여 composable() 대상 빌더의 일부로 딥 링크를 정의할 수 있습니다. 만들 수 있는
NavDeepLink 객체 목록을 허용합니다.
navDeepLink() 함수를 사용하여
@Serializable
data class Profile(val id: String)
val uri = "https://www.example.com"
composable<Profile>(
deepLinks = listOf(
navDeepLink<Profile>(basePath = "$uri/profile")
)
) { backStackEntry ->
val profile: Profile = backStackEntry.toRoute()
ProfileScreen(id = profile.id)
}
Kotlin DSL
Kotlin DSL을 사용하는 경우 대상
블록 내에서
deepLink() 빌더 함수를 사용하여 딥 링크를 정의할 수 있습니다.
@Serializable
data class Profile(val id: String)
val uri = "https://www.example.com"
fragment<ProfileFragment, Profile> {
deepLink<Profile>(basePath = "$uri/profile")
}
프로그래매틱 그래프의 인텐트 필터 추가
프로그래매틱 탐색 그래프는 런타임에 빌드되므로 탐색
구성요소는 일치하는 <intent-filter> 요소
를 AndroidManifest.xml에서 자동으로 생성할 수 없습니다. 대신 적절한
<intent-filter> 요소를 수동으로 추가해야 합니다.
이전 예에서 딥 링크를 사용 설정하려면 매니페스트의
상응하는 <activity> 요소 내부에 다음을 추가합니다.
<activity …>
<intent-filter>
...
<data android:scheme="https" android:host="www.example.com" />
</intent-filter>
</activity>
XML 그래프
XML 기반 그래프에서 암시적 딥 링크를 만들려면 XML에서 직접
<deepLink> 요소를 정의하거나 Navigation Editor를 사용하면 됩니다.
다음은 URI, 작업 및 MIME 유형을 포함하는 딥 링크의 예입니다.
<fragment android:id="@+id/a"
android:name="com.example.myapplication.FragmentA"
tools:layout="@layout/a">
<deepLink app:uri="www.example.com"
app:action="android.intent.action.MY_ACTION"
app:mimeType="type/subtype"/>
</fragment>
Navigation Editor를 사용하여 다음과 같이 대상으로 연결되는 암시적 딥 링크를 만들 수도 있습니다.
- Navigation Editor의 Design 탭에서 딥 링크 대상을 선택합니다.
- Attributes 패널의 Deep Links 섹션에서 +를 클릭합니다.
표시되는 Add Deep Link 대화상자에서 딥 링크의 정보를 입력합니다.
다음에 유의하세요.
- 스키마가 없는 URI는
http또는https로 가정됩니다. 예를 들어www.google.com은http://www.google.com및https://www.google.com과 모두 일치합니다. {placeholder_name}형식의 경로 매개변수 자리표시자는 1개 이상의 문자와 일치합니다. 예를 들어http://www.example.com/users/{id}는http://www.example.com/users/4와 일치합니다. 탐색 구성요소는 자리표시자 값을 적절한 유형으로 파싱하려고 시도합니다. 자리표시자 이름을 딥 링크 대상에 관해 정의된 인수와 일치시켜 정의된 동일한 이름의 인수가 정의되어 있지 않으면 인수 값에 기본String유형이 사용됩니다. .* 와일드 카드를 사용하면 0개 이상의 문자와 일치시킬 수 있습니다.- 쿼리 매개변수 자리표시자는 경로 매개변수 대신 또는 경로 매개변수와 함께 사용할 수 있습니다. 예를 들어
http://www.example.com/users/{id}?myarg={myarg}는http://www.example.com/users/4?myarg=28과 일치합니다. - 기본값 또는 null을 허용하는 값으로 정의된 변수의 쿼리 매개변수 자리표시자는 일치할 필요가 없습니다. 예를 들어
http://www.example.com/users/{id}?arg1={arg1}&arg2={arg2}는http://www.example.com/users/4?arg2=28또는http://www.example.com/users/4?arg1=7과 일치합니다. 경로 매개변수에서는 그렇지 않습니다. 예를 들어http://www.example.com/users?arg1=7&arg2=28은 필수 경로 매개변수가 제공되지 않았기 때문에 위의 패턴과 일치하지 않습니다. - 관련 없는 쿼리 매개변수는 딥 링크 URI 일치에 영향을 주지 않습니다. 예를 들어
http://www.example.com/users/{id}는extraneousParam이 URI 패턴에 정의되어 있지 않더라도http://www.example.com/users/4?extraneousParam=7과 일치합니다.
- 스키마가 없는 URI는
(선택사항) Google에서 개발자가 URI의 소유자임을 확인하도록 하려면 Auto Verify를 선택합니다. 자세한 내용은 Android App Links 인증하기를 참고하세요.
Add를 클릭합니다. 선택한 대상에 딥 링크가 있음을 나타내는 링크 아이콘
이 대상 위에 표시됩니다.Code 탭을 클릭하여 XML 뷰로 전환합니다. 다음과 같이 중첩된
<deepLink>요소가 대상에 추가되었습니다.<deepLink app:uri="https://www.google.com" />
XML 기반 그래프의 암시적 딥 링크를 사용 설정하려면 앱의 manifest.xml 파일에도 추가해야 합니다. 다음 예와 같이 기존 탐색 그래프를 가리키는 활동에 단일 <nav-graph>
요소를 추가합니다.
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myapplication"> <application ... > <activity name=".MainActivity" ...> ... <nav-graph android:value="@navigation/nav_graph" /> ... </activity> </application> </manifest>
프로젝트를 빌드할 때 탐색 구성요소는 <nav-graph>
요소를 생성된 <intent-filter> 요소로 대체하여 탐색 그래프의 모든 딥 링크
와 일치시킵니다.
암시적 딥 링크 및 백 스택
암시적 딥 링크를 트리거할 때 백 스택의 상태는
암시적 Intent가
Intent.FLAG_ACTIVITY_NEW_TASK
플래그와 함께 실행되었는지에 따라 다릅니다.
- 플래그가 설정되면 작업 백 스택이 삭제되고 딥 링크 대상으로 대체됩니다. 명시적 딥 링크와 마찬가지로 그래프를 중첩할 때 각 중첩 수준의 시작 대상, 즉 계층 구조에 있는 각
<navigation>요소의 시작 대상도 스택에 추가됩니다. 즉, 사용자가 딥 링크 대상에서 뒤로 버튼을 누르면 마치 진입점에서 앱에 들어간 것처럼 탐색 스택을 다시 위로 탐색합니다. - 플래그가 설정되지 않으면 암시적 딥 링크가 트리거된 이전 앱의 작업 스택에 남게 됩니다. 이 경우 뒤로 버튼을 누르면 다시 이전 앱으로 돌아가는 반면 위로 버튼을 누르면 탐색 그래프 내 계층 구조의 상위 대상에서 앱 작업이 시작됩니다.
딥 링크 처리
탐색을 사용할 때는 항상 기본
launchMode인 standard
을 사용하는 것이 좋습니다. standard 시작 모드를 사용하면 탐색이 Intent 내의 명시적 또는 암시적 딥 링크를 처리하기 위해 handleDeepLink()를 호출하여 자동으로 딥 링크를 처리합니다. 그러나 singleTop과 같은 다른 launchMode를 사용할 때 Activity가 재사용되는 경우에는 딥 링크 처리가 자동으로 이루어지지 않습니다. 이 경우에는 다음 예시와 같이 onNewIntent()의 handleDeepLink()를 수동으로 호출해야 합니다.
Kotlin
override fun onNewIntent(intent: Intent?) { super.onNewIntent(intent) navController.handleDeepLink(intent) }
자바
@Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); navController.handleDeepLink(intent); }