Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

딥링크 - 01 #16

Open
Brandnew-one opened this issue Dec 19, 2022 · 0 comments
Open

딥링크 - 01 #16

Brandnew-one opened this issue Dec 19, 2022 · 0 comments
Assignees
Labels

Comments

@Brandnew-one
Copy link
Owner

딥링크

프로젝트 진행 중 FCM을 이용해 날라온 푸시를 클릭 했을 때 관련 내용을 앱 내에서 화면전환 해서 보여주는 기능이 필요했다. (ex 카카오톡 푸시를 눌렀을 때 해당 대화방으로 이동)

이런 기능등을 처리할 때 딥링크, 앱링크, 유니버셜 링크 등등을 들어보긴 했지만 한번도 구현해본적은 없어서 이번기회에 한번 정리해보려고 한다. SwiftUI를 이용해서 구현해야 한다는 제약사항이 있어 아쉽긴 하지만 기회가 된다면 UIKit을 이용한 프로젝트에도 정리하는 시간을 가져볼 예정이다.

용어정리 부터 하고 넘어가보자

딥링크

특정 주소 혹은 값을 입력하면 앱이 실행되거나 앱 내 특정 화면으로 이동시키는 기능을 수행

우선 딥링크, 앱링크, 유니버셜링크를 각각 개별적으로 생각하고 있었는데 딥링크라는 큰 범주안에서 앱링크, 유니버셜 링크로 나누어진다. (다이나믹 링크, deferred 딥링크는 추후 정리)

Untitled

그림으로 나타내면 위와 같은 형태이다. 기본적으로 특정 링크를 입력(클릭) 했을 때 개발자가 원하는 페이지로 사용자들을 안내하는 기술을 딥링크라고 하고, 딥링크를 구현하는 방법이 위와 같이 존재한다.

(앱링크는 AOS에서 사용하는 용어)

1) URL Scheme

일반적이고 초기에 사용된 딥링크 구현 방식으로 앱에 스킴값을 등록해서 사용한다.

{ Scheme : 앱을 구분 }:// { Path : 앱내 페이지 구분 }

kakaotalk://me
sms://

위의 링크를 사파리에 입력해보자. 카카오톡이 설치되어 있는 휴대폰일 경우 카카오톡이 열리는 것을 확인할 수 있을것이다.

간단하게 위의 내용을 한번 구현해보자(정대리님의 딥링크 강의를 정리한 내용입니다.)

정대리님 강의 링크](https://www.youtube.com/watch?v=kjDl_15fOEQ)

Untitled 1

우선, 위와 같이 스킴을 등록해준다.

enum TabIdentifier: Hashable {
  case todo
  case profile
}

enum PageIdentifier: Hashable {
  case todoItem(id: UUID)
}

extension URL {
  var isDeepLink: Bool {
    return scheme == "deeplink-bran"
  }

  // 어떤 탭을 보여줄 것인가?
  var tabIdentifier: TabIdentifier? {
    guard isDeepLink else { return nil }

    // deeplink-bran:// { host }
    switch host {
    case "todo":
      return .todo
    case "profile":
      return .profile
    default:
      return nil
    }
  }

  //deeplink-bran://todo/ED7E277E-1A5E-4197-AF6D-1D9ED1BFFF9F
  var detailPage: PageIdentifier? {
    guard
      let tabIdentifier = tabIdentifier,
      pathComponents.count > 1,
      let uuid = UUID(uuidString: pathComponents[1])
    else { return nil }

    switch tabIdentifier {
    case .todo:
      return .todoItem(id: uuid)
    case .profile:
      return nil
    }
  }
}

URL이 들어온 경우 { Scheme }:// { Path } 형태의 URL인지 확인하고, Path를 통해서 사용자에게 적절한 페이지로 보내주는 과정이 필요하다.

위의 코드는 Scheme:// {TabIdentifier} / {PageIdentifier?} 형태로 들어온 URL에서 사용자를 적절한 페이지에 보내주기 위해 필요한 데이터들을 뽑아 낼 수 있도록 extension으로 구현한 코드이다.

struct TodoTabView: View {
  let todoModels: [TodoListItem] = [...]

  @State
  var selectedTab: TabIdentifier = .todo

  var body: some View {
    tabSection
      .onOpenURL { url in
        guard let tabId = url.tabIdentifier else { return }
        selectedTab = tabId
      }
  }
}

extension TodoTabView {
  @ViewBuilder
  var tabSection: some View {
    TabView(selection: $selectedTab) {
      TodoView(todoListItems: todoModels)
        .tabItem {
          Image(systemName: "tray")

          Text("TODO")
        }
        .tag(TabIdentifier.todo)

      ProfileView()
        .tabItem {
          Image(systemName: "person")

          Text("Profile")
        }
        .tag(TabIdentifier.profile)
    }
  }
}

우리가 설정한 Scheme://Path 형태의 URL이 들어왔을 경우, 어떻게 화면 전환를 처리해줄 수 있을까?

자세하게 보진 않았지만 UIKit에서는 SceneDelegate, AppDelegate에서 위의 내용을 처리해주고 있는것 같다. SwiftUI에서는 onOpenURL이라는 modifier를 통해서 간편하게 처리할 수 있다.

Brandnew-one/Practice-SwiftUI

해당 프로젝트는 위의 깃허브 링크에서 전체를 확인 할 수 있다. 위의 프로젝트에서 URL Scheme을 통해 개발자가 설정한 탭바 & 네비게이션 푸쉬가 정상적으로 동작하는 것을 확인 할 수 있다.

하지만 처음 딥링크 그림에서 개선 이 걸린다. URL Scheme에는 어떤 문제가 있어서 유니버셜 링크라는 개념이 나오게 된걸까? 이는 위의 프로젝트를 요리조리 테스트 해보다 보면 의외로 쉽게 발견할 수 있다.

  • 앱이 설치되어 있지 않는 경우 실행할 수 없음
  • 동일한 Scheme이 존재하는 경우 문제가 발생함

앱이 설치되어 있지 않는 경우, 주소가 유효하지 않기 때문에 Safari가 해당 페이지를 열 수 없다는 에러 메시지가 나오고, 번들 identifier를 바꿔서 동일한 Scheme이 동일한 여러개의 앱을 만들고 테스트 하면 어떤 앱이 열릴 지 우리가 보장할 수 없는 문제가 발생하는데 이 Scheme은 사용자가 사용하고 있는 앱에서 Identifiable를 보장 할 수 없다.

다음 토이 프로젝트에서는 유니버셜 링크를 간단하게 구현해보고 정리해볼 예정이다.

@Brandnew-one Brandnew-one self-assigned this Dec 19, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant