如何通过Android AlarmManager实现ACTION_CALL定时自动通话?
定时自动通话功能实现问题
我需要通过个人应用/手机实现定时自动通话功能。目前使用AlarmManager调度通话,但仅当应用和设备处于活跃状态时该功能才生效。我在调度接收器中添加了测试蜂鸣音,即使设备处于休眠状态也能正常工作(说明调度器本身运行正常)。
请问如何从调度器触发Intent.ACTION_CALL?或者如何从调度器唤起/聚焦应用的MainActivity界面?
感谢
Steve
现有代码
权限声明
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/> <uses-permission android:name="android.permission.CALL_PHONE" /> <permission android:name="android.permission.CALL_PRIVILEGED" android:protectionLevel="signature|privileged" />
主界面设置闹钟
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); Intent myAlarmIntent = new Intent(context, MyAlarmReceiver.class); PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1000, myAlarmIntent, PendingIntent.FLAG_UPDATE_CURRENT); alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timeFromUI, pendingIntent);
闹钟接收器
public class MyAlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // 测试蜂鸣(休眠时正常工作) ToneGenerator toneGenerator = new ToneGenerator(AudioManager.STREAM_MUSIC, 100); toneGenerator.startTone(ToneGenerator.TONE_CDMA_PIP, 100); // 通话仅在应用活跃、设备唤醒时生效 Intent callIntent = new Intent(Intent.ACTION_CALL); callIntent.setData(Uri.parse(("tel:123456789"))).setFlags( Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_RECEIVER_FOREGROUND); context.startActivity(callIntent); } }
解决方案
一、休眠状态下触发Intent.ACTION_CALL的处理
你的接收器能正常触发蜂鸣但通话失败,核心是Android后台启动限制和权限问题:
清理无效权限
CALL_PRIVILEGED是系统签名级权限,普通应用无法获取,直接移除Manifest中的该权限声明。处理后台启动限制
Android 8.0(API 26)及以上,后台广播接收器无法直接启动Activity(包括系统通话界面),需通过前台服务绕过限制:修改接收器代码,转由前台服务发起通话:
public class MyAlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // 测试蜂鸣 ToneGenerator toneGenerator = new ToneGenerator(AudioManager.STREAM_MUSIC, 100); toneGenerator.startTone(ToneGenerator.TONE_CDMA_PIP, 100); // 启动前台服务 Intent callServiceIntent = new Intent(context, CallInitiateService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { context.startForegroundService(callServiceIntent); } else { context.startService(callServiceIntent); } } } // 新建通话发起服务 public class CallInitiateService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { // Android 8.0+必须创建前台通知 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel("call_channel", "定时通话", NotificationManager.IMPORTANCE_LOW); NotificationManager manager = getSystemService(NotificationManager.class); manager.createNotificationChannel(channel); Notification notification = new NotificationCompat.Builder(this, "call_channel") .setContentTitle("正在发起定时通话") .setSmallIcon(R.drawable.ic_notification) .build(); startForeground(1, notification); } // 发起通话 Intent callIntent = new Intent(Intent.ACTION_CALL); callIntent.setData(Uri.parse("tel:123456789")); callIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { startActivity(callIntent); } catch (SecurityException e) { e.printStackTrace(); } // 完成后停止服务 stopSelf(); return START_NOT_STICKY; } @Nullable @Override public IBinder onBind(Intent intent) { return null; } }同时在Manifest中注册服务:
<service android:name=".CallInitiateService" />额外适配
- 确保
CALL_PHONE权限已完成运行时动态申请(Android 6.0+要求)。 - 部分国产厂商有后台管控,需将应用加入后台白名单或允许自启动权限。
- 确保
二、唤起/聚焦MainActivity的方法
若需触发闹钟时唤起应用主界面,需添加合适的Intent标记,且同样需注意后台启动限制:
public class MyAlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // 测试蜂鸣 ToneGenerator toneGenerator = new ToneGenerator(AudioManager.STREAM_MUSIC, 100); toneGenerator.startTone(ToneGenerator.TONE_CDMA_PIP, 100); // 唤起并聚焦MainActivity(应用已打开则前置) Intent mainIntent = new Intent(context, MainActivity.class); mainIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); // Android 8.0+建议通过前台服务启动,或先弹出通知再启动Activity context.startActivity(mainIntent); } }
内容的提问来源于stack exchange,提问作者Java Guy
相关产品推荐
相关产品推荐

