Es Branch un sustituto para los enlaces dinámicos de Firebase?

Si alguna vez ha intentado construir algo más que una aplicación móvil básica, probablemente haya tenido la necesidad de un backend. Es probable que haya descubierto que su diseño y mantenimiento no es sencillo. Existen plataformas Baas (backend como un servicio) como Firebase y Parse, que cambian las reglas del juego para los desarrolladores que prefieren centrarse en la creación de aplicaciones.

Google adquirió Firebase en 2014, y, desde entonces, ha pasado de ser un simple proveedor BaaS a convertirse en una plataforma integral de aplicación como un servicio, con todo un conjunto de nuevas herramientas para la creación y mejora de aplicaciones. Esta es una fantástica noticia para los desarrolladores: ahora es más fácil que nunca tener un MVP en funcionamiento. Puesto que muchos de los miembros del equipo de Branch también somos desarrolladores, encontramos que el potencial de la caja de herramientas de Firebase es muy emocionante y recomendamos tenerlo en cuenta para iniciar con fuerza el trabajo en nuevos proyectos.

Como siempre, también hay un problema: estas nuevas herramientas compiten con negocios verticales de servicios que llevan más de cuatro años de innovación y mejora de productos. Creemos que Google trató de abarcar más de lo que podía al lanzar casi una docena al mismo tiempo. El resultado es que muchos de estos nuevos componentes son casos clásicos de quien mucho abarca poco aprieta. Es difícil saber cuándo se ha crecido lo suficiente para necesitar algo más potente, y los fallos pueden no ser obvios hasta que no es demasiado tarde, cuando ya se ha desarrollado el núcleo de la aplicación, además de la plataforma.

El objetivo de Branch en los últimos tres años ha sido resolver el problema del descubrimiento de aplicaciones, lo que significa que tratamos con más enlaces profundos de aplicación que nadie en todo el planeta (300 millones al día, en diciembre de 2016). Teniendo esto en mente, vamos a conocer más de cerca el módulo Enlaces dinámicos de Firebase y verlo en comparación con la plataforma de enlazado de Branch. También mostraremos lo fácil que resulta implantar Branch en lugar de enlaces dinámicos si lo que necesita es más potencia, al tiempo que se sigue usando el resto de la caja de herramientas de Firebase.

Enlaces dinámicos de Firebase

El equipo de Firebase escribió una publicación de presentación de los enlaces dinámicos en su blog, en el que subrayaban el principal problema que trataban de resolver: enlazar a contenido en las aplicaciones es difícil. En la publicación se identificaban algunos requisitos clave aplicables a cualquier sistema de enlaces para aplicaciones móviles:

  • Lanzar las aplicaciones si están instaladas y llevar al usuario directamente al contenido
  • Enrutar al App Store/Play Store si no está instalada y llevar a los usuarios al contenido tras la descarga
  • Recabar análisis y realizar el seguimiento de los datos

Los enlaces dinámicos cumplen estos requisitos básicos. Al menos, los suficientes como para que se pueda experimentar el potencial del enlazado profundo. Sin embargo, se trata de uno de los componentes de Firebase más recientes y menos desarrollados, y enseguida puede resultar frustrante si se trata de hacer cosas más avanzadas.

Enlaces dinámicos != Enlaces alojados de Branch

Los requisitos mencionados son los mismos que identificamos cuando empezamos a crear Branch, en el año 2014. Son la base de un servicio eficaz de enlazado profundo y la base de todo lo que hemos estado construyendo en Branch a medida que nos hemos convertido en la infraestructura de enlazado de las mejores aplicaciones del mundo. Pero la clave está en los detalles. Como desarrollador de aplicaciones, ¿qué es lo que realmente puede hacer con estos enlaces?

Enlaces dinámicos Branch
Generar enlaces dentro de la aplicación X X
Generar enlaces utilizando el panel en línea X X
URL de enlaces libres de spam X
Parámetros de datos personalizados y flexibles por enlace   X* X
Enrutamiento a contenido específico, incluso cuando la aplicación no está instalada X X
Respuesta de datos de enlace estandarizada en formato JSON   X
Atribución de primera instalación   X
Precisión de correspondencia garantizada en la primera instalación   X
Identificación de usuarios únicos (para usuarios que recomiendan, etc.)   X
Soporte técnico con apoyo en un SLA líder en el sector X
Manejo integral de casos críticos (incluidos Facebook y correo electrónico) X


