Branch가 Firebase 다이나믹 링크를 대체할까요?

아주 기본적인 모바일 앱 이상으로 무엇인가 구축하려 시도했다면 아마도 백엔드의 필요성에 부딪혔을 것입니다. 아마 그 중 하나를 설계하고 유지하는 것이 간단한 일이 아님을 발견했을 것입니다. 앱 개발에 집중하고 싶은 개발자들을 위한 게임체인저인 Firebase나 Parse와 같은 Baas (Backend as a Service) 플랫폼을 확인해 봅니다.

구글은 2014년에 Firebase를 사들였고 그 이후 이는 단순한 BaaS 제공자에서 앱을 만들고 성장시키는 새로운 툴을 갖춘 완전한 서비스로서의 앱(App as a Service) 플랫폼으로 진화하였습니다. 개발자에게 이는 환상적인 뉴스로 이제 MVP를 구하고 실행하는 것이 전례 없이 쉬어졌습니다. Branch 팀의 다수가 모바일 엔지니어이기 때문에 Firebase 툴킷의 잠재력이 매우 높은 것을 발견했으며 새로운 프로젝트에 대한 시작점으로 사용해볼 것을 강력히 권합니다.

물론, 불리한 점도 있습니다. 이러한 새로운 도구는 이미 4년 넘게 혁신과 제품 발전을 이룬 서비스 분야에서 경쟁하고 있습니다. 우리는 구글이 심지어 거의 12개를 동시에 출시하려고 애쓰며 너무 욕심을 부린다고 생각합니다. 결론적으로 이러한 새로운 구성 요소의 대부분은 폭은 넓지만 깊이는 얕은 전형적인 사례입니다. 더 강한 것을 필요로 할 정도로 충분히 성장했는지 알기 어려울 수 있으며, 플랫폼 상층에 앱의 핵심 부분을 이미 구축한 후여서 너무 늦어질 때까지 단점이 분명히 보이지 않을 수 있습니다.

Branch는 지난 3년 동안 더 나은 링크를 통해 앱 인지 문제를 해결하는 데 주력해 왔으며, 이는 지구상의 누구보다 더 많이 앱 딥 링크를 처리함을 뜻합니다. (하루 3억 건, 2016년 12월 현재) 이를 염두에 두고 Firebase 다이내믹 링크 모듈을 자세히 살펴보고 Branch 링크 플랫폼과 비교해 봅시다. Firebase 툴킷의 나머지 부분을 계속 사용하면서 더 많은 파워가 필요하다면 다이내믹 링크 대신 Branch를 구현하는 것이 얼마나 쉬운지 보여드리겠습니다.

Firebase 다이내믹 링크

Firebase 팀은 다음과 같이 그들이 해결하려 하는 핵심적인 문제에 대한 개괄적인 내용에 대한 다이내믹 링크용 블로그 포스트 서문을 작성: 앱 내부 콘텐츠 링크의 어려움. 이 포스트는 모든 모바일 앱용 링크 시스템에 적용되는 몇 가지 핵심 요구 사항을 밝혀내는 일을 계속합니다.

  • 앱이 설치된 경우 이를 구동하고 사용자를 콘텐츠로 직접 인도합니다
  • 설치되지 않은 경우 앱/플레이 스토어로 전환하고 다운로드 후 사용자를 해당 콘텐츠로 인도합니다.
  • 분석 및 데이터 추적 캡쳐

다이내믹 링크는 이러한 기본 요건들을 충족합니다. 최소한, 딥 링크의 잠재력을 맛보기에 충분합니다. 그러나, 이것이 가장 최신이자 최후에 개발된 Firebase 구성요소인데 보다 나은 어떤 것을 하고자 하면 할 수 있는 것이 별로 없습니다.

다이내믹 링크 != Branch 호스팅 링크

