Android 10及以上系统BLE设备断开后后台呼叫与短信功能失效问题排查求助
Hey there, let's dive into why your BLE tracking app's call and SMS alerts are failing on Android 10 and 11. This is almost certainly tied to the stricter background execution rules and permission changes Google introduced starting with API 29. Let's break down the issues and fix them step by step.
Core Issues Identified
From your description, the functions are being triggered but not executing as expected—here's why:
- Android 10+ Background Activity Launch Restrictions: Directly starting an
ACTION_CALLactivity from the background is blocked on API 29+. - Tighter Permission Enforcement: Android 11 (API 30) added stricter checks for call/sms permissions, especially when the app isn't in the foreground.
- Unsafe Thread Blocking: Using
sleep(60000)in your loop will block the current thread, which can lead to ANRs or the system killing your background task. - Background Execution Limits: Android 10+ restricts what apps can do while in the background, including sending SMS or initiating calls unless the app is running as a foreground service.
Step-by-Step Fixes
1. Ensure Proper Runtime Permission Handling
Your manifest includes the right permissions, but dangerous permissions like CALL_PHONE and SEND_SMS require runtime approval on Android 6+ (API 23+). Make sure you're requesting these permissions explicitly before attempting to call/send SMS:
// Example runtime permission request for CALL_PHONE and SEND_SMS private static final int REQUEST_CODE_PERMISSIONS = 1001; String[] permissions = {Manifest.permission.CALL_PHONE, Manifest.permission.SEND_SMS}; if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(this, Manifest.permission.SEND_SMS) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, permissions, REQUEST_CODE_PERMISSIONS); }
For Android 11+, users must explicitly grant these permissions—there's no "allow all the time" option for call/sms, so you'll need to guide users to enable them if denied.
2. Fix Call Functionality (Android 10+)
You can't directly start an ACTION_CALL activity from the background on API 29+. Instead, use one of these approaches:
Option A: Use TelecomManager (API 26+)
This method initiates a call without launching an activity, which avoids the background launch restriction. Make sure you're running this code in a foreground service:
TelecomManager telecomManager = (TelecomManager) getSystemService(Context.TELECOM_SERVICE); if (telecomManager != null) { try { String phoneNumber = String.valueOf(contactJsonArray.get(i)); Uri callUri = Uri.parse("tel:" + phoneNumber); if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED) { telecomManager.placeCall(callUri, null); } } catch (JSONException e) { e.printStackTrace(); } }
Option B: Trigger Call via Foreground Notification
If you need to keep the activity-based flow, create a foreground notification with a PendingIntent that launches the call intent. Users will need to tap the notification to initiate the call (this complies with Android's background rules):
// Create a notification channel first (required for API 26+) private static final String ALERT_CHANNEL_ID = "BLE_ALERT_CHANNEL"; private static final int NOTIFICATION_ID = 1002; NotificationChannel channel = new NotificationChannel(ALERT_CHANNEL_ID, "BLE Disconnect Alerts", NotificationManager.IMPORTANCE_HIGH); NotificationManager notificationManager = getSystemService(NotificationManager.class); notificationManager.createNotificationChannel(channel); // Build notification with call PendingIntent String phoneNumber = String.valueOf(contactJsonArray.get(i)); Intent callIntent = new Intent(Intent.ACTION_CALL); callIntent.setData(Uri.parse("tel:" + phoneNumber)); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, callIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); Notification notification = new NotificationCompat.Builder(this, ALERT_CHANNEL_ID) .setContentTitle("BLE Device Disconnected") .setContentText("Tap to call " + phoneNumber) .setSmallIcon(R.drawable.ic_alert) .setContentIntent(pendingIntent) .setPriority(NotificationCompat.PRIORITY_HIGH) .build(); // Start foreground service to show the notification startForeground(NOTIFICATION_ID, notification);
3. Fix SMS Functionality
Android 10+ restricts background SMS sending. To ensure delivery:
- Run the SMS code inside a foreground service (you already have the
FOREGROUND_SERVICEpermission). - Use
sendMultipartTextMessageinstead ofsendTextMessageto handle long SMS messages that would otherwise fail:
SmsManager smsManager = SmsManager.getDefault(); for (int i = 0; i < contactJsonArray.length(); i++) { try { String phoneNumber = String.valueOf(contactJsonArray.get(i)); ArrayList<String> smsParts = smsManager.divideMessage(text); smsManager.sendMultipartTextMessage(phoneNumber, null, smsParts, null, null); } catch (JSONException e) { e.printStackTrace(); } }
4. Replace Thread.sleep with Safe Delay Handling
Using sleep(60000) blocks the thread, which can cause ANRs or get your task killed by the system. Replace it with a Handler or WorkManager for delayed execution:
// Using Handler for delayed calls (run on main thread) Handler handler = new Handler(Looper.getMainLooper()); for (int i = 0; i < contactJsonArray.length(); i++) { final int index = i; handler.postDelayed(() -> { // Execute call/sms logic here }, i * 60000); // Delay each action by 60 seconds }
If you're working in a background service, use HandlerThread to avoid blocking the main thread.
5. Enforce Foreground Service for BLE Monitoring
Since your app relies on BLE disconnect alerts, ensure your BLE scanning/connection service runs as a foreground service. This prevents the system from killing your service in the background, ensuring the alert logic is triggered reliably.
Final Checks
- Test on Android 10/11 devices with all permissions granted.
- Verify that your foreground service shows a persistent notification (required by Android 8+).
- Check logcat for permission denial or activity launch errors (filter by your app's package name).
内容的提问来源于stack exchange,提问作者Saroja Thirumurugan

