Android14新特性 开启前台service服务

1. Android14新特性

1.1. 场景

**  在Android14(targetSDK=34)系统手机开启前台service服务崩溃**

javascript 复制代码
ATAL EXCEPTION: main
                 Process: com.inspur.lbrd, PID: 15634
                 java.lang.RuntimeException: Unable to create service com.inspur.lbrd.service.KeepAliveService: android.app.MissingForegroundServiceTypeException: Starting FGS without a type  callerApp=ProcessRecord{957facf 15634:com.inspur.lbrd/u0a352} targetSDK=34
                 	at android.app.ActivityThread.handleCreateService(ActivityThread.java:5182)
                 	at android.app.ActivityThread.-$$Nest$mhandleCreateService(Unknown Source:0)
                 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2638)
                 	at android.os.Handler.dispatchMessage(Handler.java:108)
                 	at android.os.Looper.loopOnce(Looper.java:226)
                 	at android.os.Looper.loop(Looper.java:328)
                 	at android.app.ActivityThread.main(ActivityThread.java:9128)
                 	at java.lang.reflect.Method.invoke(Native Method)
                 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:586)
                 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
                 Caused by: android.app.MissingForegroundServiceTypeException: Starting FGS without a type  callerApp=ProcessRecord{957facf 15634:com.inspur.lbrd/u0a352} targetSDK=34
                 	at android.app.MissingForegroundServiceTypeException$1.createFromParcel(MissingForegroundServiceTypeException.java:53)
                 	at android.app.MissingForegroundServiceTypeException$1.createFromParcel(MissingForegroundServiceTypeException.java:49)
                 	at android.os.Parcel.readParcelableInternal(Parcel.java:4884)
                 	at android.os.Parcel.readParcelable(Parcel.java:4866)
                 	at android.os.Parcel.createExceptionOrNull(Parcel.java:3066)
                 	at android.os.Parcel.createException(Parcel.java:3055)
                 	at android.os.Parcel.readException(Parcel.java:3038)
                 	at android.os.Parcel.readException(Parcel.java:2980)
                 	at android.app.IActivityManager$Stub$Proxy.setServiceForeground(IActivityManager.java:7415)
                 	at android.app.Service.startForeground(Service.java:775)
                 	at com.inspur.lbrd.service.KeepAliveService.setForeground(SourceFile:118)
                 	at com.inspur.lbrd.service.KeepAliveService.onCreate(SourceFile:32)
                 	at android.app.ActivityThread.handleCreateService(ActivityThread.java:5169)
                 	at android.app.ActivityThread.-$$Nest$mhandleCreateService(Unknown Source:0) 
                 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2638) 
                 	at android.os.Handler.dispatchMessage(Handler.java:108) 
                 	at android.os.Looper.loopOnce(Looper.java:226) 
                 	at android.os.Looper.loop(Looper.java:328) 
                 	at android.app.ActivityThread.main(ActivityThread.java:9128) 
                 	at java.lang.reflect.Method.invoke(Native Method) 
                 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:586) 
                 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099) 

1.2. 解决方案

1.2.1. 在清单文件AndroidManifest.xml添加权限和配置

javascript 复制代码
 <!-- android14前台常住服务权限-->
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
javascript 复制代码
  <service
      android:name=".service.KeepAliveService"
      android:foregroundServiceType="location" />

1.2.2. service服务

javascript 复制代码
public class KeepAliveService extends Service {
    private final String TAG = "szyj_GridTraceS-";

