S’il vous est arrivé de créer quelque chose de plus important qu’une simple application mobile de base, vous vous êtes sûrement trouvé confronté au besoin de disposer d’un back-end. Il est probable que vous ayez alors découvert que la conception et l’entretien de l’un d’entre eux est une tâche ardue. Entrez sur les plates-formes BaaS (back-end en tant que service) telles que Firebase et Parse des plates-formes qui changent la donne pour les développeurs qui veulent se concentrer sur la création d’une application.
Google a acquis Firebase en 2014, et de simple fournisseur de Baas il est devenu une application complète sous forme de plate-forme de service, avec une série de nouveaux outils destinés à la création et au développement d’une application. Pour les développeurs, C’est une nouvelle extraordinaire: il est désormais plus facile que jamais de maintenir un MVP à jour et opérationnel. Dans l’équipe de Branch, beaucoup d’entre nous sont eux-mêmes des ingénieurs des applications mobile, aussi nous trouvons le potentiel de la trousse à outils de Firebase très intéressant et nous recommandons vivement de le considérer comme un moyen d’accélérer le travail sur les nouveaux projets.
Il y a bien évidemment un revers à tout ça: ces nouveaux outils sont en concurrence dans les verticales du service qui ont déjà connu plus de quatre ans d’innovation et d’amélioration du produit. Nous pensons que Google a vu trop grand en essayant d’en lancer presque une douzaine simultanément. Il en a découlé que beaucoup de ces nouveaux composants partent dans tous les sens. Il peut être difficile de savoir quand votre évolution a atteint le point où elle nécessite quelque chose de plus puissant et les lacunes peuvent ne pas être visibles avant qu’il ne soit trop tard et après l’élaboration d’un élément central de votre application en plus de la plate-forme.
Branch, résoudre le problème de la divulgation de l’application par une meilleure liaison a été au centre de notre attention au cours de ces trois dernières années, ce qui signifie que nous nous occupons des liaisons ciblées plus que quiconque en ce monde (300 millions par jour en décembre 2016). Dans cette optique, intéressons-nous de plus près au module de liaisons universelles Firebase et voyons comment il se positionne par rapport à la plate-forme de liaison Branch. Nous aborderons également la facilité de la mise en œuvre de Branch par rapport aux liaisons dynamiques, si vous avez besoin de plus de puissance, tout en continuant à utiliser le reste de la trousse à outils de Firebase.
Liaisons dynamiques Firebase
Dans le blog de présentation des liaisons dynamiques écrit par l’équipe de Firebase, le problème central qu’ils tentent de résoudre est mis en évidence: la difficulté d’établir une liaison avec un contenu à l’intérieur des applications. Au fil de l’article, certaines exigences clés s’appliquant à tous les systèmes de liaison des applications mobiles sont définies:
- Lancer l’application lorsque celle-ci est installée et diriger l’utilisateur directement vers le contenu
- Si elle n’est pas installée, dirigez les utilisateurs vers App/Play Store puis vers le contenu après le téléchargement
- Récupérer les données sur l’analyse et le suivi
Les liaisons dynamiques assument ces exigences de base. Du moins, un nombre d’entre elles suffisamment important pour vous donner un aperçu du potentiel de la liaison ciblée. Cependant, il s’agit du composant de Firebase le plus récent et le moins développé et très rapidement, vous vous trouverez à court de possibilités lorsque vous voudrez faire quelque chose de plus évolué.
Liaisons dynamiques != Liaisons hébergées par Branch
Les critères énoncés ci-dessus sont identiques à ceux identifiés lors du démarrage de la création de Branch en 2014. Ils sont le noyau central d’un service de liaison ciblée réussie et la base de tout ce que Branch a créé, dans la mesure où nous sommes devenus l’infrastructure de gestion de la liaison des meilleures applications du monde. Mais les difficultés surgissent dans les menus détails. En tant que développeur d’applications, que pouvez-vous réellement faire avec ces liaisons?
Liaisons dynamiques | Branch | |
Génération des liaisons au cœur de l’application | X | X |
Génération de liaisons en utilisant uniquement le tableau de bord en ligne | X | X |
URL de liaison sans spam | X | |
Paramètres de données modulables et personnalisés par liaison | X* | X |
Routage vers le contenu spécifique, même lorsque l’application n’est pas installée | X | X |
Réponse normalisée des données de la liaison sous le format JSON | X | |
Attribution de la première installation | X | |
Garantie de la précision d’adéquation lors de la première installation | X | |
Identification des utilisateurs uniques (pour les renvois, etc.) | X | |
Assistance technique de pointe et soutenue par les niveaux de service SLA | X | |
Gestion complète des cas limites (y compris Facebook et le courrier électronique) | X |
* Doit être codé manuellement dans le cadre de l’URL de la liaison
Un exemple pratique
Sous forme de tableau, tout semble parfait, mais que se passe-t-il si nous voulons mettre en œuvre une fonctionnalité équivalente de liaison ciblée dans une application simple sous iOS, comme notre application bureautique Branch Room Maps app? Comparons exactement les codes.
Nous devons d’abord ouvrir une session et gérer les liaisons entrantes. Voici ce que nous obtenons en utilisant 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 | |
} | |
} |
Et voici la même chose, avec la mise en œuvre en utilisant 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) | |
} | |
} |
Comme vous pouvez le constater, il n’y a pratiquement pas de différences à ce stade. La plupart des choses sont légèrement plus simples avec Branch, mais rien qu’un bon informaticien ne puisse gérer.
Ensuite, créons quelques liaisons. D’abord avec 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)“) | |
}) | |
} | |
} |
Maintenant, avec 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)“) | |
}) | |
} | |
} |
Ici encore, un peu plus de travail manuel pour le code avec Firebase, cependant la vraie différence réside dans les URL de liaison elles-mêmes (les liaisons de marque ont une réelle importance).
Mais le plus important est de loin ce que vous pouvez réellement faire avec ces liaisons lors de leur utilisation. Voici les données que vous obtenez à partir de ces relevés d’image mémoire de retour dans 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
Dans ce cas, les deux plates-formes ne se ressemblent en rien. Branch vous propose une liste complète de paramètres contextuels utiles, parmi lesquels la détection de l’installation (+is_first_session) et la précision d’adéquation (+match_guaranteed). La détection de l’installation est cruciale pour la création d’expériences telles que l’intégration personnalisée et la précision d’adéquation permet la liaison ciblée au contenu personnalisé, en vous assurant que vous bénéficiez du bon utilisateur, ce que Branch fait mieux que quiconque dans cet écosystème.
En fait, certains de nos clients ont tellement confiance dans notre précision qu’ils utilisent les liens de Branch pour enregistrer automatiquement les utilisateurs dans une application la première fois qu’ils l’ouvrent.
Firebase renvoie une simple URL brute.
Et c’est là où les liaisons universelles s’arrêtent. Elles enverront vos utilisateurs là où vous le désirez (la plupart du temps c’est-à-dire si vous ne vous heurtez pas à trop de cas limites) et ils effectueront le suivi des clics sur le lien, mais pas grand chose de plus. D’autre part, Branch ne vient que de démarrer. Pour nous, un système de liaison ciblée solide n’est que le cadre dans lequel construire tout le reste:
- Bannières intelligentes des parcours: la bannière intelligente d’application la plus puissante et flexible disponible sur le marché.
- Deepviews: augmente la conversion en fournissant aux utilisateurs un aperçu du contenu de votre application avant de la télécharger.
- E-mails avec liaisons ciblées: ajoute automatiquement des liaisons ciblées à vos e-mails commerciaux.
- Références: effectue le suivi des références et accorde des crédits à vos utilisateurs.
- Intégration des données: envoie automatiquement les données d’analyse de votre liaison aux outils externes.
- Text Me The App: permet aux visiteurs du bureau d’envoyer eux-mêmes un lien de téléchargement par SMS.
- Analyse complète: assure le suivi des clics sur votre liaison, des installations, du contenu le plus performant, des utilisateurs les plus importants et plus encore.
De plus, comme nous sommes nous-mêmes des développeurs et des programmateurs d’application, nous comprenons combien il est important d’obtenir de l’aide en cas de besoin. Nous examinons chaque question sur StackOverflow avec la balise Branch.io, et nos équipes d’intégration offrent une assistance illimitée gratuite à TOUS les partenaires.
Comment tirer le meilleur parti de ces deux mondes
Voici le meilleur: vous n’avez pas à choisir. Firebase est mis en œuvre sous forme d’une série de kits SDK indépendants et modulables. Comme de toutes façons, vous devez ajouter un autre kit SDK pour mettre en œuvre les liaisons dynamiques, il est tout aussi simple d’utiliser Branch à la place. En fait, c’est probablement plus aisé ! Vous pouvez bénéficier de tous les avantages de la plate-forme AaaS Firebase et la flexibilité et la puissance du système de liaison ciblée le plus perfectionné du monde.