我有一个通过FCM数据消息触发来电的应用程序(优先级:高,没有通知有效载荷)。当app处于前台或后台时,app接收呼叫。对于上述情况,在锁定屏幕中接收通知(来电)。
但由于某种原因,当关闭应用程序或从多任务托盘中刷卡时,电话就不再接到了。我认为服务被扼杀了。我能做什么?
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
<service
android:name=".firebase.MyFirebaseMessagingService"
android:exported="true"
android:enabled="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
工作流当收到FCM通知时,一个后台服务启动,然后该服务将自身更改为具有“来电”通知的前台服务。我也在使用全屏意图。下层是我用来服务的
class IncomingCallNotificationService : Service() {
private val TAG = IncomingCallNotificationService::class.java.simpleName
var isRunning = false
private lateinit var soundUri: Uri
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
soundUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + applicationContext.packageName + "/" + R.raw.incoming)
val videoCallDetails: VideoNotification?= intent.getParcelableExtra(Constants.VIDEO_CALL_DETAILS)
val notificationId = intent.getIntExtra(Constants.INCOMING_CALL_NOTIFICATION_ID, 0)
val action = intent.action
if (action != null) {
when(action){
ACTION_INCOMING_CALL_NOTIFICATION -> { handleIncomingCall(videoCallDetails!!, notificationId) }
ACTION_ACCEPT -> {
endForeground()
val intent = Intent(this, VideoActivity::class.java)
intent.action = ACTION_INCOMING_CALL_NOTIFICATION
intent.putExtra(Constants.ROOM_CODE, videoCallDetails?.roomCode)
intent.putExtra(Constants.ROOM_NAME, videoCallDetails?.roomName)
intent.putExtra(Constants.ACCESS_TOKEN, videoCallDetails?.accessToken)
intent.putExtra(Constants.CALLER_NAME, videoCallDetails?.userName)
intent.putExtra(
Constants.CALL_RESPONSE_ACTION_KEY,
Constants.INCOMING_CALL_SCREEN
)
intent.putExtra(Constants.CALL_TYPE, Constants.VIDEO_CALL)
intent.putExtra(Constants.NOTIFCATION_ID, notificationId)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.action = ACTION_ACCEPT
startActivity(intent)
}
ACTION_REJECT -> {
endForeground()
val it = Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)
applicationContext.sendBroadcast(it)
}
}
}
return START_NOT_STICKY
}
override fun onBind(intent: Intent): IBinder? {
return null
}
private fun createNotification(
videoCallDetails: VideoNotification,
notificationId: Int,
channelImportance: Int
): Notification? {
val intent = Intent(this, VideoActivity::class.java)
intent.action = ACTION_INCOMING_CALL_NOTIFICATION
intent.putExtra(Constants.ROOM_CODE, videoCallDetails.roomCode)
intent.putExtra(Constants.ROOM_NAME, videoCallDetails.roomName)
intent.putExtra(Constants.ACCESS_TOKEN, videoCallDetails.accessToken)
intent.putExtra(Constants.CALLER_NAME, videoCallDetails.userName)
intent.putExtra(Constants.CALL_RESPONSE_ACTION_KEY, Constants.INCOMING_CALL_SCREEN)
intent.putExtra(Constants.CALL_TYPE, Constants.VIDEO_CALL)
intent.putExtra(Constants.INCOMING_VIDEO_CALL, true)
intent.putExtra(Constants.NOTIFCATION_ID, notificationId)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
val pendingIntent = PendingIntent.getActivity(
this,
notificationId,
intent,
PendingIntent.FLAG_UPDATE_CURRENT
)
/*
* Pass the notification id and call sid to use as an identifier to cancel the
* notification later
*/
val extras = Bundle()
extras.putString(Constants.ROOM_CODE, videoCallDetails.roomCode)
extras.putString(Constants.ROOM_NAME, videoCallDetails.roomName)
extras.putString(Constants.ACCESS_TOKEN, videoCallDetails.accessToken)
extras.putString(Constants.CALLER_NAME, videoCallDetails.userName)
extras.putString(Constants.CALL_RESPONSE_ACTION_KEY, Constants.INCOMING_CALL_SCREEN)
extras.putString(Constants.CALL_TYPE, Constants.VIDEO_CALL)
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
buildNotification(
videoCallDetails.userName + " is calling.",
pendingIntent,
extras,
videoCallDetails,
notificationId,
createChannel(channelImportance)!!
)
} else {
val builder = NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_call_end_white_24dp)
.setContentTitle(INCOMING_VIDEO_CALL_TEXT)
.setContentText(videoCallDetails.userName + " is calling.")
.setAutoCancel(true)
.setExtras(extras)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(pendingIntent)
.setTimeoutAfter(MomsezeApplication.notificationTimeOut)
.setGroup("test_app_notification")
.setColor(Notification.DEFAULT_LIGHTS)
.setSound(soundUri)
val notification = builder.build()
notification.flags = Notification.FLAG_INSISTENT
return notification
}
}
@TargetApi(Build.VERSION_CODES.O)
private fun buildNotification(
text: String, pendingIntent: PendingIntent, extras: Bundle,
videoCallDetails: VideoNotification,
notificationId: Int,
channelId: String
): Notification? {
val rejectIntent = Intent(applicationContext, IncomingCallNotificationService::class.java)
rejectIntent.action = Constants.ACTION_REJECT
rejectIntent.putExtra(Constants.VIDEO_CALL_DETAILS, videoCallDetails)
rejectIntent.putExtra(Constants.INCOMING_CALL_NOTIFICATION_ID, notificationId)
val piRejectIntent = PendingIntent.getService(
applicationContext,
0,
rejectIntent,
PendingIntent.FLAG_UPDATE_CURRENT
)
val acceptIntent = Intent(applicationContext, IncomingCallNotificationService::class.java)
acceptIntent.action = ACTION_ACCEPT
acceptIntent.putExtra(Constants.VIDEO_CALL_DETAILS, videoCallDetails)
acceptIntent.putExtra(Constants.INCOMING_CALL_NOTIFICATION_ID, notificationId)
val piAcceptIntent = PendingIntent.getService(
applicationContext,
0,
acceptIntent,
PendingIntent.FLAG_UPDATE_CURRENT
)
val builder = NotificationCompat.Builder(applicationContext, channelId)
.setSmallIcon(R.drawable.ic_call_end_white_24dp)
.setContentTitle(INCOMING_VIDEO_CALL_TEXT)
.setContentText(text)
.setCategory(Notification.CATEGORY_CALL)
.setFullScreenIntent(pendingIntent, true)
.setExtras(extras)
.setSound(soundUri)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setAutoCancel(true)
.addAction(android.R.drawable.ic_menu_delete, getString(R.string.decline), piRejectIntent)
.addAction(android.R.drawable.ic_menu_call, getString(R.string.answer), piAcceptIntent)
.setFullScreenIntent(pendingIntent, true)
.setTimeoutAfter(MomsezeApplication.notificationTimeOut)
val notification = builder.build()
notification.flags = Notification.FLAG_INSISTENT
return notification
}
@TargetApi(Build.VERSION_CODES.O)
private fun createChannel(channelImportance: Int): String? {
var callInviteChannel = NotificationChannel(
Constants.VOICE_CHANNEL_HIGH_IMPORTANCE,
"Primary Voice Channel", NotificationManager.IMPORTANCE_HIGH
)
var channelId = Constants.VOICE_CHANNEL_HIGH_IMPORTANCE
if (channelImportance == NotificationManager.IMPORTANCE_LOW) {
callInviteChannel = NotificationChannel(
Constants.VOICE_CHANNEL_LOW_IMPORTANCE,
"Primary Voice Channel",
NotificationManager.IMPORTANCE_DEFAULT
)
channelId = Constants.VOICE_CHANNEL_LOW_IMPORTANCE
}
val audioAttributes = AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_NOTIFICATION)
.build()
callInviteChannel.setSound(soundUri, audioAttributes)
callInviteChannel.lightColor = Color.GREEN
callInviteChannel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC
val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(callInviteChannel)
return channelId
}
private fun handleIncomingCall(videoCallDetails: VideoNotification, notificationId: Int) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
setCallInProgressNotification(videoCallDetails, notificationId)
}
sendCallInviteToActivity(videoCallDetails, notificationId)
}
private fun endForeground() {
stopForeground(true)
}
@TargetApi(Build.VERSION_CODES.O)
private fun setCallInProgressNotification(
videoCallDetails: VideoNotification,
notificationId: Int
) {
if (isAppVisible()) {
startForeground(
notificationId, createNotification(
videoCallDetails,
notificationId,
NotificationManager.IMPORTANCE_LOW
)
)
} else {
startForeground(
notificationId, createNotification(
videoCallDetails,
notificationId,
NotificationManager.IMPORTANCE_HIGH
)
)
}
}
/*
* Send the CallInvite to the VoiceActivity. Start the activity if it is not running already.
*/
private fun sendCallInviteToActivity(videoCallDetails: VideoNotification, notificationId: Int) {
if (Build.VERSION.SDK_INT >= 29 && !isAppVisible()) {
return
}
val intent = Intent(this, VideoActivity::class.java)
intent.action = ACTION_INCOMING_CALL_NOTIFICATION
intent.putExtra(Constants.ROOM_CODE, videoCallDetails.roomCode)
intent.putExtra(Constants.ROOM_NAME, videoCallDetails.roomName)
intent.putExtra(Constants.ACCESS_TOKEN, videoCallDetails.accessToken)
intent.putExtra(Constants.CALLER_NAME, videoCallDetails.userName)
intent.putExtra(Constants.CALL_RESPONSE_ACTION_KEY, Constants.INCOMING_CALL_SCREEN)
intent.putExtra(Constants.CALL_TYPE, Constants.VIDEO_CALL)
intent.putExtra(Constants.INCOMING_VIDEO_CALL, true)
intent.putExtra(Constants.NOTIFCATION_ID, notificationId)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
this.startActivity(intent)
}
private fun isAppVisible(): Boolean {
return ProcessLifecycleOwner
.get()
.lifecycle
.currentState
.isAtLeast(Lifecycle.State.STARTED)
}
private fun createRandomCode(codeLength: Int): Int {
val chars = "1234567890".toCharArray()
val sb = StringBuilder()
val random: Random = SecureRandom()
for (i in 0 until codeLength) {
val c = chars[random.nextInt(chars.size)]
sb.append(c)
}
return sb.toString().toInt()
}
override fun onCreate() {
super.onCreate()
isRunning = true
LocalBroadcastManager.getInstance(this).registerReceiver(
broadCastReceiver, IntentFilter(
Constants.NOTIFCATION_ID
)
)
}
override fun onDestroy() {
super.onDestroy()
isRunning = false
LocalBroadcastManager.getInstance(this).unregisterReceiver(broadCastReceiver)
}
private val broadCastReceiver = object : BroadcastReceiver() {
override fun onReceive(contxt: Context?, intent: Intent?) {
endForeground()
}
}
}
您可以从onstartcommand()
返回start_not_sticky
。当你从最近的任务列表中刷取应用程序时,Android会删除承载应用程序的操作系统进程(以及所有组件activity
、service
等)。如果希望Android在这种情况下自动重新启动服务
,则需要从onstartcommand()
返回start_sticky
。
在我的应用程序中,我有一个在后台(和前台)运行。 在这个中,有一个,当它完成时,我想在某个中启动应用程序并在中自动执行一些操作,即使我的应用程序被杀死或关闭,我也希望它能正常工作。 我看到了一些答案,这是其中之一,但它对我不起作用。我找到了一个更好的解决方案,并将其作为答案发布在下面,但仍然只有在应用程序关闭但未完全关闭时才有效。 如何从后台启动,即使应用程序已关闭或关闭?
问题内容: 如何杀死linux中最后一个生成的后台任务? 例: 问题答案: bash中有一个特殊的变量: $!扩展为在后台执行的最后一个进程的PID。
我的目标是每12小时更新一次我的应用令牌(使用网络请求),无论应用程序是在后台还是被杀死,所以我使用workmanager来解决这个问题。但周期性任务仅在应用程序处于后台或打开状态时有效,但当我杀死应用程序时,周期性任务停止以更新我的应用程序令牌。 这是我的代码: 我正在使用workmanager 2.4.0版本
当我的应用程序前台服务被终止时,不会收到FCM通知,更清楚的是,我正试图让我的应用程序始终在后台运行,我使用前台服务来实现这一点,有时应用程序未被ANDROID系统终止,前台通知会出现15个多小时,但其他情况下,当我的前台通知被终止,并且我发送FCM通知时,它在1小时或更短时间内被终止,而我的设备没有收到FCM通知!!这里有什么问题!我怎样才能解决它!
问题内容: 我是android的新手,我的论文就像android的“ Battery Doctor Saver”一样。我的第一个问题是选择多个应用程序并立即将其杀死。老实说,我已经遇到了第一大问题,但是我的问题是我一次只能杀死一个应用程序。因此,这是我的代码,谢谢您对我的问题的立即答复:)。 问题答案: 创建onButton,然后单击您的kill按钮。从ListView中收集所有选择的按钮及其位置
另外,是否有可能在保留用户数据的同时清除使用ADB的应用程序的缓存?似乎清除了所有用户数据。我只想清除缓存。 我之所以这么问是因为我正在对一些用户应用程序进行性能测试。为了使每个测试有效,我希望确保没有任何用户应用程序有任何任务,活动,服务和缓存已经在后台。