You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Android App中获取并展示WhatsApp用户状态?实时获取可行吗?

Hey there! Let's walk through how to build an Android Activity that displays WhatsApp statuses, including real-time updates. First, some critical context you need to know:

Critical Pre-Requisite: WhatsApp's Limitations

WhatsApp doesn't offer an official public API to fetch user statuses directly. The only way to access these statuses is by reading the local storage directory where WhatsApp temporarily saves friends' status media (images/videos). Keep in mind:

  • This method relies on WhatsApp's current storage structure — if they change it in an update, your implementation might break.
  • Android 10+ Scoped Storage restrictions mean you can't directly access this folder without explicit user permission.
Step 1: Get Access to WhatsApp's Status Directory

For Android 11 and above, you need to ask the user to manually grant access to WhatsApp's hidden status folder (Android/media/com.whatsapp/WhatsApp/Media/.Statuses). Here's how to trigger the directory picker:

private const val REQUEST_CODE_PICK_WHATSAPP_DIR = 101

fun launchWhatsAppDirPicker() {
    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
    // Pre-select the WhatsApp status directory if possible
    val initialUri = Uri.parse("content://com.android.externalstorage.documents/tree/primary%3AAndroid%2Fmedia%2Fcom.whatsapp%2FWhatsApp%2FMedia%2F.Statuses")
    intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, initialUri)
    startActivityForResult(intent, REQUEST_CODE_PICK_WHATSAPP_DIR)
}

// Handle the result in onActivityResult (or registerForActivityResult for newer APIs)
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == REQUEST_CODE_PICK_WHATSAPP_DIR && resultCode == RESULT_OK) {
        data?.data?.let { selectedDirUri ->
            // Save this URI for future access (use SharedPreferences)
            saveSelectedDirUri(selectedDirUri)
            // Load status files immediately
            loadStatusFiles(selectedDirUri)
        }
    }
}
Step 2: Read Status Files from the Directory

Once you have access to the directory, use ContentResolver to iterate through the media files. These files are the temporary statuses saved by WhatsApp:

// Data class to hold status file info
data class StatusFile(
    val name: String,
    val mimeType: String,
    val lastModified: Long,
    val uri: Uri
)

fun loadStatusFiles(dirUri: Uri) {
    val statusFiles = mutableListOf<StatusFile>()
    val childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(
        dirUri,
        DocumentsContract.getTreeDocumentId(dirUri)
    )

    contentResolver.query(
        childrenUri,
        null,
        null,
        null,
        "${DocumentsContract.Document.COLUMN_LAST_MODIFIED} DESC" // Sort newest first
    )?.use { cursor ->
        val nameCol = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_DISPLAY_NAME)
        val mimeTypeCol = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_MIME_TYPE)
        val lastModifiedCol = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_LAST_MODIFIED)
        val docIdCol = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_DOCUMENT_ID)

        while (cursor.moveToNext()) {
            val fileUri = DocumentsContract.buildDocumentUriUsingTree(dirUri, cursor.getString(docIdCol))
            statusFiles.add(
                StatusFile(
                    cursor.getString(nameCol),
                    cursor.getString(mimeTypeCol),
                    cursor.getLong(lastModifiedCol),
                    fileUri
                )
            )
        }
    }
    // Update your RecyclerView with the loaded files
    updateStatusRecyclerView(statusFiles)
}
Step 3: Implement Real-Time Status Updates

To detect when new statuses are added (or old ones are deleted by WhatsApp), use a ContentObserver to monitor changes in the directory:

private lateinit var statusObserver: ContentObserver

override fun onStart() {
    super.onStart()
    val selectedDirUri = getSavedDirUri() // Retrieve from SharedPreferences
    selectedDirUri?.let { uri ->
        statusObserver = object : ContentObserver(Handler(Looper.getMainLooper())) {
            override fun onChange(selfChange: Boolean, changedUri: Uri?) {
                super.onChange(selfChange, changedUri)
                // Refresh status list when directory changes
                loadStatusFiles(uri)
            }
        }
        val childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(uri, DocumentsContract.getTreeDocumentId(uri))
        contentResolver.registerContentObserver(childrenUri, true, statusObserver)
    }
}

override fun onStop() {
    super.onStop()
    contentResolver.unregisterContentObserver(statusObserver)
}
Step 4: Build the Status Display UI

Use a RecyclerView to display status thumbnails (matching the layout you referenced in your attachment):

  1. Item Layout: Create a layout for each status item with an ImageView for the thumbnail (add a play icon overlay for videos).
  2. RecyclerView Adapter:
class StatusAdapter(
    private val statusList: List<StatusFile>,
    private val onItemClick: (StatusFile) -> Unit
) : RecyclerView.Adapter<StatusAdapter.StatusViewHolder>() {

    inner class StatusViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val thumbnail: ImageView = itemView.findViewById(R.id.iv_status_thumbnail)
        val playIcon: ImageView = itemView.findViewById(R.id.iv_play_icon)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StatusViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_status, parent, false)
        return StatusViewHolder(view).apply {
            itemView.setOnClickListener {
                onItemClick(statusList[adapterPosition])
            }
        }
    }

    override fun onBindViewHolder(holder: StatusViewHolder, position: Int) {
        val status = statusList[position]
        if (status.mimeType.startsWith("image/")) {
            holder.playIcon.visibility = View.GONE
            Glide.with(holder.thumbnail.context)
                .load(status.uri)
                .centerCrop()
                .into(holder.thumbnail)
        } else if (status.mimeType.startsWith("video/")) {
            holder.playIcon.visibility = View.VISIBLE
            // Load video thumbnail
            val thumbnail = ThumbnailUtils.createVideoThumbnail(
                status.uri.path,
                MediaStore.Video.Thumbnails.MINI_KIND
            )
            holder.thumbnail.setImageBitmap(thumbnail)
        }
    }

    override fun getItemCount() = statusList.size
}
  1. Setup RecyclerView in Activity:
fun updateStatusRecyclerView(statusList: List<StatusFile>) {
    val recyclerView = findViewById<RecyclerView>(R.id.rv_statuses)
    recyclerView.layoutManager = GridLayoutManager(this, 3) // Adjust grid columns as needed
    recyclerView.adapter = StatusAdapter(statusList) { status ->
        // Launch full-screen view activity on click
        val intent = Intent(this, StatusDetailActivity::class.java)
        intent.putExtra("STATUS_URI", status.uri)
        intent.putExtra("STATUS_MIME_TYPE", status.mimeType)
        startActivity(intent)
    }
}
Key Notes to Keep in Mind
  • WhatsApp Directory Changes: WhatsApp might alter its storage path in future updates — test your app regularly to ensure compatibility.
  • Privacy Compliance: Your app must disclose in its privacy policy that it accesses WhatsApp's local status files, and you must not collect or share this data without user consent.
  • File Lifespan: WhatsApp automatically deletes status files after 24 hours, so your app's displayed statuses will mirror this behavior.

内容的提问来源于stack exchange,提问作者Nauman Shafqat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:54:53