0
# App Links
1
2
Facebook App Links provide deep linking functionality for seamless navigation between apps and handling of Facebook App Links. This enables users to navigate directly from Facebook content to specific screens within your app.
3
4
## App Link Data
5
6
Extract and handle App Link data from incoming intents:
7
8
```kotlin { .api }
9
class AppLinkData private constructor() {
10
val targetUri: Uri?
11
val ref: String?
12
val extras: Bundle?
13
val argumentBundle: Bundle?
14
val promotionCode: String?
15
16
companion object {
17
// Extract from activity
18
fun createFromActivity(activity: Activity): AppLinkData?
19
fun createFromAlBundle(appLinkBundle: Bundle): AppLinkData?
20
21
// Deferred deep linking
22
fun fetchDeferredAppLinkData(
23
context: Context,
24
callback: CompletionHandler
25
)
26
27
// Deferred deep linking with specific app link ID
28
fun fetchDeferredAppLinkData(
29
context: Context,
30
applicationId: String?,
31
callback: CompletionHandler
32
)
33
}
34
35
interface CompletionHandler {
36
fun onDeferredAppLinkDataFetched(appLinkData: AppLinkData?)
37
}
38
}
39
```
40
41
### Basic App Links Usage
42
43
```kotlin
44
class MainActivity : AppCompatActivity() {
45
override fun onCreate(savedInstanceState: Bundle?) {
46
super.onCreate(savedInstanceState)
47
48
// Handle direct app links
49
handleAppLink()
50
51
// Handle deferred app links (for new installs)
52
handleDeferredAppLink()
53
}
54
55
private fun handleAppLink() {
56
val appLinkData = AppLinkData.createFromActivity(this)
57
if (appLinkData != null) {
58
val targetUri = appLinkData.targetUri
59
val ref = appLinkData.ref
60
val extras = appLinkData.extras
61
val promotionCode = appLinkData.promotionCode
62
63
Log.d("AppLinks", "App link received:")
64
Log.d("AppLinks", "Target URI: $targetUri")
65
Log.d("AppLinks", "Ref: $ref")
66
Log.d("AppLinks", "Promotion Code: $promotionCode")
67
68
// Navigate to specific content based on app link
69
navigateToContent(targetUri, extras)
70
}
71
}
72
73
private fun handleDeferredAppLink() {
74
AppLinkData.fetchDeferredAppLinkData(this) { appLinkData ->
75
if (appLinkData != null) {
76
Log.d("AppLinks", "Deferred app link data received")
77
val targetUri = appLinkData.targetUri
78
val ref = appLinkData.ref
79
80
// Handle deferred deep link (e.g., after app install)
81
navigateToContent(targetUri, appLinkData.extras)
82
} else {
83
Log.d("AppLinks", "No deferred app link data")
84
}
85
}
86
}
87
88
private fun navigateToContent(uri: Uri?, extras: Bundle?) {
89
if (uri != null) {
90
when (uri.path) {
91
"/product" -> {
92
val productId = uri.getQueryParameter("id")
93
openProductDetail(productId)
94
}
95
"/article" -> {
96
val articleId = uri.getQueryParameter("id")
97
openArticle(articleId)
98
}
99
"/promotion" -> {
100
val promotionCode = extras?.getString("promotion_code")
101
applyPromotion(promotionCode)
102
}
103
else -> {
104
// Default navigation
105
Log.d("AppLinks", "Unknown app link path: ${uri.path}")
106
}
107
}
108
}
109
}
110
}
111
```
112
113
## App Links Utilities
114
115
Utility functions for working with App Links:
116
117
```kotlin { .api }
118
class AppLinks {
119
companion object {
120
// Check if app link data exists in intent
121
fun getAppLinkData(intent: Intent): AppLinkData?
122
123
// Get target URL from app link data
124
fun getTargetUrl(appLinkData: AppLinkData): String?
125
126
// Get target URL from intent
127
fun getTargetUrlFromIncomingIntent(context: Context, intent: Intent): String?
128
}
129
}
130
```
131
132
## Facebook App Link Resolver
133
134
Resolve App Links using Facebook's resolution service:
135
136
```kotlin { .api }
137
class FacebookAppLinkResolver : AppLinkResolver {
138
constructor()
139
constructor(userAgent: String?)
140
141
override fun getAppLinkFromUrlInBackground(url: Uri): Task<AppLink>
142
override fun getAppLinksFromUrlsInBackground(urls: List<Uri>): Task<Map<Uri, AppLink>>
143
144
companion object {
145
fun getWebFallbackUrl(url: Uri, userAgent: String?): Task<Uri>
146
}
147
}
148
```
149
150
### App Link Resolution Example
151
152
```kotlin
153
// Using Bolts Tasks framework
154
fun resolveAppLinks(urls: List<Uri>) {
155
val resolver = FacebookAppLinkResolver()
156
157
resolver.getAppLinksFromUrlsInBackground(urls)
158
.continueWith { task ->
159
if (task.isFaulted) {
160
Log.e("AppLinks", "Error resolving app links: ${task.error}")
161
return@continueWith null
162
}
163
164
val appLinks = task.result
165
appLinks?.forEach { (url, appLink) ->
166
Log.d("AppLinks", "URL: $url")
167
Log.d("AppLinks", "App Link: ${appLink.sourceUrl}")
168
169
// Check available targets
170
appLink.targets.forEach { target ->
171
Log.d("AppLinks", "Target: ${target.url}")
172
Log.d("AppLinks", "Package: ${target.packageName}")
173
}
174
175
// Get web fallback URL
176
val webUrl = appLink.webUrl
177
Log.d("AppLinks", "Web fallback: $webUrl")
178
}
179
180
null
181
}
182
}
183
```
184
185
## Bolts App Links Integration
186
187
The App Links functionality integrates with the Bolts framework for App Link data models:
188
189
```kotlin { .api }
190
// From facebook-bolts module
191
class AppLink {
192
val sourceUrl: Uri
193
val targets: List<Target>
194
val webUrl: Uri?
195
196
data class Target(
197
val url: Uri?,
198
val appStoreId: String?,
199
val packageName: String?,
200
val className: String?
201
)
202
}
203
204
interface AppLinkResolver {
205
fun getAppLinkFromUrlInBackground(url: Uri): Task<AppLink>
206
fun getAppLinksFromUrlsInBackground(urls: List<Uri>): Task<Map<Uri, AppLink>>
207
}
208
```
209
210
## Deep Link Navigation Patterns
211
212
Common patterns for handling different types of deep links:
213
214
```kotlin
215
class DeepLinkHandler {
216
fun handleAppLink(activity: Activity) {
217
val appLinkData = AppLinkData.createFromActivity(activity)
218
if (appLinkData != null) {
219
val targetUri = appLinkData.targetUri
220
val ref = appLinkData.ref
221
222
// Track app link usage for analytics
223
logAppLinkEvent(ref, targetUri.toString())
224
225
// Route based on URI structure
226
routeToDestination(activity, targetUri, appLinkData.extras)
227
}
228
}
229
230
private fun routeToDestination(activity: Activity, uri: Uri?, extras: Bundle?) {
231
when {
232
uri?.host == "product" -> {
233
val intent = Intent(activity, ProductDetailActivity::class.java)
234
intent.putExtra("product_id", uri.getQueryParameter("id"))
235
extras?.let { intent.putExtras(it) }
236
activity.startActivity(intent)
237
}
238
239
uri?.host == "user" -> {
240
val intent = Intent(activity, UserProfileActivity::class.java)
241
intent.putExtra("user_id", uri.getQueryParameter("id"))
242
activity.startActivity(intent)
243
}
244
245
uri?.host == "share" -> {
246
val contentId = uri.getQueryParameter("content_id")
247
val contentType = uri.getQueryParameter("type")
248
handleSharedContent(activity, contentId, contentType)
249
}
250
251
else -> {
252
// Default fallback
253
Log.w("AppLinks", "Unknown app link format: $uri")
254
activity.startActivity(Intent(activity, MainActivity::class.java))
255
}
256
}
257
}
258
259
private fun logAppLinkEvent(ref: String?, targetUrl: String) {
260
val logger = AppEventsLogger.newLogger(context)
261
val parameters = Bundle().apply {
262
putString("app_link_ref", ref)
263
putString("target_url", targetUrl)
264
putLong("timestamp", System.currentTimeMillis())
265
}
266
logger.logEvent("app_link_opened", parameters)
267
}
268
269
private fun handleSharedContent(activity: Activity, contentId: String?, contentType: String?) {
270
if (contentId != null && contentType != null) {
271
when (contentType) {
272
"article" -> openArticle(activity, contentId)
273
"video" -> openVideo(activity, contentId)
274
"product" -> openProduct(activity, contentId)
275
else -> Log.w("AppLinks", "Unknown content type: $contentType")
276
}
277
}
278
}
279
}
280
```
281
282
## Deferred Deep Linking
283
284
Handle users who install your app from a Facebook link:
285
286
```kotlin
287
class DeferredLinkHandler {
288
fun setupDeferredLinking(context: Context) {
289
// Fetch deferred app link data on app launch
290
AppLinkData.fetchDeferredAppLinkData(context) { appLinkData ->
291
if (appLinkData != null) {
292
// User came from a Facebook link before installing
293
handleDeferredLink(context, appLinkData)
294
295
// Track deferred conversion
296
trackDeferredConversion(appLinkData)
297
}
298
}
299
}
300
301
private fun handleDeferredLink(context: Context, appLinkData: AppLinkData) {
302
val targetUri = appLinkData.targetUri
303
val ref = appLinkData.ref
304
val promotionCode = appLinkData.promotionCode
305
306
Log.d("DeferredLinks", "Deferred app link data:")
307
Log.d("DeferredLinks", "Target: $targetUri")
308
Log.d("DeferredLinks", "Ref: $ref")
309
Log.d("DeferredLinks", "Promotion: $promotionCode")
310
311
// Save deferred link data for later use
312
val prefs = context.getSharedPreferences("deferred_links", Context.MODE_PRIVATE)
313
prefs.edit().apply {
314
putString("deferred_target_uri", targetUri?.toString())
315
putString("deferred_ref", ref)
316
putString("deferred_promotion", promotionCode)
317
putBoolean("has_deferred_link", true)
318
apply()
319
}
320
321
// Apply promotion code if available
322
if (promotionCode != null) {
323
applyWelcomePromotion(promotionCode)
324
}
325
326
// Show welcome flow or navigate to specific content
327
showDeferredLinkWelcome(context, targetUri)
328
}
329
330
private fun trackDeferredConversion(appLinkData: AppLinkData) {
331
val logger = AppEventsLogger.newLogger(context)
332
val parameters = Bundle().apply {
333
putString("deferred_link_ref", appLinkData.ref)
334
putString("deferred_target", appLinkData.targetUri?.toString())
335
putString("promotion_code", appLinkData.promotionCode)
336
}
337
logger.logEvent("deferred_app_link_conversion", parameters)
338
}
339
340
fun consumeDeferredLink(context: Context): AppLinkData? {
341
val prefs = context.getSharedPreferences("deferred_links", Context.MODE_PRIVATE)
342
if (prefs.getBoolean("has_deferred_link", false)) {
343
val targetUri = prefs.getString("deferred_target_uri", null)?.let { Uri.parse(it) }
344
val ref = prefs.getString("deferred_ref", null)
345
val promotion = prefs.getString("deferred_promotion", null)
346
347
// Clear the deferred link data
348
prefs.edit().clear().apply()
349
350
// Create synthetic AppLinkData
351
return if (targetUri != null) {
352
// Note: This is a simplified approach
353
// In reality, you'd need to construct the AppLinkData properly
354
createSyntheticAppLinkData(targetUri, ref, promotion)
355
} else null
356
}
357
return null
358
}
359
}
360
```
361
362
## Testing App Links
363
364
Test your App Links implementation:
365
366
```kotlin
367
class AppLinkTester {
368
fun testAppLinkHandling(activity: Activity) {
369
// Create test app link data
370
val testUri = Uri.parse("https://example.com/product?id=123&ref=facebook")
371
val testExtras = Bundle().apply {
372
putString("promotion_code", "WELCOME10")
373
putString("campaign", "summer_sale")
374
}
375
376
// Simulate app link intent
377
val testIntent = Intent(Intent.ACTION_VIEW, testUri).apply {
378
putExtras(testExtras)
379
}
380
381
// Test app link extraction
382
val appLinkData = AppLinkData.createFromActivity(activity)
383
if (appLinkData != null) {
384
Log.d("Test", "App link test successful")
385
Log.d("Test", "Target: ${appLinkData.targetUri}")
386
Log.d("Test", "Ref: ${appLinkData.ref}")
387
} else {
388
Log.w("Test", "No app link data found")
389
}
390
}
391
392
fun testDeferredLinks(context: Context) {
393
// Force fetch deferred app link for testing
394
AppLinkData.fetchDeferredAppLinkData(context) { appLinkData ->
395
if (appLinkData != null) {
396
Log.d("Test", "Deferred link test successful")
397
Log.d("Test", "Deferred target: ${appLinkData.targetUri}")
398
} else {
399
Log.d("Test", "No deferred app link data")
400
}
401
}
402
}
403
}
404
```
405
406
## Integration with Facebook Ads
407
408
App Links work seamlessly with Facebook advertising:
409
410
```kotlin
411
// Track app install attribution from Facebook ads
412
class FacebookAdTracker {
413
fun trackInstallAttribution(context: Context) {
414
AppLinkData.fetchDeferredAppLinkData(context) { appLinkData ->
415
if (appLinkData != null) {
416
val ref = appLinkData.ref
417
418
// Track attribution based on ref parameter
419
when {
420
ref?.startsWith("ad_") == true -> {
421
// User came from Facebook ad
422
trackAdConversion(ref, appLinkData)
423
}
424
ref?.startsWith("post_") == true -> {
425
// User came from Facebook post
426
trackPostConversion(ref, appLinkData)
427
}
428
ref?.startsWith("page_") == true -> {
429
// User came from Facebook page
430
trackPageConversion(ref, appLinkData)
431
}
432
}
433
}
434
}
435
}
436
437
private fun trackAdConversion(ref: String, appLinkData: AppLinkData) {
438
val logger = AppEventsLogger.newLogger(context)
439
val parameters = Bundle().apply {
440
putString("fb_ad_ref", ref)
441
putString("target_url", appLinkData.targetUri?.toString())
442
putString("promotion_code", appLinkData.promotionCode)
443
}
444
logger.logEvent("fb_ad_install_conversion", parameters)
445
}
446
}
447
```