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

Android中READ_PHONE_STATE权限配置及设备序列号获取问题求助

Android获取设备序列号权限崩溃及权限受阻问题解决

问题背景

需要在Android应用中收集设备序列号用于数据签名,尝试用getprop ro.serialno获取,但遇到以下问题:

  • 仅在AndroidManifest.xml添加READ_PHONE_STATE权限无效
  • 复用原有权限请求代码后应用启动崩溃
  • 读取序列号时出现权限拒绝错误

崩溃报错信息

--------- beginning of crash
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.strujomeri, PID: 17563
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.strujomeri/com.strujomeri.MainActivity}: java.lang.ArrayIndexOutOfBoundsException: length=0; index=0

AndroidManifest.xml权限配置

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

权限请求代码

ActivityCompat.requestPermissions(MainActivity.this,
        new String[]{Manifest.permission.READ_PHONE_STATE},
        STATE_REQUEST);

权限处理代码

if (requestCode == STATE_REQUEST) {
    if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        Toast.makeText(this, "State request granted", Toast.LENGTH_SHORT).show();
    } else {
        Toast.makeText(this, "State request granted", Toast.LENGTH_SHORT).show();
    }
}

补充错误信息

E/libc: Access denied finding property "ro.serialno"


问题分析与解决

1. 应用启动崩溃原因(ArrayIndexOutOfBoundsException)

崩溃是因为权限处理代码直接访问grantResults[0],但用户可能直接拒绝权限请求,或系统未返回权限结果,导致grantResults数组长度为0。

修复代码:先判断数组有效性再访问索引

if (requestCode == STATE_REQUEST) {
    if (grantResults != null && grantResults.length > 0) {
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(this, "权限已授予", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "权限被拒绝", Toast.LENGTH_SHORT).show();
        }
    } else {
        Toast.makeText(this, "权限请求未完成", Toast.LENGTH_SHORT).show();
    }
}

2. READ_PHONE_STATE权限受阻原因

从Android 10(API 29)开始,READ_PHONE_STATE权限不再允许获取设备序列号,ro.serialno系统属性被限制访问,普通应用即使申请权限也无法读取该属性,会返回权限拒绝错误。Android 11(API 30)及以上权限机制更严格,部分厂商还会进一步限制该权限。

3. 替代获取设备唯一标识的方法

如果用于数据签名,推荐以下合规方案:

方案一:使用Android ID

设备首次启动生成的64位字符串,恢复出厂设置才会改变,无需特殊权限:

String androidId = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);

方案二:生成应用内唯一标识

若无需跨应用的设备标识,可在应用首次启动时生成UUID并存储:

SharedPreferences sp = getSharedPreferences("device_info", MODE_PRIVATE);
String deviceId = sp.getString("unique_id", null);
if (deviceId == null) {
    deviceId = UUID.randomUUID().toString();
    sp.edit().putString("unique_id", deviceId).apply();
}

方案三:使用Advertising ID

适合广告/统计场景,依赖Google Play Services,用户可在系统设置重置:

// 需添加依赖:implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'
AdvertisingIdClient.Info adInfo = AdvertisingIdClient.getAdvertisingIdInfo(getApplicationContext());
String adId = adInfo.getId();
boolean isLAT = adInfo.isLimitAdTrackingEnabled();

4. 权限请求的正确流程

若需使用READ_PHONE_STATE获取其他设备信息,需先检查权限状态:

if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_PHONE_STATE}, STATE_REQUEST);
} else {
    // 权限已授予,执行对应操作
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 16:20:37