• Android前台服务和通知


    前台服务

    Android 13及以上系统需要动态获取通知权限。

    1. //android 13及以上系统动态获取通知权限
    2. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    3. checkPostNotificationPermission();
    4. }
    1. private void checkPostNotificationPermission() {
    2. if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.POST_NOTIFICATIONS)
    3. != PackageManager.PERMISSION_GRANTED) {
    4. ActivityCompat.requestPermissions((Activity) this, new String[]{
    5. Manifest.permission.POST_NOTIFICATIONS}, 200);
    6. } else if (manager != null) {
    7. //通知ID设置(您可以使用任何您想要的ID,相同ID通知只会显示一个)。
    8. manager.notify(2, builder.build());
    9. }
    10. }
    11. @Override
    12. public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    13. super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    14. if (requestCode == 200) {
    15. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
    16. //允许了通知权限
    17. } else {
    18. Toast.makeText(this, "您拒绝了通知权限", Toast.LENGTH_SHORT).show();
    19. }
    20. }
    21. }

    别忘记添加通知权限

    1. <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

    开启前台服务需要添加前台服务权限

    1. <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

    通知震动需要添加震动权限

    1. <uses-permission android:name="android.permission.VIBRATE" />

    前台服务代码

    1. import android.app.NotificationChannel;
    2. import android.app.NotificationManager;
    3. import android.app.PendingIntent;
    4. import android.app.Service;
    5. import android.content.Intent;
    6. import android.graphics.Color;
    7. import android.net.Uri;
    8. import android.os.Build;
    9. import android.os.IBinder;
    10. import androidx.annotation.Nullable;
    11. import androidx.core.app.NotificationCompat;
    12. import com.example.javatest.MainActivity;
    13. import com.example.javatest.R;
    14. /**
    15. * created by cwj on 2023-10-19
    16. * Description: 前台服务
    17. */
    18. public class ForegroundService extends Service {
    19. @Override
    20. public void onCreate() {
    21. super.onCreate();
    22. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    23. CharSequence name = getString(R.string.app_name);
    24. int importance = NotificationManager.IMPORTANCE_DEFAULT;
    25. NotificationChannel channel = new NotificationChannel("CHANNEL_ID", name, importance);
    26. channel.setDescription("前台服务守护进程");
    27. NotificationManager notificationManager = getSystemService(NotificationManager.class);
    28. notificationManager.createNotificationChannel(channel);
    29. }
    30. //设置服务跳转
    31. Intent intent = new Intent(this, MainActivity.class);
    32. intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
    33. PendingIntent pendingIntent = PendingIntent.getActivity(this, 1, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE);
    34. NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "CHANNEL_ID")
    35. // 设置通知的小图标。
    36. .setSmallIcon(R.mipmap.ic_launcher)
    37. //设置通知的标题。
    38. .setContentTitle(getString(R.string.app_name))
    39. //设置通知的内容
    40. .setContentText("进程守护中")
    41. //设置通知的优先级。
    42. .setPriority(NotificationCompat.PRIORITY_DEFAULT)
    43. //震动模式的通知在Android O及以上。
    44. .setVibrate(new long[]{0, 1000, 500, 1000})
    45. //在Android O及以上的系统上使用LED光色和微信号。
    46. .setLights(Color.RED, 1000, 1000)
    47. //设置Android O及以上版本的通知声音。
    48. .setSound(Uri.parse("android.resource://" + this.getPackageName() + "/raw/notification_sound"))
    49. //如果需要,在Android O及以上版本设置较大的通知标题。
    50. // .setLargeTitle("Large Title Text")
    51. //如果需要,在Android O及以上版本设置通知的子文本。
    52. // .setSubText("Sub Text")
    53. //如果需要,在Android O及以上版本设置大字体通知。
    54. // .setStyle(new NotificationCompat.BigTextStyle().bigText("Big Text"))
    55. //如果需要,在Android O及以上版本设置通知摘要文本(当有多个具有相同优先级的通知时显示摘要文本)。
    56. // .setSummaryText("Summary Text")
    57. //如果需要,在通知中添加动作按钮(可用于启动活动或发送广播)。
    58. // .addAction(R.drawable.ic_action, "Action Title", PendingIntent)
    59. //设置可点击跳转
    60. .setContentIntent(pendingIntent);
    61. // 将通知设置为前台服务
    62. startForeground(1, builder.build());
    63. }
    64. @Override
    65. public int onStartCommand(Intent intent, int flags, int startId) {
    66. // 在这里执行需要在前台运行的任务
    67. // 返回START_STICKY表示服务在被杀死后会自动重启
    68. return START_STICKY;
    69. }
    70. @Nullable
    71. @Override
    72. public IBinder onBind(Intent intent) {
    73. return null;
    74. }
    75. @Override
    76. public void onDestroy() {
    77. super.onDestroy();
    78. // 停止前台服务
    79. stopForeground(true);
    80. stopSelf();
    81. }
    82. }

    application中添加服务

    1. <service
    2. android:name=".service.ForegroundService"
    3. android:enabled="true"
    4. android:exported="false" />

    activity中启动服务

    1. Intent intent = new Intent(this, ForegroundService.class);
    2. // Android 8.0使用startForegroundService在前台启动新服务
    3. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    4. startForegroundService(intent);
    5. } else {
    6. startService(intent);

    创建通知

     模拟发送通知

    1. binding.iv.setOnClickListener(v ->
    2. showNotification(getString(R.string.app_name), dateToString(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss") + "您收到一条消息")
    3. );

    创建通知及通知点击取消通知

    1. private NotificationCompat.Builder builder;
    2. private NotificationManagerCompat manager;
    3. private void showNotification(String title, String content) {
    4. // 创建通知频道,如果用户没有创建,则会自动创建。
    5. String CHANNEL_ID = "message";
    6. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    7. if (getSystemService(NotificationManager.class).getNotificationChannel(CHANNEL_ID) == null) {
    8. NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "消息", NotificationManager.IMPORTANCE_DEFAULT);
    9. //通知的振动模式。
    10. channel.setVibrationPattern(new long[]{0, 1000, 500, 1000});
    11. //为通知通道启用振动。
    12. channel.enableVibration(true);
    13. //设置通道的颜色。
    14. channel.setLightColor(Color.RED);
    15. //设置通道的锁屏可见性。
    16. channel.setLockscreenVisibility(NotificationCompat.VISIBILITY_PUBLIC);
    17. getSystemService(NotificationManager.class).createNotificationChannel(channel);
    18. }
    19. }
    20. //设置服务跳转
    21. Intent intent = new Intent(this, MainActivity.class);
    22. intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
    23. PendingIntent pendingIntent = PendingIntent.getActivity(this, 2, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE);
    24. // 创建并分发通知。
    25. builder = new NotificationCompat.Builder(this, CHANNEL_ID)
    26. // 设置通知的小图标。
    27. .setSmallIcon(R.mipmap.ic_launcher)
    28. //设置通知的标题。
    29. .setContentTitle(title)
    30. //设置通知的内容
    31. .setContentText(content)
    32. //设置通知的优先级。
    33. .setPriority(NotificationCompat.PRIORITY_DEFAULT)
    34. //震动模式的通知在Android O及以上。
    35. .setVibrate(new long[]{0, 1000, 500, 1000})
    36. //在Android O及以上的系统上使用LED光色和微信号。
    37. .setLights(Color.RED, 1000, 1000)
    38. //设置Android O及以上版本的通知声音。
    39. .setSound(Uri.parse("android.resource://" + this.getPackageName() + "/raw/notification_sound"))
    40. //如果需要,在Android O及以上版本设置较大的通知标题。
    41. // .setLargeTitle("Large Title Text")
    42. //如果需要,在Android O及以上版本设置通知的子文本。
    43. // .setSubText("Sub Text")
    44. //如果需要,在Android O及以上版本设置大字体通知。
    45. // .setStyle(new NotificationCompat.BigTextStyle().bigText("Big Text"))
    46. //如果需要,在Android O及以上版本设置通知摘要文本(当有多个具有相同优先级的通知时显示摘要文本)。
    47. // .setSummaryText("Summary Text")
    48. //如果需要,在通知中添加动作按钮(可用于启动活动或发送广播)。
    49. // .addAction(R.drawable.ic_action, "Action Title", PendingIntent)
    50. //设置可点击跳转
    51. .setContentIntent(pendingIntent)
    52. //开启点按通知后自动移除通知
    53. .setAutoCancel(true);
    54. manager = NotificationManagerCompat.from(this);
    55. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    56. checkPostNotificationPermission();
    57. } else {
    58. // 在 Android 10 或更早版本中,不需要请求此权限。
    59. //ID要和前台服务ID区分开,相同ID只能显示一条通知。
    60. manager.notify(2, builder.build());
    61. }

    activity完整代码

    1. import androidx.annotation.NonNull;
    2. import androidx.appcompat.app.AppCompatActivity;
    3. import androidx.core.app.ActivityCompat;
    4. import androidx.core.app.NotificationCompat;
    5. import androidx.core.app.NotificationManagerCompat;
    6. import android.Manifest;
    7. import android.app.Activity;
    8. import android.app.NotificationChannel;
    9. import android.app.NotificationManager;
    10. import android.app.PendingIntent;
    11. import android.content.Intent;
    12. import android.content.pm.PackageManager;
    13. import android.graphics.Color;
    14. import android.net.Uri;
    15. import android.os.Build;
    16. import android.os.Bundle;
    17. import android.widget.Toast;
    18. import com.example.javatest.databinding.ActivityMainBinding;
    19. import com.example.javatest.service.ForegroundService;
    20. import java.text.SimpleDateFormat;
    21. import java.util.Date;
    22. public class MainActivity extends AppCompatActivity {
    23. private ActivityMainBinding binding;
    24. @Override
    25. protected void onCreate(Bundle savedInstanceState) {
    26. super.onCreate(savedInstanceState);
    27. binding = ActivityMainBinding.inflate(getLayoutInflater());
    28. setContentView(binding.getRoot());
    29. initView();
    30. initData();
    31. }
    32. private void initView() {
    33. //android 13及以上系统动态获取通知权限
    34. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    35. checkPostNotificationPermission();
    36. }
    37. Intent intent = new Intent(this, ForegroundService.class);
    38. // Android 8.0使用startForegroundService在前台启动新服务
    39. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    40. startForegroundService(intent);
    41. } else {
    42. startService(intent);
    43. }
    44. }
    45. private void initData() {
    46. binding.iv.setOnClickListener(v ->
    47. showNotification(getString(R.string.app_name), dateToString(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss") + "您收到一条消息")
    48. );
    49. }
    50. private String dateToString(long time, String format) {
    51. Date date = new Date(time);
    52. SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
    53. return simpleDateFormat.format(date);
    54. }
    55. private NotificationCompat.Builder builder;
    56. private NotificationManagerCompat manager;
    57. private void showNotification(String title, String content) {
    58. // 创建通知频道,如果用户没有创建,则会自动创建。
    59. String CHANNEL_ID = "message";
    60. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    61. if (getSystemService(NotificationManager.class).getNotificationChannel(CHANNEL_ID) == null) {
    62. NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "消息", NotificationManager.IMPORTANCE_DEFAULT);
    63. //通知的振动模式。
    64. channel.setVibrationPattern(new long[]{0, 1000, 500, 1000});
    65. //为通知通道启用振动。
    66. channel.enableVibration(true);
    67. //设置通道的颜色。
    68. channel.setLightColor(Color.RED);
    69. //设置通道的锁屏可见性。
    70. channel.setLockscreenVisibility(NotificationCompat.VISIBILITY_PUBLIC);
    71. getSystemService(NotificationManager.class).createNotificationChannel(channel);
    72. }
    73. }
    74. //设置服务跳转
    75. Intent intent = new Intent(this, MainActivity.class);
    76. intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
    77. PendingIntent pendingIntent = PendingIntent.getActivity(this, 2, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE);
    78. // 创建并分发通知。
    79. builder = new NotificationCompat.Builder(this, CHANNEL_ID)
    80. // 设置通知的小图标。
    81. .setSmallIcon(R.mipmap.ic_launcher)
    82. //设置通知的标题。
    83. .setContentTitle(title)
    84. //设置通知的内容
    85. .setContentText(content)
    86. //设置通知的优先级。
    87. .setPriority(NotificationCompat.PRIORITY_DEFAULT)
    88. //震动模式的通知在Android O及以上。
    89. .setVibrate(new long[]{0, 1000, 500, 1000})
    90. //在Android O及以上的系统上使用LED光色和微信号。
    91. .setLights(Color.RED, 1000, 1000)
    92. //设置Android O及以上版本的通知声音。
    93. .setSound(Uri.parse("android.resource://" + this.getPackageName() + "/raw/notification_sound"))
    94. //如果需要,在Android O及以上版本设置较大的通知标题。
    95. // .setLargeTitle("Large Title Text")
    96. //如果需要,在Android O及以上版本设置通知的子文本。
    97. // .setSubText("Sub Text")
    98. //如果需要,在Android O及以上版本设置大字体通知。
    99. // .setStyle(new NotificationCompat.BigTextStyle().bigText("Big Text"))
    100. //如果需要,在Android O及以上版本设置通知摘要文本(当有多个具有相同优先级的通知时显示摘要文本)。
    101. // .setSummaryText("Summary Text")
    102. //如果需要,在通知中添加动作按钮(可用于启动活动或发送广播)。
    103. // .addAction(R.drawable.ic_action, "Action Title", PendingIntent)
    104. //设置可点击跳转
    105. .setContentIntent(pendingIntent)
    106. //开启点按通知后自动移除通知
    107. .setAutoCancel(true);
    108. manager = NotificationManagerCompat.from(this);
    109. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    110. checkPostNotificationPermission();
    111. } else {
    112. // 在 Android 10 或更早版本中,不需要请求此权限。
    113. //显示ID为1的通知(您可以使用任何您想要的ID)。
    114. manager.notify(2, builder.build());
    115. }
    116. }
    117. private void checkPostNotificationPermission() {
    118. if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.POST_NOTIFICATIONS)
    119. != PackageManager.PERMISSION_GRANTED) {
    120. ActivityCompat.requestPermissions((Activity) this, new String[]{
    121. Manifest.permission.POST_NOTIFICATIONS}, 200);
    122. } else if (manager != null) {
    123. //显示ID为1的通知(您可以使用任何您想要的ID)。
    124. manager.notify(2, builder.build());
    125. }
    126. }
    127. @Override
    128. public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    129. super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    130. if (requestCode == 200) {
    131. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
    132. //允许了通知权限
    133. } else {
    134. Toast.makeText(this, "您拒绝了通知权限", Toast.LENGTH_SHORT).show();
    135. }
    136. }
    137. }
    138. }

    完整配置文件AndroidManifest.xml

    1. "1.0" encoding="utf-8"?>
    2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    3. xmlns:tools="http://schemas.android.com/tools">
    4. <uses-permission android:name="android.permission.INTERNET" />
    5. <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    6. <uses-permission android:name="android.permission.VIBRATE" />
    7. <uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
    8. <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
    9. <application
    10. android:allowBackup="true"
    11. android:dataExtractionRules="@xml/data_extraction_rules"
    12. android:fullBackupContent="@xml/backup_rules"
    13. android:icon="@mipmap/ic_launcher"
    14. android:label="@string/app_name"
    15. android:roundIcon="@mipmap/ic_launcher_round"
    16. android:supportsRtl="true"
    17. android:theme="@style/Theme.JavaTest"
    18. tools:targetApi="31">
    19. <activity
    20. android:name=".MainActivity"
    21. android:exported="true">
    22. <intent-filter>
    23. <action android:name="android.intent.action.MAIN" />
    24. <category android:name="android.intent.category.LAUNCHER" />
    25. intent-filter>
    26. activity>
    27. <service
    28. android:name=".service.ForegroundService"
    29. android:enabled="true"
    30. android:exported="false" />
    31. application>
    32. manifest>

    build.gradle.kts文件中添加viewBinding支持

    1. buildFeatures{
    2. viewBinding = true
    3. }

  • 相关阅读:
    TypeScript学习日志-第二十四天(webpack构建ts+vue3)
    Docker实践:使用Docker搭建个人开发环境
    SSM+MySQL+JSP教务管理系统设计与实现(附源码下载地址)
    自然语言处理NLP:一文了解NLP自然语言处理技术,NLP在生活中的应用,图导加深了解,NLP语料库,NLP开源工具
    【Harmony OS】【ArkUI】ets开发 基础页面布局与数据连接
    SecureCRT 9.4.2 for Mac
    SpringAMQP
    机器学习笔记之概率图模型(十)因子图
    Tecplot绘制三维彩色流线
    TypeScript接口——interface
  • 原文地址:https://blog.csdn.net/juer2017/article/details/133946585