Android

【Android】讀取手機簡訊 顯示到自己的 APP 上 範例

【Android】讀取手機簡訊 顯示到自己的 APP 上 範例

在Android中,content://sms/inbox 是一個URI,它表示手機收件箱中的所有短信消息。開發者可以使用此URI來讀取手機上的短信消息,例如用於短信備份、消息提醒等應用場景。

使用此URI,開發者可以查詢收件箱中的所有短信消息,並讀取每個消息的發送者、接收者、時間戳和消息內容等信息。例如,可以使用以下代碼讀取收件箱中的短信消息。


文章目錄

  1. Manifest 申請權限
  2. 讀取簡訊
  3. 簡訊 projection
  4. 顯示所有簡訊
  5. SMSReadDemo Github

1.Manifest 申請權限

<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
build.gradle
buildFeatures {
    viewBinding true
}
MainActivity.kt
class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    private val readPermission = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {}

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        readPermission.launch(
            arrayOf(
                android.Manifest.permission.RECEIVE_SMS,
                android.Manifest.permission.READ_SMS
            )
        )
    }
}

2.讀取簡訊

MainActivity.kt
private fun querySMS(): MutableList<SMS> {
    val uri = Uri.parse("content://sms/inbox")
    val projection = arrayOf("_id", "address", "body", "date")
    val smsList = mutableListOf<SMS>()

    contentResolver.query(uri, projection, null, null, null)?.apply {
        if (moveToFirst()) {
            do {
                val id = getInt(getColumnIndexOrThrow("_id"))
                val sender = getString(getColumnIndexOrThrow("address"))
                val body = getString(getColumnIndexOrThrow("body"))
                val timestamp = getLong(getColumnIndexOrThrow("date"))
                val dateFormat = SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.TAIWAN)
                val dateTime = dateFormat.format(Date(timestamp))
                smsList.add(SMS(id, sender, body, dateTime))
            } while (moveToNext())
        }
        close()
    }

    return smsList
}

3.簡訊 projection

_id:短信 ID
thread_id:與該條短信相關聯的會話 ID
address:發送者或接收者的電話號碼
person:發送者或接收者在聯系人列表中的 ID
date:短信的時間戳,以毫秒為單位
date_sent:短信發送的時間戳,以毫秒為單位
protocol:短信協議
read:短信是否已讀
status:短信狀態
type:短信類型,1 表示收到的短信,2 表示發送的短信
body:短信內容

4.顯示所有簡訊

MainActivity.kt
class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    private val readPermission = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {}

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        readPermission.launch(
            arrayOf(
                android.Manifest.permission.RECEIVE_SMS,
                android.Manifest.permission.READ_SMS
            )
        )

        binding.recyclerView.apply {
            layoutManager = LinearLayoutManager(this@MainActivity)
            setHasFixedSize(true)
            adapter = SMSAdapter(querySMS())

            val divider = DividerItemDecoration(this@MainActivity, DividerItemDecoration.VERTICAL)
            addItemDecoration(divider)
        }
    }

    private fun querySMS(): MutableList<SMS> {
        val uri = Uri.parse("content://sms/inbox")
        val projection = arrayOf("_id", "address", "body", "date")
        val smsList = mutableListOf<SMS>()

        contentResolver.query(uri, projection, null, null, null)?.apply {
            if (moveToFirst()) {
                do {
                    val id = getInt(getColumnIndexOrThrow("_id"))
                    val sender = getString(getColumnIndexOrThrow("address"))
                    val body = getString(getColumnIndexOrThrow("body"))
                    val timestamp = getLong(getColumnIndexOrThrow("date"))
                    val dateFormat = SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.TAIWAN)
                    val dateTime = dateFormat.format(Date(timestamp))

                    smsList.add(SMS(id, sender, body, dateTime))
                } while (moveToNext())
            }
            close()
        }

        return smsList
    }

}
SMSAdapter.kt
class SMSAdapter(private var smsList: List<SMS>) : RecyclerView.Adapter<SMSAdapter.SMSHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SMSHolder {
        return SMSHolder(SmsItemBinding.inflate(LayoutInflater.from(parent.context), parent, false))
    }

    override fun onBindViewHolder(holder: SMSHolder, position: Int) {
        holder.onBind(position)
    }

    override fun getItemCount() = smsList.size

    inner class SMSHolder(private val smsItemBinding: SmsItemBinding) : RecyclerView.ViewHolder(smsItemBinding.root) {
        fun onBind(position: Int) {
            smsItemBinding.sender.text = smsList[position].sender
            smsItemBinding.body.text = smsList[position].body
            smsItemBinding.date.text = smsList[position].dateTime
        }
    }

}
SMS.kt
data class SMS(
    val id: Int,
    val sender: String,
    val body: String,
    val dateTime: String
)
sms_item.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:background="#C4E1FF"
    android:padding="5dp"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_marginBottom="10dp"
        android:id="@+id/smsLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/sender"
            android:layout_width="0dp"
            android:textColor="#008000"
            android:textStyle="bold"
            android:layout_height="wrap_content"
            android:gravity="center"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            tools:text="sender" />

        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/body"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:textColor="@color/black"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="@+id/sender"
            app:layout_constraintTop_toBottomOf="@+id/date"
            tools:text="body" />

        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/date"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:textColor="#9FA2A4"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            tools:text="date" />


    </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#C4E1FF"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:listitem="@layout/sms_item" />

</androidx.constraintlayout.widget.ConstraintLayout>

5.SMSReadDemo Github

SMSReadDemo Github

發表迴響