I'm currently developing an Android app, and I need to schedule periodic background tasks to run every hour on devices running Android 13 and 14. I've tried using the WorkManager with PeriodicWorkRequest, and it works perfectly on Android versions below 13. However, it doesn't seem to work as expected on Android 13 and 14.
I've checked the documentation and haven't found any specific issues related to these Android versions. Additionally, I've heard that some mobile manufacturers may not allow certain background tasks. Can anyone provide guidance on how to schedule periodic background tasks for each hour on Android 13 and 14 using WorkManager or any other suitable approach, considering potential restrictions by mobile manufacturers? Your insights and solutions would be greatly appreciated!
My Manifest Permissions
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
My Notification Helper
object NotificationHandler {
private const val CHANNEL_ID = "transactions_reminder_channel"
fun createNotification(context: Context, title: String, content: String) {
// No back-stack when launched
val intent = Intent(context, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val pendingIntent = PendingIntent.getActivity(
context, 0, intent,
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) PendingIntent.FLAG_IMMUTABLE
else PendingIntent.FLAG_UPDATE_CURRENT
)
createNotificationChannel(
context,
title,
content
) // This won't create a new channel everytime, safe to call
val builder = NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.mipmap.ic_launcher_round)
.setContentTitle(title)
.setContentText(content)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(pendingIntent) // For launching the MainActivity
.setAutoCancel(true) // Remove notification when tapped
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
with(NotificationManagerCompat.from(context)) {
if (ActivityCompat.checkSelfPermission(
context,
Manifest.permission.POST_NOTIFICATIONS
) != PackageManager.PERMISSION_GRANTED
) {
return
}
notify(1, builder.build())
}
}
/**
* Required on Android O+
*/
private fun createNotificationChannel(context: Context, title: String, content: String) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val importance = NotificationManager.IMPORTANCE_HIGH
val channel = NotificationChannel(CHANNEL_ID, title, importance).apply {
description = content
}
val notificationManager: NotificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
}
}
My Application Class
@HiltAndroidApp
class App : Application(), Configuration.Provider {
@Inject
lateinit var notificationWorkManagerFactory: NotificationWorkManagerFactory
override fun getWorkManagerConfiguration(): Configuration {
return Configuration.Builder()
.setMinimumLoggingLevel(Log.DEBUG)
.setWorkerFactory(notificationWorkManagerFactory)
.build()
}
}
class NotificationWorkManagerFactory @Inject constructor() : WorkerFactory() {
override fun createWorker(
appContext: Context,
workerClassName: String,
workerParameters: WorkerParameters
): ListenableWorker {
return NotificationWorker(appContext, workerParameters)
}
}
My Worker Class
class NotificationWorker @AssistedInject constructor(
@Assisted var context: Context,
@Assisted parameters: WorkerParameters,
) :
CoroutineWorker(context, parameters) {
override suspend fun doWork(): Result {
return try {
NotificationHandler.createNotification(context = context, title = "Hi from CoroutineWorker", "CoroutineWorker helps support multi-threaded coroutine usage in common code that works in Kotlin/Native and on JVM until kotlinx.")
Result.success()
} catch (e: Exception) {
Log.d("TAG", "doWork: "+e.message)
Result.failure()
}
}
}
And, This is my Activity
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
val workManagerState = remember { mutableStateOf("") }
WorkerTheme {
LaunchedEffect(key1 = Unit) {
val workManager = WorkManager.getInstance(this@MainActivity)
val request: PeriodicWorkRequest =
PeriodicWorkRequestBuilder<NotificationWorker>(
30,
TimeUnit.MINUTES
).build()
workManager.enqueueUniquePeriodicWork(
"reminder_notification_work",
ExistingPeriodicWorkPolicy.UPDATE,
request
)
workManager.getWorkInfosForUniqueWorkLiveData("reminder_notification_work")
.observe(lifecycleOwner) { workInfo ->
workInfo.forEach {
workManagerState.value = it.state.toString()
}
}
}
Text(
text = "Hello ${workManagerState.value}!",
modifier = Modifier.fillMaxWidth()
)
}
}
}
}
What kind of issues you have with android 13/14 and
PeriodicWorkRequest
. I am also using it with android 13/14 and does not have any issue. My usecase is updating the widgets every 15mins. So far i did not regognized a big issue.The time of execution of the work could diff because the system is deciding when to execute the work even you configured every 60 mins. It could take a bit longer until executing. Huge benefit of the WorkManager and
PeriodicWorkRequest
that they also outlive a reboot.Could you post code snipped how you configure it? Are you targeting newest compile/target SDK?