안드로이드 Navigation은 여러 기능을 지원합니다. 오늘은 그기능중 하나인 딥 링크를 구현해보도록 하겠습니다.
그전에 딥링크를 간단하게 알아봅시다
딥링크
{scheme}://{host_path}
딥링크는 일반적으로 아래와 같이 스키마(scheme)와 호스트(host) 및 경로(path)의 두 부분으로 나뉘어져 있습니다. 이러한형식은 평소 웹페이지에 접속할때 자주 볼수 있습니다. 딥링크라는 개념은 모바일과 웹의 구분없이 사용되는 개념입니다. 다만 웹의 특성상 링크가 공개되어있어 대부분 딥링크를 사용하기 때문에 특별히 딥링크라고 부르지는 않습니다.
웹처럼 링크가 공개되어있지 않은 모바일에서 이러한 딥링크를 어떻게 동작할까요?
초기에는 Traditional Deep Links 형태 였습니다 이방식은 DeepLink를 눌렀을때 해당 App이 설치되어 있다면 해당 App 페이지를 보여주고 앱이 없다면 에러나 대체 페이지를 보여줍니다.
에러페이지 문제를 해결하기 위해 Deferred Deep Links 방식이 나왔습니다. 이방식은 앱이 설치되지 않은 경우라면 구글 플레이스토어나 앱스토어로 리다이렉트하여 이동한 뒤, 앱 다운로드가 완료되면 바로 해당 컨텐츠로 이동할 수 있도록 하여 문제를 해결하였습니다.
안드로이드에서는 DeepLinks와 AppLinks를 지원하는데 DeepLinks는 사용자가 안드로이드앱에서 특정 액티비티를 직접 지정할 수 있도록 하는Intent Filter입니다. 딥링크를 사용하면 사용자가 링크를 클릭했을 때 disambiguation dialog가 열리고, 사용자가 지정된 URL을 처리할 수 있는 여러 앱 중 하나를 선택할 수 있습니다. App Links는 웹 사이트의 URL을 기반으로 하는 딥링크이다. 일반 딥 링크에서 한 단계 더 나아간 버전으로, DeepLinks와 달리 앱과 링크가 1:1 관계임을 보장하기에 disambiguation dialog가 나타나는 것이 아니라 앱이 즉시 열린다. 만약 앱이 설치되어있지 않다면 해당 웹페이지로 이동합니다.
이외에도 Firebase의 Dynamic Links를 이용하여 딥링크를 구현할수 있습니다.
이런 Deep Link를 안드로이드에서 일반적으로 구현하려면
AndroidManifest.xml 설정에
<activity android:name=".MainActivity">
<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="myapp"
android:host="product"
android:pathPattern="/.*" />
</intent-filter>
</activity>
이런식으로 스킴과 호스트를 설정하고
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
handleDeepLink(intent)
}
private fun handleDeepLink(intent: Intent?) {
intent?.data?.let { uri ->
val productId = uri.lastPathSegment
productId?.let {
openProductDetail(it)
}
}
}
private fun openProductDetail(productId: String) {
// 제품 상세 화면으로 이동하는 로직을 구현합니다.
// 예: Fragment로 전환하거나 새로운 Activity를 시작합니다.
val fragment = ProductDetailFragment.newInstance(productId)
supportFragmentManager.beginTransaction()
.replace(R.id.container, fragment)
.commit()
}
}
이런식으로 액티비티에 코드상으로 설정해야합니다.
안드로이드 Navigation에서도 DeepLink를 지원합니다.
위에서말한 링크로 동작되는 암시적 딥링크 뿐만아니라 알림이나 위젯을 눌러동작되는 명시적 딥 링크로 있습니다
암시적 딥링크의 경우
<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>
딥 링크는 URI, 인텐트 작업, MIME 유형과 일치할 수 있습니다. 단일 딥 링크에는 여러 일치 유형을 지정할 수 있습니다. 단, 일치되는 유형의 우선순위는 URI 인수가 가장 높고 그다음 작업, MIME 유형순입니다. 위의 코드처럼 프래그먼트 내부에 deepLink태그를 집어 넣어 deepLink의 정보를 입력할수있습니다.
위 방법으로 DeepLink의 정보를 입력할수 있습니다.
- 스키마가 없는 URI는 http 또는 https로 가정됩니다.
- {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과 일치합니다.
- Google에서 개발자가 URI의 소유자임을 확인하도록 하려면 Auto Verify를 선택합니다.
암시적 딥 링크를 사용 설정하려면 앱의 manifest.xml 파일에도 추가해야 합니다.
<activity name=".MainActivity" ...>
...
<nav-graph android:value="@navigation/nav_graph" />
...
</activity>
명시적 딥링크의 경우
명시적 딥 링크는 PendingIntent를 사용하여 사용자를 앱 내 특정 위치로 이동시키는 딥 링크의 단일 인스턴스입니다.
Navigation에서 사용될 경우 NavDeepLinkBuilder 클래스를 사용하여 PendingIntent를 구성할 수 있습니다
기본적으로 NavDeepLinkBuilder는 명시적 딥 링크를 앱의 매니페스트에 선언된 기본 실행 Activity로 시작합니다. Default로 설정된 MainActivity가 된다는 말이죠 NavHost가 다른 Activity에 있다면 딥 링크 빌더를 만들 때 구성요소 이름을 지정해야 합니다.
val pendingIntent = NavDeepLinkBuilder(context)
.setGraph(R.navigation.nav_graph)
.setDestination(R.id.android)
.setArguments(args)
//.setComponentName(DestinationActivity::class.java) // NavHost가 기본실행 Activityrk 아니라면 켜질 액티비티를 선언해줘야함
.createPendingIntent()
참고
https://androidpangyo.tistory.com/169
https://developer.android.com/guide/navigation/design/deep-link?hl=ko
'안드로이드 > AAC(Android Architecture Components)' 카테고리의 다른 글
[AAC] Paging 정의와 적용 (1) | 2024.06.17 |
---|---|
[AAC] Navigation - setupWithNavController (1) | 2024.06.15 |
[AAC] Navigation의 정의와 적용 (0) | 2024.06.10 |
[AAC] Lifecycle 정의와 활용 (0) | 2024.06.07 |
[AAC] LiveData의 정의와 사용 (0) | 2024.06.06 |