บทนำ
ตัวอย่างนี้แสดงวิธีดึงหมายเลข IMEI (International Mobile Equipment Identity) ของอุปกรณ์ Android ผ่าน TelephonyManager
⚠️ ข้อจำกัดสำคัญ (Android 10+ / API 29+)
- Android 10 (API 29): ต้องมี Permission
READ_PRIVILEGED_PHONE_STATE(System apps เท่านั้น) - Android 11+ (API 30+): แอปทั่วไป ไม่สามารถเข้าถึง IMEI ได้เลย
- ทางเลือก: ใช้
Settings.Secure.ANDROID_IDหรือ Advertising ID แทน
ขั้นตอนที่ 1: สร้างโปรเจกต์
สร้างโปรเจกต์ Android ใหม่ใน Android Studio
ขั้นตอนที่ 2: Layout (activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="50dp"
android:text="Device IMEI Info"
android:textAlignment="center"
android:textColor="@android:color/holo_green_dark"
android:textSize="32sp"
android:textStyle="bold" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Get IMEI" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/button"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp"
android:text="IMEI will appear here"
android:textColor="@android:color/background_dark"
android:textSize="16sp" />
</RelativeLayout>
ขั้นตอนที่ 3: MainActivity.kt
import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.telephony.TelephonyManager
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
class MainActivity : AppCompatActivity() {
private lateinit var button: Button
private lateinit var textView: TextView
private val REQUEST_CODE = 101
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
title = "Device ID Demo"
textView = findViewById(R.id.textView)
button = findViewById(R.id.button)
button.setOnClickListener {
getDeviceIdentifiers()
}
}
private fun getDeviceIdentifiers() {
val telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
// ตรวจสอบ Permission
val hasPermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// Android 10+ ต้องการ READ_PRIVILEGED_PHONE_STATE (System only)
ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
== PackageManager.PERMISSION_GRANTED
} else {
ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE)
== PackageManager.PERMISSION_GRANTED
}
if (!hasPermission) {
val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
Manifest.permission.READ_PRIVILEGED_PHONE_STATE
} else {
Manifest.permission.READ_PHONE_STATE
}
ActivityCompat.requestPermissions(this, arrayOf(permission), REQUEST_CODE)
return
}
// ดึง IMEI (อาจคืนค่า null บน Android 10+)
val imei = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
telephonyManager.imei
} else {
@Suppress("DEPRECATION")
telephonyManager.deviceId
}
// ทางเลือกอื่นๆ ที่เข้าถึงได้ง่ายกว่า
val androidId = Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID)
val serial = Build.getSerial() // ต้องการ READ_PHONE_STATE บนบางรุ่น
val result = buildString {
appendLine("Device Identifiers:")
appendLine("IMEI: ${imei ?: "Not accessible (Android 10+)"}")
appendLine("Android ID: $androidId")
appendLine("Serial: ${serial ?: "N/A"}")
appendLine()
appendLine("Note: IMEI access restricted on Android 10+")
appendLine("Use Android ID or Advertising ID for user identification")
}
textView.text = result
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == REQUEST_CODE && grantResults.isNotEmpty()
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
getDeviceIdentifiers()
} else {
Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show()
}
}
}
ขั้นตอนที่ 4: Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="com.example.deviceid">
<!-- สำหรับ Android 9 และต่ำกว่า -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- สำหรับ Android 10 (System apps เท่านั้น) -->
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
ตัวเลือกตัวระบุตัวตนที่แนะนำ (Best Practices)
| Identifier | เข้าถึงได้ | ความคงที่ | ใช้งานได้ |
|---|---|---|---|
| Advertising ID | ✅ ทุกแอป (Google Play Services) | ผู้ใช้รีเซ็ตได้ | Analytics, Ads |
| Android ID (SSAID) | ✅ ทุกแอป | คงที่ต่อ App signing key + User + Device | Fraud detection, Analytics |
| Instance ID / Firebase Installation ID | ✅ ทุกแอป | ต่อ App Install | Push notifications, Analytics |
| IMEI/MEID | ❌ Android 10+ (System only) | Hardware permanent | Carrier/Enterprise only |
ดึง Advertising ID (แนะนำ)
// build.gradle
implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'
// ใช้งาน
import com.google.android.gms.ads.identifier.AdvertisingIdClient
// ต้องรันใน Background Thread
lifecycleScope.launch(Dispatchers.IO) {
val adIdClient = AdvertisingIdClient.getAdvertisingIdInfo(this@MainActivity)
val advertisingId = adIdClient.id
val isLimitAdTracking = adIdClient.isLimitAdTrackingEnabled
// ใช้ advertisingId ต่อไป
}