[Android] Jetpack Navigation — Migrate to Compose — Deep Link
안드로이드에서 딥링크는 앱에서 특정한 Destination 으로 바로 이동하게 해주는 링크입니다.
Navigation에서는 암시적 딥링크와 명시적 딥링크 두 가지 유형의 딥 링크를 만들 수 있습니다.
명시적 딥 링크
명시적 딥 링크는 앱에서 특정 위치로 유저들을 이동시키는 단일 인스턴스입니다. 대표적인 사례는 알림이나 앱의 위젯에서 지정된 Intent 작업을 수행시 사용됩니다.
사용자가 명시적 딥 링크를 이용해 앱을 열면 백스택은 삭제되고 Deep Link Destination으로 대체됩니다. 그래프가 중첩되어 있을 때 각 계층 구조에 있는 <navigation>
요소의 시작 대상도 백스택에 추가됩니다. 이는 사용자가 Deep Link의 Destination 도착 후 뒤로 버튼을 누르면 앱의 진입점에서 앱으로 들어간 것처럼 Navigation Stack을 다시 위로 탐색합니다.
Navigation에서 명시적 딥 링크를 생성하는 방법은NavDeepLinkBuilder
클래스를 사용하여 PendingIntent
를 구성할 수 있습니다. 혹은 NavController.createDeepLink()
를 사용해서 딥 링크를 만들 수도 있습니다.
val args = Bundle().apply {
putInt("id", 4)
}
val pending = NavDeepLinkBuilder(context)
.setGraph(R.navigation.app_navigation)
.setDestination(R.id.setting_navigation)
.setArguments(args)
.createPendingIntent()
showNotification(pending)
이를 테스트해보기 위해 간단하게 알림을 띄우는 클래스를 생성하고 클릭해보겠습니다.
private fun showNotification(pending: PendingIntent) {
val nm = requireActivity().getSystemService(NOTIFICATION_SERVICE) as NotificationManager
val channelId = "channel_id"
val channelName = "channel_name"
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel =
NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_DEFAULT)
nm.createNotificationChannel(channel)
}
val notify = NotificationCompat.Builder(requireContext(), channelId)
.setContentTitle("DeepLink")
.setContentText("Click!")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(pending)
.build()
nm.notify(1, notify)
}
결과
화면의 딥링크 버튼을 클릭하면 알림이 표시되고 클릭하면 지정했던 PendingIntent가 실해되면서 4라는 값의 매개변수까지 잘 전달된 모습을 볼 수 있습니다.
암시적 딥 링크
암시적 딥 링크는 특정 Destination을 참조합니다. 딥링크는 URI, Intent Action, MIME 유형이 매치됩니다. 단일 딥 링크에는 여러 타입을 매치할 수 있으나 그 우선순위는 URI, Action, 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>
<deepLink app:uri="navigation/{id}" />
암시적 딥 링크를 사용하려면 AndroidManifest.xml
에도 추가해야합니다. Activity 하위의 <nav-graph>
를 추가하고 딥 링크 내비게이션을 지정합니다.
<activity
android:name=".AppActivity"
android:exported="true"
android:theme="@style/Theme.AndroidTheme">
<nav-graph android:value="@navigation/app_navigation"/>
</activity>
암시적 딥링크를 트리거할 때 백 스택의 상태는 암시적 Intent가 Intent.FLAG_ACTIVITY_NEW_TASK
플래그가 설정되어 있는지에 따라 다르게 동작합니다.
- 플래그가 설정되었을 때 : 백 스택 작업이 삭제되고 딥 링크 Destination으로 대체됩니다. 명시적 딥 링크에처럼 중첩된 그래프에서 같은 레벨에 있는 동일한
<navigation>
엘리먼트에 StartDestination도 스택에 함께 추가됩니다. 사용자가 딥 링크 Destination에서 뒤로 버튼을 누르면 앱의 진입점에 들어간 것처럼 Navigation 스택을 다시 위로Navigate
합니다. - 플래그가 설정되지 않을 때 : 딥 링크가 트리거 되었을 때 기존 작업은 이전 작업 스택에 남게 됩니다. 사용자가 뒤로 버튼을 누르면 이전 앱으로 돌아가게 됩니다. 반면 위로 버튼을 누르면 NavGraph 계층의 상위 Destination에서 작업이 시작됩니다.
딥 링크 처리
Navigation
을 사용할 때는 Default launchMode
를 standard
로 설정하는것을 추천합니다. standard
를 사용하면 Navigation
이 handleDeepLink()
를 호출하여 자동으로 딥링크를 처리해줍니다. singleTop
과 같은 launchMode
를 사용하면 Activity가 재사용되는 경우에는 딥 링크 처리가 자동으로 이루어지지 않습니다. 이 경우에는 onNewIntent()
오버라이드 함수에 handleDeepLink()
를 수동으로 처리해야 합니다.
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
navController.handleDeepLink(intent)
}
결과
adb를 이용해서 다음과 같이 딥 링크를 실행하면 아래와 같이 4의 값이 잘 전달된 것을 볼 수 있습니다.
adb shell am start -a android.intent.action.VIEW -d "https://navigation/setting/4"
컴포즈에서 딥 링크 처리
Navigation Compose는 compoable()
의 함수의 일부분을 정의해 딥 링크를 정의할 수 있도록 지원합니다. deepLinks
매개변수에 navDeepLink
함수를 이용해 빠르게 NavDeepLink
객체 리스트들을 만들어 전달 할 수 있습니다.
composable(
route = Setting.routeArgs,
arguments = Setting.arguments,
deepLinks = listOf(
navArgument("id") {
type = NavType.IntType
defaultValue = 0
}
),
) { backStackEntry ->
val id = backStackEntry.arguments?.getInt(KEY_ID) ?: 0
SettingScreen(
id = id
)
}
이런 딥링크를 사용하면 특정 URL이나 Action, MIME 타입을 컴포저블과 연결할 수 있습니다. 이러한 딥 링크 방식은 외부앱에 노출되지 않습니다. 딥 링크를 외부에서 사용할 수 있도록 하려면 적절하게 <intent-filter>
를 AndroidManifest.xml
을 파일에 추가해야 합니다.
<activity …>
<intent-filter>
<data
android:host="setting"
android:scheme="navigation_compose" /> // or https
</intent-filter>
</activity>
결과
adb를 이용해서 딥 링크를 실행해보면 정상적으로 setting화면에 3이 표시되는걸 볼 수 있습니다.
adb shell am start -d "navigation_compose://setting/3" -a android.intent.action.VIEW
마무리
Navigation 에서 딥 링크를 통해 목적지까지 이동하는 방법을 알아보았습니다. 전체 샘플 프로젝트는 아래 링크에서 확인하실 수 있습니다. 👋
목차
- [Android] Jetpack Navigation — Migrate to Compose — Overview
- [Android] Jetpack Navigation — Migrate to Compose — Graph & Destination
- [Android] Jetpack Navigation — Migrate to Compose — DeepLink
- [Android] Jetpack Navigation — Migrate to Compose — Animation
- [Android] Jetpack Navigation — Interaction