Android API34实现APP被杀后推送通知及解决autoCancel失效问题
Android API 34 后台保活与通知自动消失解决方案
核心解决要点
- 前台通知自动取消:前台服务的通知无法通过
autoCancel=true自动取消,需在通知点击事件中触发服务切换回静默保活通知,同时移除推送通知。 - API34后台保活优化:仅依赖
START_STICKY和onTaskRemoved重启服务在Android 12+中受限,需结合JobScheduler实现可靠重启。 - 权限适配:必须申请
POST_NOTIFICATIONS权限(API33+),并在运行时主动请求。
完整代码实现
1. 权限配置(AndroidManifest.xml)
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <!-- 可选:开机自启 --> <application ...> <service android:name=".PushKeepAliveService" android:foregroundServiceType="dataSync|remoteMessaging" <!-- API34需指定服务类型 --> android:exported="false" /> <service android:name=".JobRestartService" android:permission="android.permission.BIND_JOB_SERVICE" android:exported="true" /> <receiver android:name=".PushClickReceiver" android:exported="false" /> <receiver android:name=".BootCompletedReceiver" android:exported="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" /> </intent-filter> </receiver> </application>
2. 前台服务类(PushKeepAliveService.java)
import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.job.JobInfo; import android.app.job.JobScheduler; import android.content.ComponentName; import android.content.Intent; import android.os.Build; import android.os.IBinder; import android.util.Log; import androidx.annotation.Nullable; import androidx.core.app.NotificationCompat; public class PushKeepAliveService extends android.app.Service { private static final String TAG = "PushKeepAliveService"; private static final int FOREGROUND_ID = 1001; private static final String CHANNEL_ID = "push_keep_alive_channel"; private static final int JOB_ID = 2001; public static final String ACTION_SHOW_PUSH = "ACTION_SHOW_PUSH"; public static final String ACTION_RESET_FOREGROUND = "ACTION_RESET_FOREGROUND"; @Override public void onCreate() { super.onCreate(); createNotificationChannel(); // 启动前台,显示静默保活通知 startForeground(FOREGROUND_ID, createSilentNotification()); } @Override public int onStartCommand(Intent intent, int flags, int startId) { if (intent != null) { switch (intent.getAction()) { case ACTION_SHOW_PUSH: // 处理服务器推送请求,显示通知 String requestContent = intent.getStringExtra("REQUEST_CONTENT"); showPushNotification(requestContent); break; case ACTION_RESET_FOREGROUND: // 重置为静默保活通知 stopForeground(STOP_FOREGROUND_REMOVE); startForeground(FOREGROUND_ID, createSilentNotification()); break; } } return START_STICKY; } @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void onTaskRemoved(Intent rootIntent) { super.onTaskRemoved(rootIntent); // 用JobScheduler重启服务,规避后台启动限制 scheduleJobRestart(); stopSelf(); } @Override public void onDestroy() { super.onDestroy(); Log.d(TAG, "Service destroyed"); } private void createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "推送保活通道", NotificationManager.IMPORTANCE_LOW); channel.setSound(null, null); channel.enableVibration(false); NotificationManager manager = getSystemService(NotificationManager.class); if (manager != null) { manager.createNotificationChannel(channel); } } } // 创建静默保活通知(低优先级,无提示音) private Notification createSilentNotification() { Intent intent = new Intent(this, MainActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); return new NotificationCompat.Builder(this, CHANNEL_ID) .setSmallIcon(R.drawable.ic_notification) // 替换为你的应用图标 .setContentTitle("应用运行中") .setContentText("后台保持推送接收") .setPriority(NotificationCompat.PRIORITY_LOW) .setContentIntent(pendingIntent) .setOngoing(true) // 防止用户手动清除 .build(); } // 显示新请求推送通知,点击后自动取消 private void showPushNotification(String content) { Intent clickIntent = new Intent(this, PushClickReceiver.class); PendingIntent pendingClickIntent = PendingIntent.getBroadcast(this, 1, clickIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); Notification pushNotification = new NotificationCompat.Builder(this, CHANNEL_ID) .setSmallIcon(R.drawable.ic_notification) .setContentTitle("新请求到来") .setContentText(content) .setPriority(NotificationCompat.PRIORITY_HIGH) .setContentIntent(pendingClickIntent) .setAutoCancel(true) // 点击后自动取消通知 .build(); // 更新前台通知为推送通知 startForeground(FOREGROUND_ID, pushNotification); } // 调度Job重启服务 private void scheduleJobRestart() { JobScheduler jobScheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE); ComponentName componentName = new ComponentName(this, JobRestartService.class); JobInfo jobInfo = new JobInfo.Builder(JOB_ID, componentName) .setMinimumLatency(1000) // 1秒后执行重启 .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) .setPersisted(true) // 设备重启后仍生效 .build(); jobScheduler.schedule(jobInfo); } }
3. 通知点击接收器(PushClickReceiver.java)
import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Build; public class PushClickReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // 通知服务切换回静默保活状态 Intent serviceIntent = new Intent(context, PushKeepAliveService.class); serviceIntent.setAction(PushKeepAliveService.ACTION_RESET_FOREGROUND); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { context.startForegroundService(serviceIntent); } else { context.startService(serviceIntent); } // 打开主页面 Intent activityIntent = new Intent(context, MainActivity.class); activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(activityIntent); } }
4. JobScheduler重启服务(JobRestartService.java)
import android.app.job.JobParameters; import android.app.job.JobService; import android.content.Intent; import android.os.Build; public class JobRestartService extends JobService { @Override public boolean onStartJob(JobParameters params) { // 重启前台服务 Intent intent = new Intent(this, PushKeepAliveService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(intent); } else { startService(intent); } jobFinished(params, false); return false; } @Override public boolean onStopJob(JobParameters params) { return false; } }
5. MainActivity启动服务与权限请求
import android.Manifest; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; public class MainActivity extends AppCompatActivity { private static final int REQUEST_POST_NOTIFICATIONS = 100; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 请求通知权限(API33+) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.POST_NOTIFICATIONS}, REQUEST_POST_NOTIFICATIONS); } else { startKeepAliveService(); } } else { startKeepAliveService(); } } private void startKeepAliveService() { Intent intent = new Intent(this, PushKeepAliveService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(intent); } else { startService(intent); } } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_POST_NOTIFICATIONS) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { startKeepAliveService(); } } } }
6. 开机自启接收器(可选)
import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Build; public class BootCompletedReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction()) || Intent.ACTION_LOCKED_BOOT_COMPLETED.equals(intent.getAction())) { Intent serviceIntent = new Intent(context, PushKeepAliveService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { context.startForegroundService(serviceIntent); } else { context.startService(serviceIntent); } } } }
关键说明
- 通知逻辑:平时用静默低优先级通知保活服务,收到推送时替换为高优先级可点击通知,用户点击后自动切回静默通知,既满足保活要求,又解决
autoCancel无效问题。 - JobScheduler重启:Android 12+限制后台直接启动服务,
JobScheduler可绕过该限制,确保应用从近期列表移除后服务能可靠重启。 - 权限适配:API33+必须申请
POST_NOTIFICATIONS权限,否则无法显示通知,导致前台服务启动失败。
内容的提问来源于stack exchange,提问作者Nishant Singh
相关产品推荐
相关产品推荐

