You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

技术需求:实现后台定时推送自定义消息(参考Auto-Athkar应用)

Hey there! Let's break down how to implement those two background messaging features you need, matching the behavior of Auto-Athkar for Muslims. Here's a step-by-step solution tailored to Android's background restrictions:

实现后台定时自定义消息方案(适配未启动状态+唤醒场景)

一、核心技术选型

Android 8.0+ has strict background limits, so we'll use WorkManager (Google's recommended tool for scheduled tasks) — it handles background execution even when the app isn't running, and we'll pair it with wake locks to ensure messages show when the device is awake.

二、Step-by-Step Implementation

1. Add Dependencies

First, include WorkManager in your app-level build.gradle (Module):

dependencies {
    // Core WorkManager library
    implementation "androidx.work:work-runtime:2.8.1"
    // Kotlin extensions (optional but recommended for coroutine support)
    implementation "androidx.work:work-runtime-ktx:2.8.1"
}

2. Create a Worker Class (Handles Message Display)

This class will handle showing your custom message (we'll use notifications as an example, like Auto-Athkar) and manage wake locks to keep the device awake temporarily:

import android.app.NotificationManager
import android.content.Context
import android.os.Build
import android.os.PowerManager
import androidx.core.app.NotificationCompat
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlin.random.Random

class CustomMessageWorker(
    private val context: Context,
    params: WorkerParameters
) : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result = withContext(Dispatchers.IO) {
        // Acquire wake lock to ensure device stays awake while showing the message
        val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager
        val wakeLock = powerManager.newWakeLock(
            PowerManager.SCREEN_DIM_WAKE_LOCK or PowerManager.ACQUIRE_CAUSES_WAKEUP,
            "MyApp:MessageWakeLock"
        )
        wakeLock.acquire(10000) // Hold for 10 seconds to ensure visibility

        try {
            // Show your custom message (replace with your own UI/notification logic)
            showCustomNotification()
        } finally {
            if (wakeLock.isHeld) wakeLock.release()
        }

        // Return success to allow re-scheduling (for random intervals)
        return@withContext Result.success()
    }

    private fun showCustomNotification() {
        val notificationManager = context.getSystemService(NotificationManager::class.java)

        // Create notification channel (required for Android 8.0+)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = android.app.NotificationChannel(
                "custom_message_channel",
                "Custom Reminders",
                NotificationManager.IMPORTANCE_DEFAULT
            ).apply {
                description = "Timed custom messages from your app"
            }
            notificationManager.createNotificationChannel(channel)
        }

        val notification = NotificationCompat.Builder(context, "custom_message_channel")
            .setSmallIcon(R.drawable.ic_your_notification_icon) // Replace with your icon
            .setContentTitle("Your Custom Title")
            .setContentText("This is your scheduled custom message!") // Replace with dynamic content
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
            .build()

        // Use random ID to avoid overwriting previous notifications
        notificationManager.notify(Random.nextInt(), notification)
    }
}

3. Schedule the Two Task Types

(1) Fixed 10-Second Interval Task

Use PeriodicWorkRequest for consistent, repeated execution:

import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.workDataOf
import java.util.concurrent.TimeUnit

fun scheduleFixedIntervalTask(context: Context) {
    val fixedWorkRequest = PeriodicWorkRequestBuilder<CustomMessageWorker>(10, TimeUnit.SECONDS)
        .setInputData(workDataOf("task_type" to "fixed"))
        .setConstraints(androidx.work.Constraints.Builder()
            .setRequiresDeviceIdle(false) // Don't wait for device to be idle
            .setRequiresCharging(false) // Run even if not charging
            .build())
        .build()

    // Enqueue as a unique task to avoid duplicate schedules
    WorkManager.getInstance(context).enqueueUniquePeriodicWork(
        "fixed_interval_task",
        ExistingPeriodicWorkPolicy.REPLACE,
        fixedWorkRequest
    )
}

(2) Random 10-20 Second Interval Task

Since periodic requests can't have random intervals, use OneTimeWorkRequest and re-schedule after each execution:

import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.ExistingWorkPolicy
import kotlin.random.Random
import java.util.concurrent.TimeUnit

fun scheduleRandomIntervalTask(context: Context) {
    // Generate random delay between 10-20 seconds
    val randomDelay = Random.nextLong(10, 21)

    val randomWorkRequest = OneTimeWorkRequestBuilder<CustomMessageWorker>()
        .setInitialDelay(randomDelay, TimeUnit.SECONDS)
        .setInputData(workDataOf("task_type" to "random"))
        .setConstraints(androidx.work.Constraints.Builder()
            .setRequiresDeviceIdle(false)
            .setRequiresCharging(false)
            .build())
        .build()

    // Enqueue unique task to replace any existing random task
    WorkManager.getInstance(context).enqueueUniqueWork(
        "random_interval_task",
        ExistingWorkPolicy.REPLACE,
        randomWorkRequest
    )

    // Re-schedule the task once it completes
    WorkManager.getInstance(context).getWorkInfoByIdLiveData(randomWorkRequest.id)
        .observeForever { workInfo ->
            if (workInfo.state == androidx.work.WorkInfo.State.SUCCEEDED) {
                scheduleRandomIntervalTask(context)
            }
        }
}

4. Trigger the Tasks

Add buttons or a settings screen to let users start/stop the tasks (example in an Activity):

import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Start fixed interval task
        findViewById<android.widget.Button>(R.id.btn_start_fixed).setOnClickListener {
            scheduleFixedIntervalTask(this)
            Toast.makeText(this, "Fixed interval task started", Toast.LENGTH_SHORT).show()
        }

        // Start random interval task
        findViewById<android.widget.Button>(R.id.btn_start_random).setOnClickListener {
            scheduleRandomIntervalTask(this)
            Toast.makeText(this, "Random interval task started", Toast.LENGTH_SHORT).show()
        }
    }
}

5. Required Permissions

Add these to your AndroidManifest.xml:

<!-- For wake lock access -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- For notifications (Android 13+) -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

For Android 13+, remember to request the POST_NOTIFICATIONS permission dynamically in your code.

三、Key Notes for Auto-Athkar Like Behavior

  • Wake Lock Handling: The wake lock ensures messages show even if the device is awake but not actively used (like Auto-Athkar's prayer reminders).
  • Background Resilience: WorkManager automatically handles Doze mode and app standby, so tasks will run when the device is awake.
  • Battery Optimization: Add a toggle in your app to let users disable tasks when needed, and consider adding constraints (like only running when charging) to reduce battery usage.

内容的提问来源于stack exchange,提问作者PerfectDroid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:12:23