Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- clean architecture
- RxCocoa
- rxswift
- UICollectionView
- swift documentation
- Human interface guide
- combine
- map
- Clean Code
- swiftUI
- ribs
- 애니메이션
- tableView
- 리펙터링
- SWIFT
- Refactoring
- 스위프트
- uitableview
- Protocol
- 리펙토링
- Xcode
- MVVM
- UITextView
- 리팩토링
- ios
- HIG
- uiscrollview
- collectionview
- 클린 코드
- Observable
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[Deeplink] 딥링크 (URL Scheme, Universal Link) 본문
딥링크란?
- "Deep"한 "Link", 화면속의 특정 부분으로 이동 할 수 있는 링크를 의미
- 사용자가 "새로운 메세지가 왔습니다"와 같은 push알림을 받고 그 부분을 탭했을 때, 메세지 화면으로 바로 이동 (딥링크가 없었다면 로그인 -> 메인화면 -> 메세지 화면으로 이동)
- 카카오톡에서 카카오맵의 특정 위치 link를 탭한경우, 카카오맵이 켜지면서 바로 특정 위치로 이동
- 원리: 서버에서 앱에 URL전송 -> 앱에서 URL을 가지고 문자열을 파싱하여, 특정 화면으로 화면전환
iOS에서 딥링크의 종류
- URL Scheme를 이용한 방식
- URL Scheme란? iOS는 기본적으로 샌드박스 환경이므로 다른 앱에 정보 전달하기가 어려움 (이 때 Xcode에서 Scheme을 정해두면, 해당 Scheme로 시작하는 다른 앱을 실행하면서 정보전달이 가능)
- URL 컨벤션: 시작은 앱의 이름으로 시작하며 뒤 path와 query부분은 웹 URL과 같이 설정 (유튜브앱: youtube://path/deeplink?scene=page1)
- Universal Link를 이용한 방식: 참고
URL Scheme과 Universal Link의 차이
URL Scheme (= custom scheme) | Universal Link | |
사용방법 | Scheme을 XCode에 등록하여 사용 | 웹사이트의 Domain을 이용하여 등록 |
Uniqueness | 중복 URL이 가능 (URL이 중복된다면, 아이폰에서 어떤 앱을 선택할지 물음) | 웹사이트의 도메인으로 사용하기 때문에 중복 x |
동작 | 링크 클릭 -> "앱스토어 설치"물음 -> 앱 설치가 되어있다면 앱으로, 안되어 있다면 앱스토어로 | 링크 클릭 -> 링크가 설치되어 있다면 앱으로, 안되어 있다면 앱스토어로 |
Universal Link가 장점이 많지만 원리는 동일하므로, 기본적인 URL Scheme 내용 정리
딥링크 구현
- URL Types추가: AppTarget -> info -> URL Types -> "+"버튼을 눌러서 생성
- identifier와 URL Schemes에 기입 (URL Schemes에는 일반적으로 앱 이름을 기입)
- "{입력한 URL Schemes}://"으로 url 딥링크 사용 가능
- 딥링크가 앱으로 넘어온 경우의 함수이용 (AppDelegate에 존재)
- func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool
- 딥링크를 받아서 화면전환예제
- 앱으로 받을 URL은 임시로 사용: youtube://path/deeplink?scene=page1
- 딥링크는 braze와 같은 서버에서 push와 함께 URl을 넣어주는 경우가 있고, 그 URL을 받는다고 생각하고 아래와 같이 구현
- URL을 받으면 AppDelegate의 application(_ UIApplication: , open: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool에서 처리
주의) SceneDelegate가 있는 경우, link동작은 아래 delegate에서 받으므로 주의
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
}
- 앱을 종료 했었지만 푸시로 인해 화면들이 이미 초기화된 경우: window에 새로운 root를 등록할 필요가 없음
- 웹으로 부터 받은 URL이 딥링크인지 확인
- 쿼리 확인
- 딥링크 처리
아래 로직은 참고용도이고, 베스트 로직은 AppDelegate에서 화면전환을 하지 않고 postTaskManager와 같은 곳에 테스크를 등록한 후 특정 화면으로 이동 했을 때 그 화면에서 딥링크가 처리되게끔 하는게 좋은 구조
(Coordinator관련 로직은 여기 참고)
// AppDelegate.swift
var postTaskManager = PostTaskManager()
lazy var navigationController: UINavigationController = {
let navi = UINavigationController()
navi.setNavigationBarHidden(true, animated: false)
return navi
}()
lazy var router = SplashCoordinator(rootViewController: navigationController, postTaskManager: self.postTaskManager, initialRoute: .splash).strongRouter
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// 1. 앱을 종료 했었지만 푸시로 인해 화면들이 초기화 된 경우
if !navigationController.viewControllers.isEmpty {
return true
}
window = UIWindow(frame: UIScreen.main.bounds)
router.setRoot(for: window!)
window?.makeKeyAndVisible()
return true
}
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
// 2. 받은 URL이 딥링크인지 확인
let deeplinkPath = "/deeplink/"
guard let components = NSURLComponents(url: url, resolvingAgainstBaseURL: true),
let path = components.path,
let params = components.queryItems else {
return false
}
guard path == deeplinkPath else {
return false
}
// 3. 쿼리확인
if let value = params.first(where: { $0.name == "scene" })?.value {
processDeeplink(with: value)
return true
} else {
print("index missing")
return false
}
}
// 4. 딥링크 처리 로직: 로그인이 되어있다면 홈화면을 베이스로 하며, 특정 화면으로 이동하게끔 설정
private func processDeeplink(with scene: String) {
// TODO - token정보 가지고 로그인 판단
let isLoggedIn = true
if !isLoggedIn {
_ = SplashCoordinator(rootViewController: navigationController, postTaskManager: postTaskManager, initialRoute: .splash)
return
}
// Home화면이 베이스가 되게끔 설정
if navigationController.viewControllers.first as? HomeVC == nil {
_ = HomeCoordinator(rootViewController: navigationController, postTaskManager: postTaskManager, initialRoute: .home)
}
switch scene {
case "receipt":
_ = UsageCoordinator(rootViewController: navigationController, postTaskManager: postTaskManager, initialRoute: .receipt(date: "2020/11/06 금요일", paymentState: .success))
case "card":
break
default:
break
}
}
딥링크 처리 로직
- 딥링크 URL인지 확인
application(_: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool 위 함수에서 화면을 초기화 하는 로직이 있다면, 딥링크로 인해서 이미 화면이 존재하는지를 체크해야 이중으로 초기화가 안됨 - URL 확인:
application(_: UIApplication, open: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool
위 함수에서 deeplink URL인지 확인 - 특정 화면으로 이동하기 전에 로그인이 되어있는지 체크
- 특정 화면으로 이동하기 전에, home을 먼저 push후 이동
- 만약 현재 home화면이, navigationController.viewControllers[0]에 위치한다면, 따로 home화면 push하지 않아도 됨
'iOS 응용 (swift)' 카테고리의 다른 글
[iOS - swift] iOS14+ 위치 권한 설정 (precise) (0) | 2020.11.08 |
---|---|
[APNs] Apple push notification service (0) | 2020.11.08 |
Xcode 불필요한 캐시를 안정적으로 삭제 (0) | 2020.11.01 |
[iOS - swift] Custom View (xib) (2) | 2020.11.01 |
[iOS - swift] custom cell(일반 cell, Header cell), Hugging, Compression (0) | 2020.11.01 |
Comments