CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-facebook-android--facebook-android-sdk

Facebook SDK for Android providing comprehensive integration with Facebook platform features including Login, Sharing, Messenger, App Links, Analytics, and Graph API

Pending
Overview
Eval results
Files

messenger.mddocs/

Messenger Integration

The Facebook Messenger module provides direct integration with Facebook Messenger for sharing content and creating rich messaging experiences. This enables users to share content from your app directly to Messenger conversations.

Messenger Utils

Core utilities for Messenger integration:

object MessengerUtils {
    // Messenger availability
    fun hasMessengerInstalled(context: Context): Boolean
    fun openMessengerInPlayStore(context: Context)
    
    // Content sharing
    fun shareToMessenger(
        activity: Activity,
        requestCode: Int,
        shareToMessengerParams: ShareToMessengerParams
    )
    
    // Reply handling
    fun handleMessengerThreadReply(
        intent: Intent,
        requestCode: Int
    ): ShareToMessengerParams?
    
    // Intent creation
    fun createShareToMessengerIntent(
        shareToMessengerParams: ShareToMessengerParams
    ): Intent?
}

Basic Messenger Sharing

class MessengerSharingActivity : AppCompatActivity() {
    companion object {
        private const val SHARE_TO_MESSENGER_REQUEST_CODE = 1000
    }
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // Check if Messenger is installed
        if (MessengerUtils.hasMessengerInstalled(this)) {
            shareToMessenger()
        } else {
            // Prompt user to install Messenger
            showInstallMessengerDialog()
        }
    }
    
    private fun shareToMessenger() {
        // Create content to share
        val bitmap = createSharableBitmap()
        
        val shareParams = ShareToMessengerParams.newBuilder(bitmap, "image/png")
            .setMetaData(Bundle().apply {
                putString("content_type", "photo")
                putString("source", "my_app")
                putLong("timestamp", System.currentTimeMillis())
            })
            .build()
        
        MessengerUtils.shareToMessenger(this, SHARE_TO_MESSENGER_REQUEST_CODE, shareParams)
    }
    
    private fun showInstallMessengerDialog() {
        AlertDialog.Builder(this)
            .setTitle("Install Messenger")
            .setMessage("This feature requires Facebook Messenger. Would you like to install it?")
            .setPositiveButton("Install") { _, _ ->
                MessengerUtils.openMessengerInPlayStore(this)
            }
            .setNegativeButton("Cancel", null)
            .show()
    }
    
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        
        if (requestCode == SHARE_TO_MESSENGER_REQUEST_CODE) {
            if (resultCode == RESULT_OK) {
                Log.d("Messenger", "Content shared successfully")
                
                // Handle reply if user responds in Messenger
                val replyParams = data?.let { 
                    MessengerUtils.handleMessengerThreadReply(it, requestCode)
                }
                
                if (replyParams != null) {
                    handleMessengerReply(replyParams)
                }
            } else {
                Log.d("Messenger", "Share cancelled or failed")
            }
        }
    }
    
    private fun handleMessengerReply(replyParams: ShareToMessengerParams) {
        val metaData = replyParams.metaData
        val isReply = metaData?.getBoolean(ShareToMessengerParams.RECIPIENT_DID_REPLY, false) ?: false
        
        if (isReply) {
            val threadToken = metaData?.getString(ShareToMessengerParams.THREAD_TOKEN)
            Log.d("Messenger", "Received reply from thread: $threadToken")
            
            // Handle the reply content
            val uri = replyParams.uri
            val mimeType = replyParams.mimeType
            
            // Process the reply based on content type
            when {
                mimeType?.startsWith("image/") == true -> handleImageReply(uri)
                mimeType?.startsWith("video/") == true -> handleVideoReply(uri)
                else -> handleGenericReply(uri, mimeType)
            }
        }
    }
}

Share to Messenger Params

Configuration for content sharing to Messenger:

class ShareToMessengerParams private constructor() {
    val uri: Uri?
    val mimeType: String?
    val metaData: Bundle?
    
