Facebook SDK for Android providing comprehensive integration with Facebook platform features including Login, Sharing, Messenger, App Links, Analytics, and Graph API
—
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.
Extract and handle App Link data from incoming intents:
class AppLinkData private constructor() {
val targetUri: Uri?
val ref: String?
val extras: Bundle?
val argumentBundle: Bundle?
val promotionCode: String?
companion object {
// Extract from activity
fun createFromActivity(activity: Activity): AppLinkData?
fun createFromAlBundle(appLinkBundle: Bundle): AppLinkData?
// Deferred deep linking
fun fetchDeferredAppLinkData(
context: Context,
callback: CompletionHandler
)
// Deferred deep linking with specific app link ID
fun fetchDeferredAppLinkData(
context: Context,
applicationId: String?,
callback: CompletionHandler
)
}
interface CompletionHandler {
fun onDeferredAppLinkDataFetched(appLinkData: AppLinkData?)
}
}class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Handle direct app links
handleAppLink()
// Handle deferred app links (for new installs)
handleDeferredAppLink()
}
private fun handleAppLink() {
val appLinkData = AppLinkData.createFromActivity(this)
if (appLinkData != null) {
val targetUri = appLinkData.targetUri
val ref = appLinkData.ref
val extras = appLinkData.extras
val promotionCode = appLinkData.promotionCode
Log.d("AppLinks", "App link received:")
Log.d("AppLinks", "Target URI: $targetUri")
Log.d("AppLinks", "Ref: $ref")
Log.d("AppLinks", "Promotion Code: $promotionCode")
// Navigate to specific content based on app link
navigateToContent(targetUri, extras)
}
}
private fun handleDeferredAppLink() {
AppLinkData.fetchDeferredAppLinkData(this) { appLinkData ->
if (appLinkData != null) {
Log.d("AppLinks", "Deferred app link data received")
val targetUri = appLinkData.targetUri
val ref = appLinkData.ref
// Handle deferred deep link (e.g., after app install)
navigateToContent(targetUri, appLinkData.extras)
} else {
Log.d("AppLinks", "No deferred app link data")
}
}
}
private fun navigateToContent(uri: Uri?, extras: Bundle?) {
if (uri != null) {
when (uri.path) {
"/product" -> {
val productId = uri.getQueryParameter("id")
openProductDetail(productId)
}
"/article" -> {
val articleId = uri.getQueryParameter("id")
openArticle(articleId)
}
"/promotion" -> {
val promotionCode = extras?.getString("promotion_code")
applyPromotion(promotionCode)
}
else -> {
// Default navigation
Log.d("AppLinks", "Unknown app link path: ${uri.path}")
}
}
}
}
}Utility functions for working with App Links:
class AppLinks {
companion object {
// Check if app link data exists in intent
fun getAppLinkData(intent: Intent): AppLinkData?
// Get target URL from app link data
fun getTargetUrl(appLinkData: AppLinkData): String?
// Get target URL from intent
fun getTargetUrlFromIncomingIntent(context: Context, intent: Intent): String?
}
}Resolve App Links using Facebook's resolution service:
class FacebookAppLinkResolver : AppLinkResolver {
constructor()
constructor(userAgent: String?)
override fun getAppLinkFromUrlInBackground(url: Uri): Task<AppLink>
override fun getAppLinksFromUrlsInBackground(urls: List<Uri>): Task<Map<Uri, AppLink>>
companion object {
fun getWebFallbackUrl(url: Uri, userAgent: String?): Task<Uri>
}
}// Using Bolts Tasks framework
fun resolveAppLinks(urls: List<Uri>) {
val resolver = FacebookAppLinkResolver()
resolver.getAppLinksFromUrlsInBackground(urls)
.continueWith { task ->
if (task.isFaulted) {
Log.e("AppLinks", "Error resolving app links: ${task.error}")
return@continueWith null
}
val appLinks = task.result
appLinks?.forEach { (url, appLink) ->
Log.d("AppLinks", "URL: $url")
Log.d("AppLinks", "App Link: ${appLink.sourceUrl}")
// Check available targets
appLink.targets.forEach { target ->
Log.d("AppLinks", "Target: ${target.url}")
Log.d("AppLinks", "Package: ${target.packageName}")
}
// Get web fallback URL
val webUrl = appLink.webUrl
Log.d("AppLinks", "Web fallback: $webUrl")
}
null
}
}The App Links functionality integrates with the Bolts framework for App Link data models:
// From facebook-bolts module
class AppLink {
val sourceUrl: Uri
val targets: List<Target>
val webUrl: Uri?
data class Target(
val url: Uri?,
val appStoreId: String?,
val packageName: String?,
val className: String?
)
}
interface AppLinkResolver {
fun getAppLinkFromUrlInBackground(url: Uri): Task<AppLink>
fun getAppLinksFromUrlsInBackground(urls: List<Uri>): Task<Map<Uri, AppLink>>
}Common patterns for handling different types of deep links:
class DeepLinkHandler {
fun handleAppLink(activity: Activity) {
val appLinkData = AppLinkData.createFromActivity(activity)
if (appLinkData != null) {
val targetUri = appLinkData.targetUri
val ref = appLinkData.ref
// Track app link usage for analytics
logAppLinkEvent(ref, targetUri.toString())
// Route based on URI structure
routeToDestination(activity, targetUri, appLinkData.extras)
}
}
private fun routeToDestination(activity: Activity, uri: Uri?, extras: Bundle?) {
when {
uri?.host == "product" -> {
val intent = Intent(activity, ProductDetailActivity::class.java)
intent.putExtra("product_id", uri.getQueryParameter("id"))
extras?.let { intent.putExtras(it) }
activity.startActivity(intent)
}
uri?.host == "user" -> {
val intent = Intent(activity, UserProfileActivity::class.java)
intent.putExtra("user_id", uri.getQueryParameter("id"))
activity.startActivity(intent)
}
uri?.host == "share" -> {
val contentId = uri.getQueryParameter("content_id")
val contentType = uri.getQueryParameter("type")
handleSharedContent(activity, contentId, contentType)
}
else -> {
// Default fallback
Log.w("AppLinks", "Unknown app link format: $uri")
activity.startActivity(Intent(activity, MainActivity::class.java))
}
}
}
private fun logAppLinkEvent(ref: String?, targetUrl: String) {
val logger = AppEventsLogger.newLogger(context)
val parameters = Bundle().apply {
putString("app_link_ref", ref)
putString("target_url", targetUrl)
putLong("timestamp", System.currentTimeMillis())
}
logger.logEvent("app_link_opened", parameters)
}
private fun handleSharedContent(activity: Activity, contentId: String?, contentType: String?) {
if (contentId != null && contentType != null) {
when (contentType) {
"article" -> openArticle(activity, contentId)
"video" -> openVideo(activity, contentId)
"product" -> openProduct(activity, contentId)
else -> Log.w("AppLinks", "Unknown content type: $contentType")
}
}
}
}Handle users who install your app from a Facebook link:
class DeferredLinkHandler {
fun setupDeferredLinking(context: Context) {
// Fetch deferred app link data on app launch
AppLinkData.fetchDeferredAppLinkData(context) { appLinkData ->
if (appLinkData != null) {
// User came from a Facebook link before installing
handleDeferredLink(context, appLinkData)
// Track deferred conversion
trackDeferredConversion(appLinkData)
}
}
}
private fun handleDeferredLink(context: Context, appLinkData: AppLinkData) {
val targetUri = appLinkData.targetUri
val ref = appLinkData.ref
val promotionCode = appLinkData.promotionCode
Log.d("DeferredLinks", "Deferred app link data:")
Log.d("DeferredLinks", "Target: $targetUri")
Log.d("DeferredLinks", "Ref: $ref")
Log.d("DeferredLinks", "Promotion: $promotionCode")
// Save deferred link data for later use
val prefs = context.getSharedPreferences("deferred_links", Context.MODE_PRIVATE)
prefs.edit().apply {
putString("deferred_target_uri", targetUri?.toString())
putString("deferred_ref", ref)
putString("deferred_promotion", promotionCode)
putBoolean("has_deferred_link", true)
apply()
}
// Apply promotion code if available
if (promotionCode != null) {
applyWelcomePromotion(promotionCode)
}
// Show welcome flow or navigate to specific content
showDeferredLinkWelcome(context, targetUri)
}
private fun trackDeferredConversion(appLinkData: AppLinkData) {
val logger = AppEventsLogger.newLogger(context)
val parameters = Bundle().apply {
putString("deferred_link_ref", appLinkData.ref)
putString("deferred_target", appLinkData.targetUri?.toString())
putString("promotion_code", appLinkData.promotionCode)
}
logger.logEvent("deferred_app_link_conversion", parameters)
}
fun consumeDeferredLink(context: Context): AppLinkData? {
val prefs = context.getSharedPreferences("deferred_links", Context.MODE_PRIVATE)
if (prefs.getBoolean("has_deferred_link", false)) {
val targetUri = prefs.getString("deferred_target_uri", null)?.let { Uri.parse(it) }
val ref = prefs.getString("deferred_ref", null)
val promotion = prefs.getString("deferred_promotion", null)
// Clear the deferred link data
prefs.edit().clear().apply()
// Create synthetic AppLinkData
return if (targetUri != null) {
// Note: This is a simplified approach
// In reality, you'd need to construct the AppLinkData properly
createSyntheticAppLinkData(targetUri, ref, promotion)
} else null
}
return null
}
}Test your App Links implementation:
class AppLinkTester {
fun testAppLinkHandling(activity: Activity) {
// Create test app link data
val testUri = Uri.parse("https://example.com/product?id=123&ref=facebook")
val testExtras = Bundle().apply {
putString("promotion_code", "WELCOME10")
putString("campaign", "summer_sale")
}
// Simulate app link intent
val testIntent = Intent(Intent.ACTION_VIEW, testUri).apply {
putExtras(testExtras)
}
// Test app link extraction
val appLinkData = AppLinkData.createFromActivity(activity)
if (appLinkData != null) {
Log.d("Test", "App link test successful")
Log.d("Test", "Target: ${appLinkData.targetUri}")
Log.d("Test", "Ref: ${appLinkData.ref}")
} else {
Log.w("Test", "No app link data found")
}
}
fun testDeferredLinks(context: Context) {
// Force fetch deferred app link for testing
AppLinkData.fetchDeferredAppLinkData(context) { appLinkData ->
if (appLinkData != null) {
Log.d("Test", "Deferred link test successful")
Log.d("Test", "Deferred target: ${appLinkData.targetUri}")
} else {
Log.d("Test", "No deferred app link data")
}
}
}
}App Links work seamlessly with Facebook advertising:
// Track app install attribution from Facebook ads
class FacebookAdTracker {
fun trackInstallAttribution(context: Context) {
AppLinkData.fetchDeferredAppLinkData(context) { appLinkData ->
if (appLinkData != null) {
val ref = appLinkData.ref
// Track attribution based on ref parameter
when {
ref?.startsWith("ad_") == true -> {
// User came from Facebook ad
trackAdConversion(ref, appLinkData)
}
ref?.startsWith("post_") == true -> {
// User came from Facebook post
trackPostConversion(ref, appLinkData)
}
ref?.startsWith("page_") == true -> {
// User came from Facebook page
trackPageConversion(ref, appLinkData)
}
}
}
}
}
private fun trackAdConversion(ref: String, appLinkData: AppLinkData) {
val logger = AppEventsLogger.newLogger(context)
val parameters = Bundle().apply {
putString("fb_ad_ref", ref)
putString("target_url", appLinkData.targetUri?.toString())
putString("promotion_code", appLinkData.promotionCode)
}
logger.logEvent("fb_ad_install_conversion", parameters)
}
}Install with Tessl CLI
npx tessl i tessl/maven-com-facebook-android--facebook-android-sdk