如何解决运行时权限Bug?获取DeviceID权限实现问题求助
Hey there! It looks like you’ve started on the right track by checking for the READ_PHONE_STATE permission, but the missing pieces around requesting permissions and handling the user’s response are almost certainly causing your bug. Let’s walk through a complete, working solution to get this sorted out.
First, Double-Check Your Manifest
Before diving into runtime permission logic, make sure you’ve declared the required permission in your AndroidManifest.xml—this is a non-negotiable first step:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
Heads-up for Android 10+ (API Level 29): Google restricted access to IMEI/Device ID via
READ_PHONE_STATEon these versions. If your app targets API 29 or higher, you’ll need to useSettings.Secure.ANDROID_IDinstead (we’ll cover that workaround later).
Complete Runtime Permission Flow
Your current code only checks if the permission is granted, but doesn’t handle the case where it’s missing. Here’s how to fill in the gaps properly:
1. Define a Permission Request Code
First, add a constant to identify your permission request (this helps match the callback later):
private static final int REQUEST_READ_PHONE_STATE = 101;
2. Full Permission Check & Request Logic
Update your existing code to request the permission when it’s not already granted:
TelephonyManager tManager = (TelephonyManager) Constants.currentActivity.getSystemService(Context.TELEPHONY_SERVICE); // Check if permission is already granted if (ActivityCompat.checkSelfPermission(Constants.currentActivity, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) { // Request the permission from the user ActivityCompat.requestPermissions( Constants.currentActivity, new String[]{Manifest.permission.READ_PHONE_STATE}, REQUEST_READ_PHONE_STATE ); } else { // Permission is granted—safe to retrieve Device ID String deviceId = getDeviceId(tManager); // Use the deviceId for your needs } // Helper method to handle API version differences for Device ID retrieval private String getDeviceId(TelephonyManager telephonyManager) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { return telephonyManager.getImei(); // For API 26 and above } else { return telephonyManager.getDeviceId(); // For older Android versions } }
3. Handle the Permission Request Callback
You need to override the onRequestPermissionsResult method in your Activity to respond to the user’s choice (grant or deny):
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_READ_PHONE_STATE) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // Permission granted—fetch the Device ID now TelephonyManager tManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); String deviceId = getDeviceId(tManager); // Use the deviceId as needed } else { // Permission denied—handle this gracefully (e.g., explain why you need the permission) Toast.makeText(this, "Permission denied. We can't retrieve your device ID to complete this action.", Toast.LENGTH_SHORT).show(); } } }
Critical Notes for Higher Android Versions
If your app targets API 29 (Android 10) or above:
READ_PHONE_STATEno longer allows access to IMEI/Device ID. Instead, useSettings.Secure.ANDROID_IDas an alternative:
String androidId = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
- Keep in mind: Android ID resets if the user performs a factory reset, and on Android 12+, each app gets a unique Android ID (so it won’t identify a user across different apps).
Bonus: Avoid Memory Leaks with Constants.currentActivity
Make sure Constants.currentActivity is stored using a WeakReference instead of a strong reference to prevent memory leaks. For example:
public class Constants { public static WeakReference<Activity> currentActivity; }
Then set it in your Activity’s onCreate or onResume:
Constants.currentActivity = new WeakReference<>(this);
And when accessing it, always check if it’s still valid:
Activity activity = Constants.currentActivity.get(); if (activity != null) { // Use the activity safely }
That should cover all the common issues with runtime permissions for Device ID retrieval. If you hit any specific edge cases or error messages, feel free to share more details!
内容的提问来源于stack exchange,提问作者YoYo