* Debe cifrarse de forma manual, como parte de la URL del enlace

Un ejemplo práctico

Parece todo correcto, pero ¿y si queremos implementar una funcionalidad de enlazado profundo equivalente en una aplicación iOS, como nuestra aplicación de oficina Branch Room Maps app? Comparemos el código directamente.

Lo primero que tenemos que hacer es iniciar una sesión y tratar los enlaces entrantes. Así es como sería utilizando 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
}
}

 

Y lo mismo, implementado con 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)
}
}

Como se puede ver, son muy similares hasta este punto. La mayor parte de las cosas son algo más sencillas en Branch, pero nada de lo que un buen programador no pueda hacerse cargo.

Ahora, vamos a crear algunos enlaces. Primero, en 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))
})
}
}

 

Ahora con 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))
})
}
}

De nuevo, ha sido necesario algo más de trabajo manual en el código de Firebase, si bienla auténtica diferencia está en las propias URL de los enlaces (los enlaces de marca son realmente importantes).

Pero lo que es aún más importante, ¿qué se puede hacer realmente con estos enlaces cuando se usan? Aquí están los datos obtenidos de las instrucciones dump en 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

 

Aquí, las plataformas se parecen poco entre sí. Branch le da una lista completa de parámetros contextuales útiles,incluida la detección de instalación (+is_first_session) y la precisión de la correspondencia (+match_guaranteed). La detección de instalación es importantísima para crear experiencias como integración personalizada, y la precisión de correspondencia permite el enlazado profundo a contenido personalizado, con la confianza de que se trata del usuario correcto, algo que Branch hace mejor que cualquiera en el ecosistema.

De hecho, algunos de nuestros clientes confían tanto en nuestra precisión, que utilizan los enlaces de Branch para que los usuarios inicien sesión automáticamente en una aplicación la primera vez que la abren.

Firebase devuelve una simple URL en bruto.

Y aquí es donde entran los enlaces dinámicos. Estos enlaces envían a los usuarios donde los quiere (la mayor parte de las vecessi no se dan demasiados casos críticos) y rastrea los clic a los enlaces, pero poco más. Por el otro lado, Branch no ha hecho más que empezar. Para nosotros, un sistema de enlazado profundo sólido es solo el marco para todo lo demás:

  • Journeys Smart Banners: los banners inteligentes para aplicaciones más poderosos y flexibles que existen.
  • Deepviews: incrementan la conversión ofreciendo a los usuarios una vista previa del contenido dentro de la aplicación antes de descargarla.
  • Correo electrónico con enlaces profundos: incluye de forma automática enlaces profundos a sus correos electrónicos de marketing.
  • Recomendaciones: hace un seguimiento de las recomendaciones y otorga créditos a los usuarios.
  • Integración de datos: envía automáticamente sus datos analíticos de enlaces a herramientas externas.
  • Text Me The App: permite a los visitantes en ordenador enviar ellos mismos un enlace de descarga mediante SMS.
  • Análisis integrales: rastrea los clics a sus enlaces, instalaciones, contenido con mejor rendimiento, usuarios más valiosos y más.

Además, puesto que nosotros también somos desarrolladores y programadores de aplicaciones, sabemos lo importante que es obtener ayuda cuando hace falta. Hacemos un seguimiento de todas las preguntas en StackOverflow con la etiqueta Branch.io tag, y nuestro equipo de integración da soporte ilimitado de forma gratuita a TODOS nuestros asociados.

Cómo tener lo mejor de los dos mundos

Esta es la mejor parte: no tiene que elegir. Firebase se implementa como una serie de SDK modulares independientes. Tiene que añadir otro SDK para implementar los enlaces dinámicos, así que es tan fácil como utilizar Branch en su lugar. De hecho, ¡probablemente sea más fácil! Puede obtener todos los beneficios de plataforma AaaS de la plataforma Firebase y la flexibilidad y potencia del sistema de enlazado profundo móvil más avanzado del mundo.

TO LEARN MORE ABOUT BRANCH'S
PRODUCTS AND SERVICES

Solicitar demonstración