위의 요구사항은 저희가 2014년에 Branch를 만들기 시작했을 때와 같습니다. 이는 성공적인 딥 링크 서비스의 핵심이며 세계 최고의 앱을. 위한 링크 인프라가 되었기 때문에 Branch가 구축한 모든 것을 위한 기반입니다. 그러나 악마는 디테일에 있죠. 앱 개발자로서 실제 이 링크로 무엇을 할 수 있습니까?

다이내믹 링크 Branch
앱 내부 링크 생성 X X
온라인 대시보드를 이용한 링크 생성 X X
비 스팸 링크 URL X
링크 별 유연한 맞춤 데이터 매개 변수   X* X
심지어 앱이 설치되지 않은 경우에도 특정 콘텐츠로 인도 X X
JSON 형식의 표준 링크 데이터 응답   X
최초 설치 속성   X
최초 설치 시 일치 정확도 보장   X
특정 사용자 식별(추천 및 기타 목적)   X
업계를 선도하는 SLA 기반의 기술 지원 X
포괄적인 경계 조건 처리 (페이스북과 이메일 포함) X


* 링크 URL의 일부로 반드시 수동 인코딩 해야함

실제 사례

겉보기에는 그럴듯하지만, 우리의 Branch Room Maps app앱과 같은 간단한 iOS 앱에서 동등한 딥링크 기능을 구현하려면 어떻게 해야 할까요? 코드를 직접 비교해 봅시다.

우선 세션을 시작하고 들어오는 링크를 다룰 필요가 있습니다. Firebase 사용의 양상:

import UIKit
import Firebase
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
let customURLScheme = branchmaps // Hmmm…why?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Set up the SDK
FIROptions.default().deepLinkURLScheme = self.customURLScheme
FIRApp.configure()
return true
}
// This extra call to the open url method often causes confusion…but both are necessary!
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any]) -> Bool {
return application(app, open: url, sourceApplication: nil, annotation: [:])
}
// Here, we handle URI scheme links, and (more importantly) the initial launch after a new install
// This can also cause confusion, because the initial launch is not a URI link and yet is still handled here
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
let dynamicLink = FIRDynamicLinks.dynamicLinks()?.dynamicLink(fromCustomSchemeURL: url)
if let dynamicLink = dynamicLink {
// We can see the URL of the link…
dump(dynamicLink.url)
// …and then pull it apart to use the pieces
let deepLink = URLComponents(url: dynamicLink.url!, resolvingAgainstBaseURL: false)!
let deepLinkQueryString = deepLink.queryItems
// Filtering through the results to see if they contain the parameter we want
if let roomID = deepLinkQueryString!.filter({$0.name == roomID}).first?.value {
// Set up the transition
let destination = self.window?.rootViewController?.storyboard?.instantiateViewController(withIdentifier: roomDetails) as! ViewController
destination.roomToShow = String(describing: roomID)
self.window?.rootViewController?.present(destination, animated: true, completion: nil)
}
return true
}
return false
}
// Aaaaand now do it all again for Universal Links
@available(iOS 8.0, *)
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> Bool {
guard let dynamicLinks = FIRDynamicLinks.dynamicLinks() else {
return false
}
let handled = dynamicLinks.handleUniversalLink(userActivity.webpageURL!) { (dynamicLink, error) in
dump(dynamicLink!.url)
let deepLink = URLComponents(url: dynamicLink!.url!, resolvingAgainstBaseURL: false)!
let deepLinkQueryString = deepLink.queryItems
if let roomID = deepLinkQueryString!.filter({$0.name == roomID}).first?.value {
let destination = self.window?.rootViewController?.storyboard?.instantiateViewController(withIdentifier: roomDetails) as! ViewController
destination.roomToShow = String(describing: roomID)
self.window?.rootViewController?.present(destination, animated: true, completion: nil)
}
}
return handled
}
}

 

그리고 같은 것을 Branch로 구현한 것:

