Developer技术博客 DevEngineer:林建有

Android 前台服务和通知相关排查


前台服务和通知相关排查

VRecorder涉及到的前台服务

主版本VRecorder targetSDK已经是28(Android P,API 9)

  • FloatWindowService.java

    应用打开后,创建悬浮球依赖的前台服务,同时会在通知栏创建前台服务通知。

      /**
       * 没有开始录制则会开启foreground通知栏
       */
      private void startForegroundServiceAndNotification() {
          if (!Prefs.getIsRecordStart(getApplicationContext())) {
              StartRecordNotifications notifications = new StartRecordNotifications(getApplicationContext());
              if (Build.MANUFACTURER.equals("OPPO") || Build.BRAND.equalsIgnoreCase("Xiaomi")) {
                  //判断是否是oppo手机
                  //判断是否是小米手机
                  startForeground(StartRecordNotifications.NOTIFICATION_ID, notifications.getXiaoMiNotification());
              } else {
                  startForeground(StartRecordNotifications.NOTIFICATION_ID, notifications.getNormalNotification());
              }
          }
      }
    

    因为是target 28,所有Manifest里配置了权限前台服务权限

      <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    
  • StartRecorderService.java

    该服务是录制时打开的后台服务,在Android P以下没有独立打开通知,不属于前台服务。

退出APP主动关闭服务和通知

@Override
public int onStartCommand(final Intent intent, int flags, int startId) {
    if (intent != null) {
       
        if (intent.getBooleanExtra(VIDEO_EXIT_APP, false)) {
            //退出录制
            NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            if (manager != null) {
                manager.cancelAll();//关闭所有通知
            }
   ...
       //关闭所有APP打开的任务
        ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
            if (activityManager != null) {
                List<ActivityManager.AppTask> appTasks = activityManager.getAppTasks();
                for (int i = 0; i < appTasks.size(); i++) {
                    appTasks.get(i).finishAndRemoveTask();
                }
            }
            //关闭自身服务
            stopSelf();
            return START_NOT_STICKY;
        }

通知栏的创建涉及到的channel ID和channel Name

  • StartRecordNotifications.java 录制通知栏专属类

创建该类的时候就一并创建通知渠道id和渠道名称

 public StartRecordNotifications(Context context) {
        this.context = context;
        createNotificationChannel();
    }

创建渠道id和名称

public static final String RECORD_CHANNEL_ID               = "record_channel_id";
public static final String RECORD_CHANNEL                  = "record channel";
public static final String RECORD_NOTIFICATION_DESCRIPTION = "record notification";

private void createNotificationChannel() {
        mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        int importance = NotificationManager.IMPORTANCE_LOW;
        NotificationChannel channel = new NotificationChannel(RECORD_CHANNEL_ID, RECORD_CHANNEL, importance);
        channel.setDescription(RECORD_NOTIFICATION_DESCRIPTION);
        // Register the channel with the system; you can't change the importance
        // or other notification behaviors after this
        mNotificationManager.createNotificationChannel(channel);
    }
        mBuilder = new NotificationCompat.Builder(context.getApplicationContext(), RECORD_CHANNEL_ID);
        //创建通知:
        mBuilder.setOngoing(true)//设置是否常驻,true为常驻
     .setContentTitle(context.getString(R.string.string_notification_start_recording))
//                .setStyle(new NotificationCompat.DecoratedCustomViewStyle())
                .setSmallIcon(R.mipmap.ic_launcher_white)//设置小图标
                .setCategory(NotificationCompat.CATEGORY_EVENT)
                .setPriority(Notification.PRIORITY_LOW)//设置优先级
                .setWhen(System.currentTimeMillis());//设置展示时间
}

Target 29(Android 10 )前台服务的升级

前台服务在Manifest里的升级增加android:foregroundServiceType属性

依然需要前台服务权限声明

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<service
    android:name=".windowmanager.StartRecorderService"
    android:enabled="true"
    android:foregroundServiceType="mediaProjection"
    android:exported="false" />
<service 
    android:name=".windowmanager.FloatWindowService"
    android:foregroundServiceType="mediaProjection"/>

代码里的打开前台服务升级

开启前台服务时需要添加参数foregroundServiceType使用如下方法

startForeground(int id,Notification notification,int foregroundServiceType)

VRecorder使用案例:在FloatWindowService.java和StartRecorderService.java里都需要调用

public static void startForegroundServiceAndNotification(Service service) {
		...
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {//Android 10
          service.startForeground(StartRecordNotificationUtils.NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION);
        } else {//非Android10
          service.startForeground(StartRecordNotificationUtils.NOTIFICATION_ID, notification);
        }
    }
}

代码里关闭服务升级

FloatWindowService.java里退出APP时:

@Override
public int onStartCommand(final Intent intent, int flags, int startId) {
    if (intent == null) return START_REDELIVER_INTENT;
    if (intent.getBooleanExtra(VIDEO_EXIT_APP, false)) {//退出录制
        Prefs.setIsRecordStart(getApplicationContext(), false);
        MyWindowManager.releaseFloatViews(this);
        finishAllTaskAndActivity();//关闭所有activity task
        stopRecorderServices();//关闭录制服务
        stopForeground(true);//设置true,移除通知
        NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        if (manager != null) {
            manager.cancelAll();
        }
        stopSelf();
        return START_NOT_STICKY;
    }
    
    /**
     *关闭录制服务
     */
    private void stopRecorderServices() {
        Intent name = new Intent(this, StartRecorderService.class);
        name.putExtra(VIDEO_EXIT_APP, true);
        stopService(name);
    }

Similar Posts

上一篇 涂鸦功能

Comments