如何让Flutter应用获取Android 11设备真实序列号(支持额外配置)
解决Flutter获取Infinix HOT 12 Play NFC设备真实序列号返回unknown的问题
问题说明
我的Flutter应用需要获取设备真实序列号用于身份识别,Android ID在设备恢复出厂设置后会变更,无法满足需求。使用设备为Infinix HOT 12 Play NFC,已在AndroidManifest.xml中添加READ_PRIVILEGED_PHONE_STATE与READ_PHONE_STATE权限,通过device_info_plus包调用接口仍返回“unknown”,需要分步解决方案,不介意设备进行额外配置。
分步解决方案
1. 明确Android权限限制
从Android 10(API 29)开始,普通第三方应用就算申请了READ_PHONE_STATE权限,也无法获取设备序列号;而READ_PRIVILEGED_PHONE_STATE是系统级权限,仅系统应用或获得系统授权的应用可使用,常规渠道无法获取该权限。
2. 设备Root并授予系统权限(适合允许设备配置的场景)
这是直接解决问题的方式:
- 先对Infinix HOT 12 Play NFC进行Root操作(步骤需匹配机型,比如先解锁Bootloader,再刷入Magisk等Root包)
- Root完成后,通过ADB命令给应用授予权限:
adb shell pm grant com.example.e_ktp_reader android.permission.READ_PRIVILEGED_PHONE_STATE - 也可以用Magisk等Root权限管理工具,手动给应用分配该权限
3. 验证设备本身是否可读取序列号
先确认设备序列号本身可被读取,执行ADB命令:
adb shell getprop ro.serialno
如果命令返回正确序列号,说明是权限问题;如果也返回unknown,代表厂商隐藏了序列号,只能更换其他标识符。
4. 调整代码完善权限流程
在Dart代码中动态请求READ_PHONE_STATE权限(低版本Android可能有效),同时校验权限状态:
import 'package:device_info_plus/device_info_plus.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:flutter/services.dart'; import 'dart:io'; static final DeviceInfoPlugin _deviceInfo = DeviceInfoPlugin(); static Future<String> getSerialNumber() async { if (Platform.isAndroid) { // 动态请求电话状态权限 PermissionStatus status = await Permission.phone.request(); if (status.isGranted) { AndroidDeviceInfo info = await _deviceInfo.androidInfo; return info.serialNumber; } else { throw PlatformException( code: "PERMISSION_DENIED", message: "电话状态权限被拒绝", ); } } throw PlatformException( code: "UNSUPPORTED", message: "不支持当前平台", ); }
5. 备选方案:使用其他硬件标识符(若Root不可行)
如果不想Root,可考虑以下替代方案,但同样受权限限制:
- IMEI:双卡设备存在两个IMEI,Android 10+普通应用无法获取,同样需要系统权限
- 自定义UUID:首次启动时生成唯一UUID并存储到本地(如SharedPreferences),但恢复出厂设置会丢失,可同步到云端作为备选,但这并非“真实序列号”
当前使用的代码
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.e_ktp_reader"> <uses-permission android:name="android.permission.NFC" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <application android:label="Sam Online" android:name="${applicationName}" android:icon="@mipmap/launcher_icon"> <activity android:name=".MainActivity" android:exported="true" android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize"> <meta-data android:name="io.flutter.embedding.android.NormalTheme" android:resource="@style/NormalTheme" /> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <meta-data android:name="flutterEmbedding" android:value="2" /> </application> </manifest>
原Dart代码
import 'package:device_info_plus/device_info_plus.dart'; // ... more imports static final DeviceInfoPlugin _deviceInfo = DeviceInfoPlugin(); // ... more code static Future<String> getSerialNumber() async { if (Platform.isAndroid) { return (await _deviceInfo.androidInfo).serialNumber; } throw PlatformException( code: "UNSUPPORTED", message: "Platform is not supported.", ); }
内容的提问来源于stack exchange,提问作者Dias Utsman
相关产品推荐
相关产品推荐