    companion object {
        // Builder methods
        fun newBuilder(uri: Uri, mimeType: String): Builder
        fun newBuilder(bitmap: Bitmap, mimeType: String): Builder
        
        // Metadata keys
        const val THREAD_TOKEN = "thread_token"
        const val RECIPIENT_DID_REPLY = "recipient_did_reply"
        const val REPLY_TO_MESSAGE_ID = "reply_to_message_id"
        const val SOURCE_APPLICATION = "source_application"
        
        // MIME types
        const val MIME_TYPE_PNG = "image/png"
        const val MIME_TYPE_JPEG = "image/jpeg"
        const val MIME_TYPE_GIF = "image/gif"
        const val MIME_TYPE_MP4 = "video/mp4"
        const val MIME_TYPE_WEBP = "image/webp"
    }
    
    class Builder internal constructor() {
        fun setUri(uri: Uri): Builder
        fun setBitmap(bitmap: Bitmap): Builder
        fun setMimeType(mimeType: String): Builder
        fun setMetaData(metaData: Bundle?): Builder
        fun build(): ShareToMessengerParams
    }
}

Advanced Messenger Sharing

class AdvancedMessengerSharing {
    
    fun sharePhoto(activity: Activity, bitmap: Bitmap, caption: String) {
        val metaData = Bundle().apply {
            putString("content_type", "photo")
            putString("caption", caption)
            putString("app_name", activity.getString(R.string.app_name))
            putLong("created_time", System.currentTimeMillis())
        }
        
        val params = ShareToMessengerParams.newBuilder(bitmap, ShareToMessengerParams.MIME_TYPE_PNG)
            .setMetaData(metaData)
            .build()
        
        MessengerUtils.shareToMessenger(activity, SHARE_REQUEST_CODE, params)
    }
    
    fun shareVideo(activity: Activity, videoUri: Uri) {
        val metaData = Bundle().apply {
            putString("content_type", "video")
            putString("video_source", "user_generated")
            putLong("duration_ms", getVideoDuration(videoUri))
        }
        
        val params = ShareToMessengerParams.newBuilder(videoUri, ShareToMessengerParams.MIME_TYPE_MP4)
            .setMetaData(metaData)
            .build()
        
        MessengerUtils.shareToMessenger(activity, SHARE_REQUEST_CODE, params)
    }
    
    fun shareGif(activity: Activity, gifUri: Uri) {
        val params = ShareToMessengerParams.newBuilder(gifUri, ShareToMessengerParams.MIME_TYPE_GIF)
            .setMetaData(Bundle().apply {
                putString("content_type", "gif")
                putBoolean("animated", true)
            })
            .build()
        
        MessengerUtils.shareToMessenger(activity, SHARE_REQUEST_CODE, params)
    }
    
    fun shareWebpSticker(activity: Activity, stickerUri: Uri) {
        val params = ShareToMessengerParams.newBuilder(stickerUri, ShareToMessengerParams.MIME_TYPE_WEBP)
            .setMetaData(Bundle().apply {
                putString("content_type", "sticker")
                putBoolean("is_sticker", true)
            })
            .build()
        
        MessengerUtils.shareToMessenger(activity, SHARE_REQUEST_CODE, params)
    }
}

Messenger Thread Params

Handle thread-specific messaging parameters:

class MessengerThreadParams private constructor() {
    val threadToken: String?
    val metaData: Bundle?
    val participants: List<String>?
    val isComposer: Boolean
    
    companion object {
        const val THREAD_PARTICIPANTS = "thread_participants"
        const val IS_REPLY = "is_reply"
        const val COMPOSER_CONTEXT = "composer_context"
    }
    
    class Builder {
        fun setThreadToken(threadToken: String): Builder
        fun setMetaData(metaData: Bundle): Builder
        fun setParticipants(participants: List<String>): Builder
        fun setIsComposer(isComposer: Boolean): Builder
        fun build(): MessengerThreadParams
    }
}

Messenger Extensions Support

Support for Messenger Platform Extensions:

class MessengerExtensions {
    
    fun createQuickReply(text: String, payload: String): JSONObject {
        return JSONObject().apply {
            put("content_type", "text")
            put("title", text)
            put("payload", payload)
        }
    }
    
    fun createButtonTemplate(
        text: String,
        buttons: List<JSONObject>
    ): JSONObject {
        return JSONObject().apply {
            put("template_type", "button")
            put("text", text)
            put("buttons", JSONArray(buttons))
        }
    }
    
    fun createGenericTemplate(elements: List<JSONObject>): JSONObject {
        return JSONObject().apply {
            put("template_type", "generic")
            put("elements", JSONArray(elements))
        }
    }
    