    public KeepAliveService() {
    }
    @Override
    public void onCreate() {
        super.onCreate();
        // 添加常驻通知栏
        setForeground();
       // startXcService();
    }
    private void startXcService() {
        try {
            String patrolStatus = SpUtil.getInstance(this).getString(
                    GridTraceConstant.SP_PATROL_STATUS,
                    GridTraceConstant.SP_PATROL_STATUS_FALSE);
            //巡查服务已开启
            if (TextUtils.equals(patrolStatus, GridTraceConstant.SP_PATROL_STATUS_TRUE)) {
                if (!ServiceUtil.isServiceRunning(this, GridTraceService.class.getName())) {
                    startService(new Intent(this, GridTraceService.class));
                }
            } else {//未开启巡查服务
                if (ServiceUtil.isServiceRunning(this, GridTraceService.class.getName())) {
                    stopService(new Intent(this, GridTraceService.class));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        //可将onStartCommand() 方法的返回值设为 START_STICKY或START_REDELIVER_INTENT ,
        //该值表示服务在内存资源紧张时被杀死后,在内存资源足够时再恢复。
        //也可将Service设置为前台服务,这样就有比较高的优先级,在内存资源紧张时也不会被杀掉。
        return START_STICKY;
        //return super.onStartCommand(intent, flags, startId);
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        // 删除图标
        stopForeground(true);
    }

    @Override
    public IBinder onBind(Intent intent) {
        throw new UnsupportedOperationException("Not yet implemented");
    }
    /**
     * 添加常驻通知栏
     */
    private void setForeground() {
        NotificationManager notificationManager = (NotificationManager) getSystemService
                (Context.NOTIFICATION_SERVICE);
        String notificationId = "serviceid";
        String notificationName = "servicename";
        int noticeId = 2;
        Notification.Builder builder = new Notification.Builder(this);
        //创建NotificationChannel
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(notificationId,
                    notificationName, NotificationManager.IMPORTANCE_HIGH);
            channel.enableLights(true);//设置高亮(选填)
            channel.setShowBadge(true);//设置角标(选填)
            //设置锁屏可见(选填)
            channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
            notificationManager.createNotificationChannel(channel);
            builder.setChannelId(notificationId);
        }
        Intent intent = new Intent(KeepAliveService.this, MainActivity.class);
        PendingIntent pendingIntent;
        //Android12
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
            pendingIntent = PendingIntent.getActivity(this,
                    123, intent, PendingIntent.FLAG_IMMUTABLE);
        } else {
            pendingIntent = PendingIntent.getActivity(this,
                    123, intent, PendingIntent.FLAG_ONE_SHOT
                            | PendingIntent.FLAG_MUTABLE);
        }
        builder.setSmallIcon(R.mipmap.icon_app)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(),
                        R.mipmap.icon_app))
                .setContentTitle(getString(R.string.app_name))//选填
                .setContentText(getString(R.string.app_name))//选填
                .setWhen(System.currentTimeMillis())
                .setContentIntent(pendingIntent);
        Notification notification = builder.build();
        startForeground(noticeId, notification);
    }
}

1.2.2. 启动service服务

javascript 复制代码
  if (!ServiceUtil.isServiceRunning(this, KeepAliveService.class.getName())) {
            startService(new Intent(this, KeepAliveService.class));
        }

&emsp;&emsp;判断服务是否开启

javascript 复制代码
public class ServiceUtil {
    /**
     * @param context
     * @param className service后台服务名称
     * @return
     * @desc 查询service是否在运行
     */
    public static boolean isServiceRunning(Context context, String className) {
        ActivityManager activityManager = (ActivityManager) context
                .getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningServiceInfo> serviceList = activityManager
                .getRunningServices(Integer.MAX_VALUE);

        if (!(serviceList.size() > 0)) {
            return false;
        }

        for (int i = 0; i < serviceList.size(); i++) {
            ActivityManager.RunningServiceInfo serviceInfo = serviceList.get(i);
            ComponentName serviceName = serviceInfo.service;

            if (serviceName.getClassName().equals(className)) {
                return true;
            }
        }
        return false;
    }
}
相关推荐
还鮟2 小时前
CTF Web的数组巧用
android
小蜜蜂嗡嗡4 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi004 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体
zhangphil6 小时前
Android理解onTrimMemory中ComponentCallbacks2的内存警戒水位线值
android
你过来啊你6 小时前
Android View的绘制原理详解
android
移动开发者1号9 小时前
使用 Android App Bundle 极致压缩应用体积
android·kotlin
移动开发者1号9 小时前
构建高可用线上性能监控体系:从原理到实战
android·kotlin
ii_best14 小时前
按键精灵支持安卓14、15系统,兼容64位环境开发辅助工具
android
美狐美颜sdk14 小时前
跨平台直播美颜SDK集成实录:Android/iOS如何适配贴纸功能
android·人工智能·ios·架构·音视频·美颜sdk·第三方美颜sdk
恋猫de小郭18 小时前
Meta 宣布加入 Kotlin 基金会,将为 Kotlin 和 Android 生态提供全新支持
android·开发语言·ios·kotlin