关于Android 11、12和13服务保活问题

这篇具有很好参考价值的文章主要介绍了关于Android 11、12和13服务保活问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

关于Android 11、12和13服务保活问题

物联网环境,为了解决不同厂商、不同设备、不同网络情况下使用顺畅,同时也考虑到节约成本,缩小应用体积的好处,我们需要一个服务应用一直存在系统中,保活它以提供服务给其他客户端调用。
开机自启动,通过广播通信,

必要权限

    <!--允许查看所有未启动的应用-->
    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
        tools:ignore="QueryAllPackagesPermission" />
    <!--// 添加接收开机广播的权限-->
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <!--前台服务-->
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>

开机自启动Service相关代码

import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.os.Build
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

/**
 * @date 2023/2/28
 * @email L2279833535@163.com
 * @author 小红妹
 * @package com.xxx.xxx.receiver
 * @describe 接收开机广播、开机自启动Service
 * @copyright
 */
class BootBroadcastReceiver : BroadcastReceiver() {
    private val ACTION_BOOT = "android.intent.action.BOOT_COMPLETED"
    override fun onReceive(context: Context?, intent: Intent?) {
        if (intent?.action == ACTION_BOOT) {
            GlobalScope.launch(Dispatchers.Main) {
                delay(20000L)
                val intent = Intent()
                intent.component =
                    ComponentName("com.xxx.xxx.end", "com.xxx.xxx.end.DeviceService")
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    context?.startForegroundService(intent)
                } else {
                    context?.startService(intent)
                }
            }
        }
    }

}
import android.app.*
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.graphics.Color
import android.os.Build
import android.os.IBinder
import android.util.Log
import androidx.core.app.NotificationCompat
import com.ccbft.pda.reader.RfidUHF
import com.krd.ricemachine.uits.ShareUtil
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

/**
 * @date 2023/3/16
 * @email L2279833535@163.com
 * @author 小红妹
 * @package com.xxx.xxx.end
 * @describe
 * @copyright
 */
class DeviceService : Service() {

    private lateinit var deviceBroadcastReceiver : DeviceBroadcastReceiver
    private lateinit var mContext: Context
    private val TAG = "DeviceService"
    /** 标记服务是否启动 */
    private var serviceIsLive = false
    /** 唯一前台通知ID */
    private val NOTIFICATION_ID = 1000

    override fun onCreate() {
        super.onCreate()
        mContext = this
        //前台显示服务
        // 获取服务通知
        val notification: Notification = createForegroundNotification()
        //将服务置于启动状态 ,NOTIFICATION_ID指的是创建的通知的ID
        startForeground(NOTIFICATION_ID, notification)
    }

    override fun onBind(p0: Intent?): IBinder? {
        return null
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        CoroutineScope(Dispatchers.Main).launch {
            //delay(1000L)//阻塞时间
            //receiverRegist()
            RfidUHF.initUHF()
            ShareUtil.putString("AES_key", intent?.getStringExtra("key"), mContext)
            Log.e(TAG, "onStartCommand: "+ intent?.getStringExtra("key"))
        }
        // 标记前台服务启动
        serviceIsLive = true
        return super.onStartCommand(intent, flags, startId)
    }

    private fun receiverRegist() {
        deviceBroadcastReceiver = DeviceBroadcastReceiver()
        val filter = IntentFilter()
        filter.addAction("deviceCall")
        registerReceiver(deviceBroadcastReceiver, filter)
    }


