반응형

안드로이드 개발자로 실무를 하다보면 딥링크를 다룰 일이 굉장히 많습니다.

프론트엔드 개발자와 협업을 할 때 사용하기도 하고, Push 알림에 targetUri 로 설정하기도 하는 등 활용도가 높은데요.

 

안드로이드에서 딥링크를 처리하는 라이브러리는 다양하게 있습니다만 그중에서 오늘 소개할 라이브러리는 에어비앤비에서 개발하고 오픈소스로 공개한 DeepLinkDispatch 입니다.

 

Activity 에 @DeepLink 어노테이션과 함께 URI 를 등록하면, DeepLinkDispatch 가 요청이 들어왔을 때 적절하게 이동시켜 줍니다. 이때 URI 에 함께 들어온 파라미터 또한 파싱 해주기 때문에 다양한 상황에 대해 유연하게 활용할 수도 있습니다.

 

예제

간단하게 예제를 살펴보겠습니다. 

@DeepLink("example://readystory.com/deepLink/{id}")
class SampleActivity : Activity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    if (intent.getBooleanExtra(DeepLink.IS_DEEP_LINK, false)) {
      val parameters: Bundle = intent.getExtras()
      val id = parameters.getString("id")
      // Do something with id
    }
  }
}

위 코드를 보면 굉장히 간단하게 적용된 것을 확인할 수 있는데요.

@DeepLink 어노테이션에 딥링크 URL 를 설정해주면, 요청이 들어왔을 때 해당 액티비티를 띄워줍니다.

그리고 이때, 위 예제에서 {id} 로 표기된 path parameter 나, 쿼리 파라미터가 있을 경우에는 Activity 의 Intent 에 key-value 형식으로 값이 파싱되어 들어있으니 필요에 따라 꺼내 사용할 수 있습니다.

추가로, DeepLink.IS_DEEP_LINK 를 통해 해당 액티비티 진입이 딥링크를 통해서 들어왔는지 여부를 판단할 수 있기에 딥링크로 진입했을 때와 그렇지 않을 때를 구분지어 처리할 수도 있습니다.

 

위 예제에는 나오지 않았지만 하나의 액티비티에 다수의 딥링크를 적용할 수 있습니다. 따라서 여러 링크를 연결하고 싶은 경우에는 @DeepLink({"A Link", "B Link"}) 형태로 사용하면 되겠습니다.

 

함수에 적용하기

@DeepLink 어노테이션은 Activity 클래스에만 적용할 수 있는 것이 아닙니다. 함수에도 적용할 수 있는데요. 이때 조건은 Java 는 public static 으로 선언된 함수이어야 하고, Kotlin 은 object 내에서 @JvmStatic 어노테이션을 적용한 함수에만 적용 가능합니다. (주의할 점은, companion object 내 함수에는 적용이 불가합니다.)

 

그럼 위 조건에 부합하는 함수이기만 하면 되는걸까요?

아쉽게도 아닙니다. @DeepLink 어노테이션을 함수에 적용할 때는 함수의 리턴 타입에 대해 몇 가지 제한사항이 있습니다.

 

그 중 먼저 Intent 를 반환하는 케이스입니다.

Intent 를 리턴하는 함수에 @DeepLink 를 적용한다는 것은 특정 딥링크를 통해 유입 됐을 시에 어떤 액티비티를 실행할 지에 대해서 어떤 Intent 를 통해 화면을 띄울지에 대해 커스텀 가능하다는 것을 의미합니다.

 

만약 딥링크를 통해 실행시킨 Activity 에 대해 백스택 관리도 하고자 할 경우에는 @DeepLink 를 적용한 함수의 리턴 타입을 TaskStackBuilder 로 선언하시면 되겠습니다. DeepLinkDispatch 라이브러리는 이때 반환된 TaskStackBuilder 의 마지막 Intent 를 사용하여 액티비티를 실행하기 때문에, 딥링크에 의해 호출되는 액티비티의 스택에 어떤 Intent 를 어떤 순서로 쌓을지 커스텀할 수 있습니다.

 

아래는 Java 로 작성된 예시코드입니다.

@DeepLink("http://readystory.com/deepLink/{id}/{name}")
public static TaskStackBuilder intentForTaskStackBuilderMethods(Context context) {
  Intent detailsIntent =  new Intent(context, SecondActivity.class).setAction(ACTION_DEEP_LINK_COMPLEX);
  Intent parentIntent =  new Intent(context, MainActivity.class).setAction(ACTION_DEEP_LINK_COMPLEX);
  TaskStackBuilder  taskStackBuilder = TaskStackBuilder.create(context);
  taskStackBuilder.addNextIntent(parentIntent);
  taskStackBuilder.addNextIntent(detailsIntent);
  return taskStackBuilder;
}

딥링크로 인해 위 함수가 호출된 경우에는 MainActivity 위에 SecondActivity 를 쌓았기 때문에, SecondActivity 가 처음에 보여졌다가 스택에서 제거 된다면 MainActivity 가 보여질 것입니다.

 

만약 상황에 따라 Intent 를 반환해야할수도 있고 TaskStackBuilder 를 반환해야할수도 있는 상황이 있다면 어떻게 해야할까요?

이런 경우에는 DeepLinkDispatch 라이브러리에서 제공해주는 DeepLinkMethodResult 타입을 반환하도록 함수를 선언해야 합니다.

DeepLinkMethodResult 에는 Intent 와 TaskStackBuilder 를 각각 담을 수 있으며, 이때 null 이 아닌 객체를 통해 실행합니다. (만약 둘 다 null 이 아닐 경우에는 TaskStackBuilder 의 우선순위가 더 높습니다.)

 

Custom Annotations

앱 내에 딥링크로 연결해주는 화면이 많아질수록, 반복되는 문자열이 많이 있을 수 있습니다. 예를들어 https:// 등과 같은 스킴이 될 수도 있지만 ready:// 와 같이 앱마다 정의하고 있는 커스텀 스킴, 또는 readystory.com 처럼 호스트 이름 등이 반복될 수 있죠.

그런 경우에 보다 편하게 적용할 수 있도록 DeepLinkDispatch 라이브러리에서는 Custom Annotation 방식을 제공해주고 있습니다. Custom Annotation 을 활용한다면 공통의 prefix 를 자동으로 제공할 수 있습니다.

 

예시를 살펴보겠습니다.

@DeepLinkSpec(prefix = { "app://readystory" })
@Retention(RetentionPolicy.RUNTIME)
public @interface AppDeepLink {
  String[] value();
}

위와 같이 선언한 경우에는 이제 액티비티에서 아래와 같이 사용할 수 있습니다.

// "app://readystory/view_users"
@AppDeepLink({ "/view_users" })
class CustomPrefixesActivity : AppCompatActivity() {
    //...
}

만약 http(s) 형태의 웹 스킴에 대한 prefix 를 제공하기 위한 @WebDeepLink 같은 어노테이션을 만들더라도 다른 커스텀 어노테이션과 함께 사용 가능하니 적극적으로 사용한다면 앱 개발시에 상당히 유용하게 활용 가능합니다.

 

프로젝트에 새롭게 딥링크를 적용해야 하는 니즈가 있으신 분들은 DeepLinkDispatch 라이브러리를 도입해보는 것을 추천합니다.

반응형
반응형