Skip to content

딥링크로 체크리스트 초대하기

김영균 edited this page Dec 12, 2023 · 1 revision

딥링크

딥링크(DeepLink)는 모바일 애플리케이션에서 특정한 화면으로 사용자를 직접 연결하는 링크입니다.

애플리케이션을 실행하면 홈 화면, 로그인 화면과 같이 기기에 설정된 첫 화면이 나오는데요.

딥링크를 사용하면 앱실행 시 특정 화면으로 바로 이동할 수 있습니다.

iOS의 딥링크 방식은 앱 스킴 방식의 딥링크와 유니버셜 링크가 있습니다.

앱 스킴 딥링크

앱 스킴 방식의 딥링크는 가장 일반적으로 사용할 수 있는 딥링크인데요. 특정 스킴 값을 호출하여 특정 앱을 오픈하는 방식입니다.

출처: URL이란?

앱 스킴 방식도 URL의 구조와 비슷하게 특정 페이지를 구분할 수 있습니다.

{scheme}://{path}

예를들어 오리의 스킴이 openlist라면 로그인화면은 openlist://login이 될 수 있는 것이죠.

앱 스킴 방식은 한계가 존재합니다. 만약 앱 스킴이 중복된다면 어떻게할까요? 앱 스킴은 앱을 구분하는 수단이지만 고유한 값은 아니므로 중복될 수 있습니다.

이렇게 중복되는 경우에는 사용자에게 어떤 앱을 실행시킬 것인지 물어봅니다.

오리의 딥링크

오리는 함께 체크리스트에서 친구을 초대하여 같이 체크리스트를 작성할 수 있는데요. 초대 링크를 통해 애플리케이션을 실행한 사용자는 바로 함께 체크리스트 화면으로 이동합니다.

따라서 오리는 초대 링크를 통해 애플리케이션을 실행한 경우 함께 체크리스트 화면으로 이동하는 기능을 구현해야했습니다.

이 때 오리는 딥링크를 통해 해결했습니다. 오리는 간단하게 앱 스킴 방식을 사용하였는데요.

사용자는 초대하기 버튼을 눌러 openlist://shared-checklists?shared-checklistId=\(id) 링크를 친구에게 전달합니다.

링크를 받은 친구는 링크를 열어 애플리케이션을 실행합니다. 이 때 앱의 상태에 따라 다른 델리게이트 메서드를 통해 딥링크를 파싱할 수 있습니다.

// 만약 종료된 상태에서 실행된다면 
func scene(
  _ scene: UIScene,
  willConnectTo session: UISceneSession,
  options connectionOptions: UIScene.ConnectionOptions
) {
 ...
 if let urlContext = connectionOptions.urlContexts.first {
  // parse link
  // navigate page
 }
}

// 만약 앱이 백그라운드 상태에서 실행된다면
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
  guard let url = URLContexts.first?.url else { return }
  // parse link
  // navigate page
}

url를 파싱하여 이동할 페이지를 알았다면 이제 이동해야할 화면으로 이동해야합니다.

오리는 화면이동을 담당하는 라우터가 있는데요. 따라서 라우터에게 화면 이동을 시키면 될 것 같습니다.

SceneDelegate에서 어떻게 라우터에게 화면이동을 시킬 수 있을까요?

enum DeepLinkTarget {
  /// openlist://shared-checklists?shared-checklistId=\(id)
  case routeToSharedCheckList(id: UUID)
}

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
  var deepLinkSubject: PassthroughSubject<DeepLinkTarget, Never> = .init()
  let component = AppComponent(deepLinkSubject: deepLinkSubject)
  ...
}

라우터는 딥링크 타입을 가지고 있는 deepLinkSubject를 구독하고있어 deepLinkSubject에서 방출된 값에 따라 해당 라우터에서 적절한 화면이동을 할 수 있습니다.

final class WithCheckListRouter {
  private var deepLinkSubject: PassthroughSubject<DeepLinkTarget, Never>
  private var cancellables: Set<AnyCancellable> = []
  private var withCheckListDetailFactory: WithDetailCheckListFactoryable
	
  func bind() {
  deepLinkSubject
    .receive(on: DispatchQueue.main)
    .sink { [weak self] target in
      guard let self else { return }
      switch target {
      case let .routeToSharedCheckList(id):
        self.routeToDetailScene(with: id)
      }
    }
    .store(in: &cancellables)
  }
}

오리들의 애자일한 개발 여정

📜 기획

💢 규칙

🐥 1주차 회의록, 회고

데일리 스크럼

회의록

회고

🐥 2주차 회의록, 회고

데일리 스크럼

회의록

회고

🐥 3주차 회의록, 회고

데일리 스크럼

회고

🐥 4주차 회의록, 회고

데일리 스크럼

회고

🐥 5주차 회의록, 회고

데일리 스크럼

회고

🐥 6주차 회의록, 회고

데일리 스크럼

회고

🍎 iOS

아키텍처 의사 결정 기록

Clone this wiki locally