    fun createWebUrlButton(title: String, url: String): JSONObject {
        return JSONObject().apply {
            put("type", "web_url")
            put("title", title)
            put("url", url)
        }
    }
    
    fun createPostbackButton(title: String, payload: String): JSONObject {
        return JSONObject().apply {
            put("type", "postback")
            put("title", title)
            put("payload", payload)
        }
    }
}

Gaming-Specific Messenger Integration

Messenger features specifically for gaming apps:

class MessengerGaming {
    
    fun shareGameScore(
        activity: Activity,
        score: Int,
        level: Int,
        screenshot: Bitmap?
    ) {
        val metaData = Bundle().apply {
            putString("content_type", "game_score")
            putInt("score", score)
            putInt("level", level)
            putString("game_name", activity.getString(R.string.app_name))
            putLong("achieved_at", System.currentTimeMillis())
        }
        
        val bitmap = screenshot ?: createScoreShareBitmap(score, level)
        
        val params = ShareToMessengerParams.newBuilder(bitmap, ShareToMessengerParams.MIME_TYPE_PNG)
            .setMetaData(metaData)
            .build()
        
        MessengerUtils.shareToMessenger(activity, SHARE_REQUEST_CODE, params)
    }
    
    fun shareGameInvite(
        activity: Activity,
        inviteMessage: String,
        gameData: String
    ) {
        val metaData = Bundle().apply {
            putString("content_type", "game_invite")
            putString("invite_message", inviteMessage)
            putString("game_data", gameData)
            putString("invite_type", "challenge")
        }
        
        // Create invite image
        val inviteBitmap = createGameInviteBitmap(inviteMessage)
        
        val params = ShareToMessengerParams.newBuilder(inviteBitmap, ShareToMessengerParams.MIME_TYPE_PNG)
            .setMetaData(metaData)
            .build()
        
        MessengerUtils.shareToMessenger(activity, SHARE_REQUEST_CODE, params)
    }
    
    fun shareGameResult(
        activity: Activity,
        gameResult: GameResult,
        competitorName: String?
    ) {
        val metaData = Bundle().apply {
            putString("content_type", "game_result")
            putString("result_type", gameResult.type)
            putInt("player_score", gameResult.playerScore)
            putInt("opponent_score", gameResult.opponentScore)
            putString("winner", gameResult.winner)
            competitorName?.let { putString("competitor_name", it) }
            putBoolean("is_multiplayer", competitorName != null)
        }
        
        val resultBitmap = createGameResultBitmap(gameResult, competitorName)
        
        val params = ShareToMessengerParams.newBuilder(resultBitmap, ShareToMessengerParams.MIME_TYPE_PNG)
            .setMetaData(metaData)
            .build()
        
        MessengerUtils.shareToMessenger(activity, SHARE_REQUEST_CODE, params)
    }
    
    data class GameResult(
        val type: String, // "win", "lose", "draw"
        val playerScore: Int,
        val opponentScore: Int,
        val winner: String
    )
}

Reply Handling and Thread Management

Handle replies and manage conversation threads:

class MessengerReplyHandler {
    
    fun processReply(
        context: Context,
        replyParams: ShareToMessengerParams
    ) {
        val metaData = replyParams.metaData ?: return
        val threadToken = metaData.getString(ShareToMessengerParams.THREAD_TOKEN)
        val isReply = metaData.getBoolean(ShareToMessengerParams.RECIPIENT_DID_REPLY, false)
        
        if (isReply && threadToken != null) {
            Log.d("Messenger", "Processing reply from thread: $threadToken")
            
            // Store thread information for future reference
            storeThreadInfo(context, threadToken, metaData)
            
            // Process the reply content
            val contentType = metaData.getString("content_type")
            when (contentType) {
                "photo" -> handlePhotoReply(replyParams)
                "video" -> handleVideoReply(replyParams)
                "sticker" -> handleStickerReply(replyParams)
                "game_move" -> handleGameMoveReply(replyParams)
                else -> handleGenericReply(replyParams)
            }
            
            // Track reply analytics
            trackReplyReceived(contentType, threadToken)
        }
    }
    
    private fun storeThreadInfo(context: Context, threadToken: String, metaData: Bundle) {
        val prefs = context.getSharedPreferences("messenger_threads", Context.MODE_PRIVATE)
        prefs.edit().apply {
            putString("thread_$threadToken", metaData.toString())
            putLong("thread_${threadToken}_last_activity", System.currentTimeMillis())
            apply()
        }
    }
    