    /**
     * 创建前台服务通知
     */
    private fun createForegroundNotification(): Notification {
        val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager

        // 唯一的通知通道的id.
        val notificationChannelId = "notification_channel_id_01"

        // Android8.0以上的系统,新建消息通道
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            //用户可见的通道名称
            val channelName = "Foreground Service Notification"
            //通道的重要程度
            val importance = NotificationManager.IMPORTANCE_HIGH
            val notificationChannel =
                NotificationChannel(notificationChannelId, channelName, importance)
            notificationChannel.description = "Channel description"
            //LED灯
            notificationChannel.enableLights(true)
            notificationChannel.lightColor = Color.RED
            //震动
            notificationChannel.vibrationPattern = longArrayOf(0, 1000, 500, 1000)
            notificationChannel.enableVibration(true)
            notificationManager?.createNotificationChannel(notificationChannel)
        }
        val builder = NotificationCompat.Builder(this, notificationChannelId)
        //通知小图标
        builder.setSmallIcon(R.mipmap.ic_launcher)
        //通知标题
        builder.setContentTitle("AndroidServer")
        //通知内容
        builder.setContentText("AndroidServer服务正在运行中")
        //设定通知显示的时间
        builder.setWhen(System.currentTimeMillis())
        //设定启动的内容
        val activityIntent = Intent(this, MainActivity::class.java)
        val pendingIntent = PendingIntent.getActivity(
            this,
            1,
            activityIntent,
            PendingIntent.FLAG_IMMUTABLE
        ) /*FLAG_UPDATE_CURRENT*/
        builder.setContentIntent(pendingIntent)

        //创建通知并返回
        return builder.build()
    }

    override fun onDestroy() {
        //unregisterReceiver(deviceBroadcastReceiver)
        super.onDestroy()
        // 标记服务关闭
        serviceIsLive = false
        // 移除通知
        stopForeground(true)
    }

注意
1、Android 8.0后台运行服务需要开启前台显示服务
2、Android 8.0 不再允许后台进程直接通过startService方式去启动服务,改为startForegroundService方式启动。
对应错误提示如下

Context.startForegroundService() did not then call Service.startForeground(): 
ServiceRecord{24fafff u0 com.xxx.xxx.end/.DeviceService}

3、Android O 后台应用想启动服务调用:调用startForegroundService()后 切记调用startForeground(),这个时候会有一个Notification常驻,也就是上面说的1。
权限提示:

Permission Denial: startForeground from pid=2406, uid=10134 requires 
android.permission.FOREGROUND_SERVICE

4、Android 11以上启动服务不能只是这样简单的调用//context?.startService(Intent(context, DeviceService::class.java))
不然会报错,

Process: com.xuanyi.webserver, PID: 2455
java.lang.IllegalStateException: Not allowed to start service Intent { cmp=com.xxx.xxx/.service.WebService }: app is in background uid UidRecord{103aaa1 u0a138 CEM  idle change:cached procs:1 seq(0,0,0)}
	at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1715)
	at android.app.ContextImpl.startService(ContextImpl.java:1670)
	at android.content.ContextWrapper.startService(ContextWrapper.java:720)
	at android.content.ContextWrapper.startService(ContextWrapper.java:720)
	at com.xxx.xxx.receiver.BootBroadcastReceiver$onReceive$1.invokeSuspend(BootBroadcastReceiver.kt:26)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:749)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
	Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@e0016fc, Dispatchers.Default]

5、Android 12 四大组件含有< intent-filter >< /intent-filter >的需要添加android:exported=“true”,更多情况情况着这篇文章 Android 12适配安全组件导出设置android:exported 指定显式值”

6、Android 11引入了包可见性 ,要么添加QUERY_ALL_PACKAGES权限,要么这样写

<queries>
        //你要交互的service的包名
        <package android:name="com.XXX.XXX" />
        //...等等包名
</queries>

广播通信的前提,1.应用APP要启动过一次,2、要有至少有一个activity ,3、注册广播方式
这就是为什么我们需要服务的意思,首先需要开机自启动服务,这会我们可以在启动的服务中动态注册广播,测试静态注册也可以。
对了,广播的静态注册效果随着版本的升高,效果大打折扣,为了防止小人作弊,系统把君子和小人都设防了。

若是用户手动从后台杀掉应用程序,那么广播无法再次启动服务,哈哈哈哈哈哈,那就想办法让用户无法删除服务吧!文章来源地址https://www.toymoban.com/news/detail-405021.html

