-
Universal link 적용하기Language/iOS,AOS 2023. 3. 2. 09:17
유니버셜 링크 (Univeral Link)란?
iOS에서만 작동하는 딥링크의 한 종류로 웹에서 앱을 호출하는 기능이 필요할 때 사용
딥링크 (Deep Link)란?
Application 내 특정 페이지에 도달할 수 있도록 하는 링크
유니버셜 링크 특징
- url 형태로 동작 하고 ip 및 http 프로토콜에서는 동작하지 않습니다.
- iOS 9 이상에서만 지원합니다.
- redirection이 없어야 합니다.
1. AASA (apple-app-site-association 파일 추가
파일명 : JSON apple-app-site-association파일에는 파일 확장자가 없어야 합니다
위치 : .well-known 디렉토리 또는 root 디렉토리에 추가
iOS 13보다 아래인 버전은 따로 옵션을 추가해야한다. (여기선 제외)
참고 링크를 꼭 한번은 보시길 권장드립니다.
https://gist.github.com/anhar/6d50c023f442fb2437e1
https://kyte.travel/.well-known/apple-app-site-association
{ applinks: { details: [ { appIDs: [<TEAM_DEVELOPER_ID>.<BUNDLE_IDENTIFIER>], components: [ { /: "*" } ] } ] } }
details : 웹사이트에서 핸들링되는 앱들의 목록. 즉 한 웹사이트에서 유니버셜 링크를 사용하는 여러 앱 연동이 가능.appIDs : 애플 개발자 계정을 생성하면 Team ID가 만들어지는 데 해당 ID는 developer.apple.com 에서 확인 가능하다. Bundle ID는 프로젝트 Target 들어가서 확인 가능하다. (<> 는 빼야 한다.)
2. Capability 추가
TARGETS -> Signing & Capabilities -> Associated Domains 추가
도메인 설정
3. 유니버셜 링크 URL 핸들링 하기 (SceneDelegate)
3.1. 앱 종료 (background) -> 유니버셜 링크 클릭 -> 앱실행 및 링크이동
class SceneDelegate: UIResponder, UIWindowSceneDelegate { ... func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { ... // Get URL components from the incoming user activity. guard let userActivity = connectionOptions.userActivities.first, userActivity.activityType == NSUserActivityTypeBrowsingWeb, let incomingURL = userActivity.webpageURL, let components = NSURLComponents(url: incomingURL, resolvingAgainstBaseURL: true) else { return } // Check for specific URL components that you need. guard let path = components.path, let params = components.queryItems else { return } AppInfo.shared.universalURL = incomingURL.absoluteString } }
페이지 이동은 웹에서 판단해서 이동하여 준다.
class MainViewController: BaseViewController { ... override func viewDidLoad() { super.viewDidLoad() ... // Universal Link (앱 실행중 : active, inactive) NotificationCenter.default.addObserver(forName: Notification.Name("didReceiveUniversalURL"), object: nil, queue: nil) { notification in let universalUrl:String? = AppInfo.shared.universalURL AppInfo.shared.universalURL = nil if(universalUrl != nil) { self.executeJavasScript(wKWeb: self.wKMainWeb, callback: "Common.Native.setDeepLink('\(universalUrl!)')") } } ... } }
3.2 앱 실행중 (active, inactive) -> 유니버셜 링크 클릭 -> 링크이동
class SceneDelegate: UIResponder, UIWindowSceneDelegate { ... // Universal Link (앱 실행중일때) func scene(_ scene: UIScene, continue userActivity: NSUserActivity) { guard userActivity.activityType == NSUserActivityTypeBrowsingWeb, let incomingURL = userActivity.webpageURL, let components = NSURLComponents(url: incomingURL, resolvingAgainstBaseURL: true), let path = components.path else { return } // 도메인 주소의 쿼리값을 받음 let params = components.queryItems ?? [URLQueryItem]() AppInfo.shared.universalURL = incomingURL.absoluteString NotificationCenter.default.post(name: Notification.Name("didReceiveUniversalURL"), object: nil) } }
페이지 이동은 웹에서 판단해서 이동하여 준다.
// MARK: - iOS Bridge // 웹 액션 정의 : WebAction을 구분하는데 사용되는 타입 enum WebAction: String { ... case getDeepLink } extension MainViewController: WKScriptMessageHandler { func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { guard message.name == "IosBridge", let messages = message.body as? [String: Any], let action = messages["action"] as? String else { return } let webAction = WebAction(rawValue: action) switch webAction { ... case .getDeepLink: guard let params: [String: String] = messages["params"] as? [String: String], let callback: String = params["callback"] else { return } let universalUrl:String? = AppInfo.shared.universalURL AppInfo.shared.universalURL = nil if(universalUrl != nil) { executeJavasScript(wKWeb: self.wKMainWeb, callback: "\(callback)('\(universalUrl!)')") } default: Utils.Log("undefined action") } } }
아래 URL로 접속해서 정상 동작하는지 확인해 볼 수 있습니다.
iOS 메모장 앱에서 https://aaaaa.com/path1/path2/path3 과 같이 클릭해서 앱이 깔려있으면 실행되는지 확인 할 수 있습니다.
디버깅 환경에서 테스트 하는데 잘 안되서 추가적으로 설정한 부분
TARGETS -> Debug, Staging -> Associated Domains에 ?mode=developer 파라미터를 추가해 줬다.
applinks:aaaaa.com?mode=developer
apple-app-site-association 설정은 모두 더블 쿼테이션(`"`)으로 감쏴주었다.
[<TEAM_DEVELOPER_ID>.<BUNDLE_IDENTIFIER>],
{ "applinks": { "details": [ { "appIDs": ["10자리.아이덴티티", "10자리.아이덴티티"], "components": [ { "/": "*" } ] } ] } }
아이폰 환경설정에서 개발자 -> UNIVERSAL LINKS에서 개발자 항목을 활성화 해주었다.
안되서 추가한 부분들은 여러가지 해주긴 했지만 디버깅에서 안되는 부분인지 까지는 시간상 확인해 보지 못했다.
아이폰 캐시 떄문인지 되다 안되다 해서 결과적으로 3가지 설정을 추가하니 계속 잘 되니깐..
여기서 넘어가지.. 시간없다!
유니버셜 링크가 동작 안하는 경우
- 웹브라우저에서 직접 url 입력시 실제로 그 주소로 이동하고자 하는 의사가 있다고 생각해서 universal link가 동작하지 않는다.
- iOS version이 10 미만인 경우 Universal Link가 동작하지 않는다.
- AASA 를 변경 해도 바로 반영되지 않는다. Apple CDN 캐시가 있기때문 .. 지웠다 깔아도 바로 반영이 안된다면 조금 기다린 후 다시 확인하면 된다.
- Universal link는 Safari와 Chrome에서만 작동합니다.
- 브라우저 주소 입력창에 딥링크를 직접 복사/입력 하는 경우 동작하지 않음
- 각각의 플랫폼에서 자신들이 만든 앱(크롬, 사파리, 메일 등)으로 실행하면 의도대로 잘 동작하지만 그외에서는 동작하지 않는 경우도 있음
- 자체 브라우저를 사용하는 앱들(카카오톡, 페이스북, 인스타그램)에 따라서 이 유형의 딥링크가 잘 동작하는 경우도 있고 동작하지 않는 경우도 있음
동작
앱이 설치되어 있다면 해당 딥링크에 맞는 화면이 실행
앱이 설치되어 있지 않다면, 웹 URL로 인식되어 실제 해당 웹 링크를 열려고 시도함
웹서비스도 함께 제공하고 있다면 해당 웹서비스에서 맞는 컨텐츠를 보여줄것임
하지만 그렇지 않다면, 해당 URL로 웹으로 열었을때 앱 마켓(구글 플레이, 앱스토어)으로 이동시키도록 처리해두면 됨아래 에러 발생시!!
Provisioning profile "XXX" doesn't support the Associated Domains capability.
Provisioning profile "XXX" doesn't include the com.apple.developer.associated-domains entitlement. Profile qualification is using entitlement definitions that may be out of date. Connect to network to update.
원인은 애플 개발자 사이트에서 Associated Domains 권한이 포함되지 않아서이다!
권한 주고 프로비저닝 파일 다시 다운로드 받으면 된다!
Identifiers 메뉴로 접근합니다.
Associated Domains을 추가합니다.
프로비저닝 프로파일을 다시 받아서 Xcode에 Import 해줍니다.
참고
https://jooeungen.tistory.com/entry/iOSSwift-Universal-link-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0
https://lxxyeon.tistory.com/74
https://juneyr.dev/universal-link
https://developer.apple.com/videos/play/wwdc2019/717/
https://developer.apple.com/documentation/xcode/supporting-associated-domains
'Language > iOS,AOS' 카테고리의 다른 글
카카오 간편 로그인 속도 개선 (0) 2023.03.06 URI 스킴 적용 (URL Scheme) (0) 2023.03.06 iOS 푸시 랜딩 (active, inactive, background) (0) 2023.03.01 웹뷰 캐시 삭제 (0) 2023.03.01 scrollView 확대/축소 방법 (0) 2023.02.24