    private fun handlePhotoReply(params: ShareToMessengerParams) {
        val uri = params.uri
        val metaData = params.metaData
        
        // Process photo reply
        Log.d("Messenger", "Received photo reply: $uri")
        
        // Extract any game-specific data
        val score = metaData?.getInt("score", -1)
        val level = metaData?.getInt("level", -1)
        
        if (score != -1 && level != -1) {
            // This is a game score reply
            handleGameScoreReply(uri, score, level)
        } else {
            // Regular photo reply
            handleRegularPhotoReply(uri)
        }
    }
    
    private fun handleGameMoveReply(params: ShareToMessengerParams) {
        val metaData = params.metaData ?: return
        val gameData = metaData.getString("game_data")
        val moveData = metaData.getString("move_data")
        val threadToken = metaData.getString(ShareToMessengerParams.THREAD_TOKEN)
        
        if (gameData != null && moveData != null && threadToken != null) {
            // Process the game move
            processGameMove(threadToken, gameData, moveData)
            
            // Generate response move if needed
            generateResponseMove(threadToken, gameData, moveData)
        }
    }
    
    private fun trackReplyReceived(contentType: String?, threadToken: String) {
        val logger = AppEventsLogger.newLogger(context)
        val parameters = Bundle().apply {
            putString("reply_content_type", contentType)
            putString("thread_token_hash", threadToken.hashCode().toString())
            putLong("reply_timestamp", System.currentTimeMillis())
        }
        logger.logEvent("messenger_reply_received", parameters)
    }
}

Error Handling and Fallbacks

Handle common Messenger integration errors:

class MessengerErrorHandler {
    
    fun handleMessengerError(
        activity: Activity,
        error: Exception,
        fallbackAction: () -> Unit
    ) {
        when (error) {
            is SecurityException -> {
                // Permission issue
                Log.e("Messenger", "Permission denied: ${error.message}")
                showPermissionError(activity)
            }
            is ActivityNotFoundException -> {
                // Messenger not installed or can't handle intent
                Log.e("Messenger", "Messenger not available: ${error.message}")
                offerMessengerInstallation(activity)
            }
            else -> {
                // Other errors
                Log.e("Messenger", "Messenger error: ${error.message}")
                showGenericError(activity, fallbackAction)
            }
        }
    }
    
    private fun offerMessengerInstallation(activity: Activity) {
        AlertDialog.Builder(activity)
            .setTitle("Messenger Required")
            .setMessage("This feature requires Facebook Messenger. Install it now?")
            .setPositiveButton("Install") { _, _ ->
                MessengerUtils.openMessengerInPlayStore(activity)
            }
            .setNegativeButton("Cancel", null)
            .show()
    }
    
    private fun showGenericError(activity: Activity, fallbackAction: () -> Unit) {
        AlertDialog.Builder(activity)
            .setTitle("Sharing Failed")
            .setMessage("Unable to share to Messenger. Try another sharing method?")
            .setPositiveButton("Try Alternative") { _, _ ->
                fallbackAction()
            }
            .setNegativeButton("Cancel", null)
            .show()
    }
    
    fun validateShareParams(params: ShareToMessengerParams): Boolean {
        return when {
            params.uri == null -> {
                Log.e("Messenger", "Share params missing URI")
                false
            }
            params.mimeType.isNullOrEmpty() -> {
                Log.e("Messenger", "Share params missing MIME type")
                false
            }
            !isSupportedMimeType(params.mimeType) -> {
                Log.e("Messenger", "Unsupported MIME type: ${params.mimeType}")
                false
            }
            else -> true
        }
    }
    
    private fun isSupportedMimeType(mimeType: String?): Boolean {
        return mimeType in listOf(
            ShareToMessengerParams.MIME_TYPE_PNG,
            ShareToMessengerParams.MIME_TYPE_JPEG,
            ShareToMessengerParams.MIME_TYPE_GIF,
            ShareToMessengerParams.MIME_TYPE_MP4,
            ShareToMessengerParams.MIME_TYPE_WEBP
        )
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-com-facebook-android--facebook-android-sdk

docs

app-events.md

app-links.md

bolts-tasks.md

core-authentication.md

gaming.md

graph-api.md

index.md

login.md

messenger.md

sharing.md

tile.json