到了这里,关于关于Android 11、12和13服务保活问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android13关于获取外部存储文件的相关问题及解决方案记录

      Android的学习路上... 测试设备:vivo X90s 安卓版本: Android13 开发环境:AndroidStudio Flamingo SDK:33 最近我在Android13的环境下尝试写一个 文件选择器 ,以便日后的开发使用。但是我们知道,从Android13 (API33) 开始,外部存储权限发生了变化,要想读取外部存储文件,使用原来的权

    2024年01月15日
    浏览(59)
  • Android app保活(前台服务)

    国内厂商定制,除非厂商给app白名单,否则只能用户手动添加白名单(应用自启和后台运行),才能通过前台服务实现app保活。 这里介绍前台服务相关实现方式。 开启服务: 服务: 清单文件

    2024年02月09日
    浏览(40)
  • 关于安卓13中Android/data目录下的文件夹只能查看无法进行删改的问题

    因为升级了安卓13,然后有个app需要恢复数据,打算和以前一样直接删除Android/data下对应目录再添加,结果不行,以下是结合网上以及自己手机情况来做的一种解决方案。 准备: 待恢复app(包名com.test.ai) 其他app(包名com.other.ai,这个app当做临时变量就行,随便任意app,且知

    2024年02月09日
    浏览(72)
  • Android 11/12 app-lint 系统Update-API时Lint检查问题

    这种方式你可以其他博客也有 但是要每个类和方法都加上 @SuppressLint 太麻烦了 我才不要这样呢 1. 打开 frameworks/base/Android.bp 文件 2. 搜索找到这个字段 metalava_framework_docs_args 3. 然后在最后面添加   --api-lint-ignore-prefix xxxx 芜湖 成功啦

    2024年02月11日
    浏览(51)
  • 关于在Android 11系统手机上请求READ_PHONE_STATE权限的问题

    起因是因为bugly报错: 上网查了下,原来在Android11及以上机型上调用telephonyManager.getNetworkType()需要READ_PHONE_STATE权限,于是我就在应用启动时加上了申请该权限的代码,并且在调用getNetworkType()方法的地方加了判断,如果系统版本大于等于11并且没有被授予READ_PHONE_STATE权限,就

    2024年02月12日
    浏览(47)
  • MIUI14+安卓13 Root教程 小米10 小米11 小米12 小米13 红米

    1. 确保手机已完成 BL 解锁。这里来申请解锁 2. 手机下载并且安装Magisk 下载地址 3. 去下载当前版本刷机包 小米 10 (umi) 国行版 线刷、卡刷包 ​ 网页上ctrl+f 搜索 miui14,直接找到最新版,目前版本是: ​ V14.0.2.0.TJBCNXM MIUI14 13.0 ​ miui_UMI_V14.0.2.0.TJBCNXM_6d38dfc521_13.0.zip | 下载 4.把

    2023年04月16日
    浏览(57)
  • 【每日刷题】动态规划-代码随想录动规-11、12、13

    问题背景 : 有若干个物品对应各自的体积和价值,有一个容量确定的背包,有选择的将物品装进背包里,求可放进背包的最大价值。 思路: 定义dp数组: dp[i][j]的含义:从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。 dp[i][j]递推公式: 不放物品

    2024年02月22日
    浏览(49)
  • 高通 Android 12/13获取IMIE号

    1、由于我们工厂smt需要显示imei号,因此需要 2、查阅相关资料Android O(之后)Android 10之后进行限制  3、通过反射获取 imei号  4、通过 TelephonyManager 中getImei()方法获取 5、结果 获取imei号 如下图所示     6、到这里基本结束了,转载请注明出处,谢谢 7、记得添加系统权限 否则

    2024年02月11日
    浏览(40)
  • C Primer Plus(第六版)11.13 编程练习 第12题

    /* 编写一个程序,读取输入,直至读到EOF,报告读入的单词数、大写字母数、小写字母数、标点 符号数和数字字符数。使用ctype.h头文件中的函数。 */ //测试字符串  //ajskm,dl kdAj,.lfj sjkdl  sdk12lfj !.,fkdj.,.lssd.1a //(ajskm),(dl) (kdAj),.(lfj) (sjkdl)  (sdk)12(lfj) !.,(fkdj).,.(lssd).1(a) #includestdi

    2024年02月02日
    浏览(38)
  • 高通Android 12/13 默认应用程序授予权限

    1、一提到权限很多Android开发者都会想到 比如拨打电话 读取手机通讯录 定位 这些都是需要申请权限,Google Android 6.0之后(sdk 23) 需要app动态申请权限 或者权限组 2、我这里打个比方 比如需要在fm应用 默认打开mic权限  3、我们需要知道这个默认应用程序的包名 (例如 xxx.

    2024年02月01日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包