import UIKit
import Branch
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Set up the SDK
let branch: Branch = Branch.getInstance()
// Get a bunch of extra logging output
branch.setDebug()
// No need to manually configure any transitions, because the Branch SDK can do that automatically
// Of course, you can do it manually too if you need more flexibility
let controller = UIStoryboard.init(name: Main, bundle: Bundle.main).instantiateViewController(withIdentifier: roomDetails)
branch.registerDeepLinkController(controller, forKey: room_name)
// Start the session and get all the link data. This occurs on every launch, even if a link was not opened
// This is also where the link data from a new install is captured
branch.initSession(launchOptions: launchOptions, automaticallyDisplayDeepLinkController: true) { (params, error) in
if (error == nil) {
// We can look at the contents of the link, and a bunch of other interesting things
dump(params)
}
}
return true
}
// Here, we check for URI scheme links
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
// If we find one, pass it back to the deep link handler for unpacking
Branch.getInstance().handleDeepLink(url);
return true
}
// Also check for Universal Links
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> Bool {
// If we find one, it goes back to the deep link handler for unpacking too
return Branch.getInstance().continue(userActivity)
}
}

 

아직까지 보기에는 비슷합니다. 모든 면에서 Branch 쪽이 약간 더 간단하지만 좋은 프로그래머가 처리할 수 없는 것은 없습니다.

다음으로, 링크를 몇 개 생성해 봅시다. Firebase 먼저:

@IBAction func shareButton(_ sender: UIButton) {
if let selectedRoom = (RoomData.allRoomsArray().filter{ $0.roomID == roomToShow }).first {
// We need to specify everything for each link…so let’s start with the base URL on the web
// Also need to manually append any custom data params we want passed through
let roomLink = https://branch.io/room?roomID=\(selectedRoom.roomID)
// Next, wrap that URL into the Firebase link and add required control params
let firebaseLink = https://x2z5q.app.goo.gl/?link=\(roomLink.addingPercentEncoding(withAllowedCharacters: .alphanumerics)!)&ibi=io.branch.branchmap
// Configure and display the stock iOS share sheet
let shareSheet = UIActivityViewController(activityItems: [ firebaseLink ], applicationActivities: nil)
shareSheet.popoverPresentationController?.sourceView = self.view
self.present(_: shareSheet, animated: true, completion: {
print(Generated \(firebaseLink) sharing link for \(selectedRoom.roomID))
})
}
}

 

이번에는 Branch:

@IBAction func shareButton(_ sender: UIButton) {
// Set up some basic info about the link we are going to create
let linkProperties = BranchLinkProperties()
linkProperties.feature = sharing
// Define a container to store link data
let branchUniversalObject = BranchUniversalObject()
if let selectedRoom = (RoomData.allRoomsArray().filter{ $0.roomName == roomToShow }).first {
// Insert all the link data…these are just few of the options
// Many configuration items can be omitted because they are inherited from the main Branch app config
branchUniversalObject.canonicalIdentifier = room/\(selectedRoom.roomID) // This one lets us dedup the same piece of content across many links
branchUniversalObject.title = selectedRoom.roomName
branchUniversalObject.addMetadataKey(room_name, value: selectedRoom.roomName) // We can have as many of these as we want
// Use the pre-packaged share sheet method
branchUniversalObject.showShareSheet(with: linkProperties, andShareText: nil, from: self, completion: { (activity, finished) in
print(Generated sharing link for \(selectedRoom.roomName))
})
}
}

 

비록 진짜 차이는 링크 URL 그 자체이지만 Firebase 쪽 코드에 수작업이 더 필요합니다. (축약 브랜드 링크는 정말 중요합니다).

그러나 가장 중요한 것은, 이 링크를 써서 실제로 무엇을 할 수 있습니까? 여기에 AppDelegate 덤프 구문으로부터의 데이터가 있습니다:

Firebase:

url: https://branch.io/room?roomID=PineCone

Branch:

+click_timestamp: 1482541476
+clicked_branch_link: 1
+is_first_session: 0
+match_guaranteed: 1
+referrer: https://www.google.com/
+phone_number: //only returned when link is SMSed from desktop to mobile
~creation_source: 3
~referring_link: https://branchmaps.app.link/D1PpymBZlz
~feature: sharing
~channel: Pasteboard
~id: 341010052121261919
$one_time_use: 0
$og_title: Pine Cone
$identity_id: 339834809826614244
$canonical_identifier: room/PineCone
$publicly_indexable: 1
$exp_date: 0
room_name: Pine Cone

여기에서 두 플랫폼은 전혀 비슷하지 않습니다. Branch 는 설치 감지와(+is_first_session) 일치 정확도를 (+match_guaranteed) 포함하는 유용한 컨텍스트 매개 변수 전체를 제공합니다.  포함하는 유용한 컨텍스트 매개 변수 전체를 제공합니다.  설치 감지는 맞춤 온보딩과 같은 경험 구축에 필수적이며 일치 정확도는 Branch가 생태계 내의 누구보다  잘 하는  부분으로 정확한 사용자라는 확신 하에 개별 콘텐츠 딥 링크를 가능하게 합니다.

사실 저희 고객 중 일부는 정확도를 매우 신뢰하여 앱을 처음 구동하면 Branch 링크를 사용자 앱 자동 로그인에 사용합니다.

Firebase는 단순한 그대로의 URL을 반환합니다.

그리고 여기가 다이내믹 링크가 끝나는 지점입니다. 그들은 그들이 원하는 곳으로 사용자를 인도하고 (너무나 많은 경계 조건에 빠지지 않는 대부분의 경우) 링크 클릭을 추적하는 외에 별다른 것은 없습니다. 반면에 Branch는 단지 시작할 뿐입니다. 우리에게 있어서 견고한 딥 링크 시스템은 다음과 같이 추가로 그 위에서 무엇이든 할 수 있는 프레임워크일 뿐:

  • Journeys 스마트 배너: 현존하는 가장 강력하고 유연한 앱 스마트 배너.
  • Deepviews: 사용자가 내려받기 전에 앱 내부 콘텐츠의 미리 보기를 제공하여 변환을 증가시킵니다.
  • 딥 링크 이메일: 마케팅 이메일에 자동으로 딥링크를 추가합니다.
  • 추천: 추천 내역을 추적하여 사용자에게 크레딧을 지급합니다.
  • 데이터 통합: 링크 분석 데이터를 자동으로 외부 툴로 전송합니다.
  • Text Me The App: 데스크탑 사용 방문자가 내려받기 링크를 SMS로 보내게 합니다.
  • 포괄적 분석: 링크 클릭 추적, 설치, 최고 실적 콘텐츠, 가장 가치있는 사용자 및 기타.

이에 더하여 저희 스스로가 앱 개발자이면서 프로그래머이기 때문에 필요할 때 도움을 받는 것이 얼마나 중요한지 잘 이해하고 있습니다. 저희는 StackOverflow에서 Branch.io 태그를 단 모든 질문을 모니터링하며 저희 통합 팀은 모든 파트너에게 무료 지원을 무제한으로 제공합니다.

두 세계에서 최고가 되는 방법

가장 좋은 부분은 선택할 필요가 없다는 것입니다. Firebase는 일련의 개별적인 모듈형 SDK로 구현되었습니다. 어떻든 다이내믹 링크를 구현하려면 다른 SDK를 추가해야 하므로 그 대신 그냥 Branch를 사용하는 것이 손쉬운 방법입니다. 사실, 더 간단할 겁니다! Firebase 플랫폼 AaaS 플랫폼의 모든 혜택을 누리면서 세계에서 가장 유연하고 강력하며 앞선 모바일 딥 링크 시스템을 사용할 수 있습니다.

TO LEARN MORE ABOUT BRANCH'S
PRODUCTS AND SERVICES

Request a demo