ภาพรวม
ตัวอย่างนี้สาธิตการดึงหมายเลข Serial Number ของอุปกรณ์ Android ผ่าน Build.SERIAL และ TelephonyManager พร้อมจัดการ Runtime Permission สำหรับ READ_PHONE_STATE
⚠️ ข้อจำกัดสำคัญ (Android 10+ / API 29+)
ตั้งแต่ Android 10 (API 29) เป็นต้นมา ไม่สามารถเข้าถึง Serial Number จริงได้แล้ว เพื่อเหตุผลด้านความเป็นส่วนตัว
Build.SERIALจะคืนค่า "UNKNOWN" เสมอTelephonyManager.getSerial()ต้องการ PermissionREAD_PRIVILEGED_PHONE_STATE(System App เท่านั้น)- แอปทั่วไปควรใช้ Android ID (
Settings.Secure.ANDROID_ID) หรือ Advertising ID แทน
ขั้นตอนที่ 1: สร้างโปรเจกต์ใหม่
Android Studio → File → New Project → Empty Activity
ขั้นตอนที่ 2: จัดรูปแบบหน้าจอ (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">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:onClick="showDeviceInfo"
android:text="Get Serial Number" />
<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="16sp"
android:textSize="16sp" />
</RelativeLayout>
ขั้นตอนที่ 3: เขียนโค้ด MainActivity.java
import android.Manifest;
import android.app.AlertDialog;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.telephony.TelephonyManager;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_CODE_PHONE_STATE = 100;
private TextView textView;
private boolean permissionGranted = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
// ตรวจสอบ Permission เริ่มต้น
checkPermission();
}
private void checkPermission() {
int permissionCheck = ContextCompat.checkSelfPermission(this,
Manifest.permission.READ_PHONE_STATE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.READ_PHONE_STATE},
REQUEST_CODE_PHONE_STATE);
} else {
permissionGranted = true;
}
} else {
// Android 5.1 (API 22) และต่ำกว่า ให้ Permission อัตโนมัติตอน Install
permissionGranted = true;
}
}
public void showDeviceInfo(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
StringBuilder info = new StringBuilder();
// 1. Build.SERIAL (Android 9 และต่ำกว่า ทำงานได้, Android 10+ คืน "UNKNOWN")
String serial = Build.SERIAL;
info.append("Build.SERIAL: ").append(serial).append("\n\n");
// 2. Android ID (ไม่ต้อง Permission, คงที่ต่อการติดตั้งแอป)
String androidId = Settings.Secure.getString(getContentResolver(),
Settings.Secure.ANDROID_ID);
info.append("Android ID: ").append(androidId).append("\n\n");
// 3. TelephonyManager (ต้อง Permission READ_PHONE_STATE)
if (permissionGranted) {
TelephonyManager telephonyManager = (TelephonyManager)
getSystemService(Context.TELEPHONY_SERVICE);
// IMEI (Android 8.0+ ต้อง Permission)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (checkSelfPermission(Manifest.permission.READ_PHONE_STATE)
== PackageManager.PERMISSION_GRANTED) {
info.append("IMEI: ").append(telephonyManager.getImei()).append("\n");
}
} else {
info.append("IMEI: ").append(telephonyManager.getDeviceId()).append("\n");
}
} else {
info.append("IMEI: Permission denied\n");
}
builder.setTitle("Device Information")
.setMessage(info.toString())
.setPositiveButton("OK", null)
.show();
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CODE_PHONE_STATE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
permissionGranted = true;
Toast.makeText(this, "Permission granted", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show();
}
}
}
}
ขั้นตอนที่ 4: AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="app.com.sample">
<uses-permission android:name="android.permission.READ_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>
</intent-filter>
</activity>
</application>
</manifest>
การทดสอบ
รันแอป → กดปุ่ม "Get Serial Number" → จะแสดง Dialog ข้อมูลอุปกรณ์
สรุป Identifier ต่างๆ ใน Android
| Identifier | API | Permission | ความคงที่ | หมายเหตุ |
|---|---|---|---|---|
| Serial Number | Build.SERIAL | - | Hardware | Android 10+ คืน UNKNOWN |
| Android ID | Settings.Secure.ANDROID_ID | - | Per Install | Reset เมื่อ Factory Reset |
| IMEI/MEID | TelephonyManager | READ_PHONE_STATE | Hardware | เฉพาะอุปกรณ์ที่มี SIM |
| Advertising ID | AdvertisingIdClient | - | Per User | ผู้ใช้ Reset ได้, สำหรับ Ads |
| Instance ID | FirebaseInstanceId | - | Per App Install | สำหรับ Push Notification |
แนวทางปฏิบัติที่ดีที่สุด (Best Practice)
- ใช้ Android ID สำหรับระบุตัวตนอุปกรณ์ทั่วไป
- ใช้ Advertising ID สำหรับการตลาด/Analytics
- ใช้ Firebase Installation ID สำหรับ Push Notification
- หลีกเลี่ยงการใช้ Hardware ID (IMEI, Serial) เพราะจำกัดมากใน Android ใหม่
- สร้าง UUID เองเก็บใน SharedPreferences หากต้องการ ID ที่ควบคุมได้เต็มที่