2026 में भरोसेमंद Android रिमाइंडर: WorkManager, सटीक अलार्म और नए बैटरी नियम
2026 में Android पर ऐसे रिमाइंडर कैसे शिप करें जो सचमुच फायर हों — WorkManager बनाम AlarmManager, SCHEDULE_EXACT_ALARM, POST_NOTIFICATIONS, और वे OEM झंझटें जो अब भी काटती हैं।
Android पर एक रिमाइंडर ऐप तभी काम करती है जब रिमाइंडर दिखाई दे। सुनने में साफ़ लगता है — जब तक आप एक शिप नहीं कर देते। फिर आपको पता चलता है डोज़ मोड, ऐप स्टैंडबाय बकेट (app standby buckets), OEM बैटरी ऑप्टिमाइज़र, SCHEDULE_EXACT_ALARM अनुमति, POST_NOTIFICATIONS रनटाइम अनुमति, फ़ोरग्राउंड सर्विस पाबंदियाँ, और यह प्यारा तथ्य कि Samsung और Xiaomi आपके शेड्यूल किए गए काम को “बैटरी बचाने” के लिए चुपचाप मार देंगे, चाहे आपने उसे कितनी भी सही तरह से लिखा हो।
मैंने Hydrame बनाया, एक पानी-ट्रैकिंग ऐप जिसका पूरा मूल्य-प्रस्ताव है “मुझे सही समय पर, धीरे से याद दिलाओ।” मैंने Android की रिमाइंडर स्टैक को भरोसेमंदी में जकड़ने के लिए उतना समय लगाया है जितना मैं मानना नहीं चाहूँगा। यह पोस्ट उस प्लेबुक का 2026 संस्करण है जो आख़िरकार काम करती है।
एक पैराग्राफ़ में रिमाइंडर की समस्या
Android बैकग्राउंड काम को मारने में आक्रामक है, और होना भी चाहिए — बिना नियंत्रण के, हर ऐप हर कुछ मिनट में रेडियो को जगा देती और आपकी बैटरी दोपहर के खाने तक ख़त्म हो जाती। वैध रिमाइंडर ऐप्स के लिए इसका नतीजा है ओवरलैप करने वाली API का ढेर, जिनमें से हर एक संस्करणों और OEM स्किन्स में थोड़ा अलग व्यवहार करती है। काम है आपके “सटीक होना ही चाहिए” स्तर के लिए सही प्रिमिटिव चुनना और यह स्वीकार करना कि बाक़ी असली डिवाइसों पर परीक्षण है।
2026 में जो दो प्रिमिटिव मायने रखती हैं, वे हैं:
WorkManager— असटीक, टाले जा सकने वाले काम के लिए। आवधिक जाँच, “अगले एक घंटे में कभी याद दिला दो” जैसे उपयोग-मामले। बैटरी के प्रति सजग, आपस में जोड़ी जाती है, रिबूट के बाद भी चलती है।AlarmManager.setExactAndAllowWhileIdle— किसी विशिष्ट समय पर सटीक, उपयोगकर्ता को दिखने वाली सूचनाओं के लिए। महँगी वाली। इसे कम-कम इस्तेमाल करें और केवल तभी जब “15 मिनट इधर-उधर” होने से फ़ीचर टूटा हुआ लगे।
अगर आपका रिमाइंडर ठीक 19:30 पर फायर होना ही चाहिए, तो आपको सटीक अलार्म चाहिए। अगर “19:30 के आसपास कभी” ठीक है, तो WorkManager इस्तेमाल करें। ज़्यादातर ऐप्स डिफ़ॉल्ट रूप से ग़लत वाली चुन लेती हैं।
तीन अनुमतियाँ जिन्हें सही करना ज़रूरी है
2026 में, तीन रनटाइम/इंस्टॉल अनुमतियाँ तय करती हैं कि उपयोगकर्ता को कभी कोई रिमाइंडर दिखेगा या नहीं:
POST_NOTIFICATIONS(रनटाइम, Android 13+)। इसके बिना, आपकी सूचना अक्षरशः दिखती ही नहीं। इसे सही पल पर माँगें, पहली लॉन्च पर नहीं।SCHEDULE_EXACT_ALARM(Android 12+, 13+ पर प्रतिबंधित)।setExactAndAllowWhileIdleके लिए ज़रूरी। Android 14+ पर यह तभी मिलती है जब उपयोगकर्ता सिस्टम सेटिंग्स में इसे स्पष्ट रूप से टॉगल करे; ऐप को उपयोगकर्ता को वहाँ भेजना पड़ता है।USE_EXACT_ALARM(Android 13+, विशेष-उपयोग)। उन ऐप्स के लिए जहाँ सटीक अलार्म मूल हैं (अलार्म घड़ियाँ, कैलेंडर रिमाइंडर, हाइड्रेशन)। Play औचित्य माँगता है।
Hydrame का मेनिफ़ेस्ट ऐसा दिखता है:
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
RECEIVE_BOOT_COMPLETED वह है जिसे ज़्यादातर लोग भूल जाते हैं — इसके बिना, आपके शेड्यूल किए गए अलार्म अगले रिबूट पर ग़ायब हो जाते हैं। ACTION_BOOT_COMPLETED पर एक BroadcastReceiver से इन्हें दोबारा शेड्यूल करें।
POST_NOTIFICATIONS को सही पल पर माँगना
पहली लॉन्च पर मत माँगें। स्वीकृति दर नाटकीय रूप से ज़्यादा होती है अगर आप ऐसे पल पर माँगें जो मूल्य से मेल खाता हो: ठीक उस समय जब उपयोगकर्ता अपना पहला रिमाइंडर चालू करे। एक असली फ़्लो:
@Composable
fun EnableReminderButton(onEnabled: () -> Unit) {
val context = LocalContext.current
val launcher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.RequestPermission(),
) { granted ->
if (granted) onEnabled()
}
FilledButton(onClick = {
if (Build.VERSION.SDK_INT >= 33) {
val state = ContextCompat.checkSelfPermission(
context,
Manifest.permission.POST_NOTIFICATIONS,
)
if (state == PackageManager.PERMISSION_GRANTED) onEnabled()
else launcher.launch(Manifest.permission.POST_NOTIFICATIONS)
} else {
onEnabled()
}
}) { Text("Enable reminders") }
}
दो और चीज़ें जो मैं हमेशा करता हूँ:
- एक दूसरा-मौका औचित्य। अगर उपयोगकर्ता मना कर दे, तो तुरंत दोबारा मत माँगें। अगली बार जब वह कोई रिमाइंडर चालू करने की कोशिश करे, एक छोटा इनलाइन संदेश दिखाएँ जिसमें एक बटन हो जो ऐप की सेटिंग्स स्क्रीन खोले ताकि वह ख़ुद इसे बदल सके।
- “दोबारा मत पूछो” के साथ अस्वीकृत स्थिति का पता लगाएँ आख़िरी इनकार को DataStore में याद रखकर — इसके लिए अकेले
shouldShowRequestPermissionRationaleभरोसेमंद नहीं है।
असटीक: WorkManager आवधिक काम
ऐसे रिमाइंडर के लिए जहाँ “सुबह कभी” स्वीकार्य है, WorkManager उबाऊ लेकिन सही जवाब है:
class DailyHydrationCheckWorker(
appContext: Context,
params: WorkerParameters,
) : CoroutineWorker(appContext, params) {
override suspend fun doWork(): Result {
scheduleTodayReminders()
return Result.success()
}
}
fun scheduleDailyHydrationCheck(context: Context) {
val request = PeriodicWorkRequestBuilder<DailyHydrationCheckWorker>(
repeatInterval = 1, repeatIntervalTimeUnit = TimeUnit.DAYS,
)
.setConstraints(
Constraints.Builder()
.setRequiresBatteryNotLow(true)
.build(),
)
.setInitialDelay(secondsUntil(6, 0).toLong(), TimeUnit.SECONDS)
.build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
"daily_hydration_check",
ExistingPeriodicWorkPolicy.UPDATE,
request,
)
}
कुछ चीज़ें जो लोगों को काटती हैं:
- 15 मिनट की न्यूनतम अवधि।
PeriodicWorkRequestहर 15 मिनट से ज़्यादा बार नहीं चलेगा, चाहे आप कुछ भी माँगें। 15 मिनट से कम की शेड्यूलिंग के लिए, ऐसा वन-टाइम काम इस्तेमाल करें जो ख़ुद को श्रृंखला में जोड़े। - कोई सटीक टाइमिंग नहीं। WorkManager एक विंडो के भीतर शेड्यूल करता है। अगर आपको “ठीक 8:00:00 पर” चाहिए, तो यह ग़लत प्रिमिटिव है।
- Battery-not-low आपके उपयोगकर्ताओं के लिए भी और सिस्टम के लिए भी अनुकूल है; जब तक कोई वजह न हो, इसे चालू रखें।
सटीक: AlarmManager.setExactAndAllowWhileIdle
जब रिमाइंडर किसी विशिष्ट पल पर फायर होना ही चाहिए — जैसे, किसी उपयोगकर्ता ने कहा “मुझे 19:30 पर याद दिलाओ” और वह सचमुच यही चाहता है — तो आपको सटीक अलार्म चाहिए। पैटर्न:
fun scheduleExactReminder(
context: Context,
triggerAtMillis: Long,
requestCode: Int,
) {
val am = context.getSystemService(AlarmManager::class.java)
if (Build.VERSION.SDK_INT >= 31 && !am.canScheduleExactAlarms()) {
// Send the user to the system page to grant the permission.
context.startActivity(
Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM)
.setData(Uri.parse("package:${context.packageName}"))
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
)
return
}
val intent = Intent(context, ReminderReceiver::class.java)
.putExtra("requestCode", requestCode)
val pending = PendingIntent.getBroadcast(
context, requestCode, intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerAtMillis, pending)
}
setExactAndAllowWhileIdle वह है जो डोज़ का सम्मान करती है। इसके बजाय setAlarmClock तभी इस्तेमाल करें जब आपकी ऐप सचमुच एक अलार्म घड़ी हो — यह सिस्टम UI पर अगला-अलार्म चिप दिखाती है और सबसे ऊँची प्राथमिकता पाती है।
भारी पल के लिए रिसीवर + फ़ोरग्राउंड सर्विस
जब अलार्म फायर होता है, तो आपके पास सूचना पोस्ट करने के लिए कुछ सेकंड का जागृत-समय होता है। एक साधारण “टन!” रिमाइंडर के लिए यह काफ़ी है:
class ReminderReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
// Post the notification synchronously.
val nm = context.getSystemService(NotificationManager::class.java)
nm.notify(
intent.getIntExtra("requestCode", 0),
buildHydrationNotification(context),
)
// Re-schedule the next one.
scheduleNext(context)
}
}
अगर आपको अलार्म पर असली काम करना है (सिंक, डाउनलोड), तो तुरंत एक फ़ोरग्राउंड सर्विस में बढ़ोतरी करें। चतुर बनने की कोशिश न करें — अगर आप रिसीवर में अटके, तो सिस्टम एक पल में आपको रद्द कर देगा।
रिबूट और टाइमज़ोन बदलाव
दो घटनाएँ एक भोले क्रियान्वयन को चुपचाप तोड़ देंगी:
- रिबूट। अलार्म मिटा दिए जाते हैं।
ACTION_BOOT_COMPLETEDसुनें और अपने स्थायी स्थिति से दोबारा शेड्यूल करें। - टाइमज़ोन बदलाव। सुबह 7 बजे का रिमाइंडर उपयोगकर्ता के जाने से पहले स्थानीय समय के 7 बजे और जाने के बाद इस्तांबुल के 7 बजे फायर नहीं होना चाहिए।
ACTION_TIMEZONE_CHANGEDसुनें और दोबारा गणना करें।
एक ही रिसीवर दोनों को संभालता है:
<receiver android:name=".BootAndTimezoneReceiver" android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.TIMEZONE_CHANGED"/>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
</intent-filter>
</receiver>
MY_PACKAGE_REPLACED वह है जिसे ऐप अपडेट फायर करते हैं — आपका कोड ताज़ा है, लेकिन आपके अलार्म ग़ायब हैं। वहाँ भी दोबारा शेड्यूल करें।
OEM ऑप्टिमाइज़र — ख़ामोश हत्यारे
2026 में सबसे बुरा बचा हुआ अपराधी अब भी Samsung की “स्लीपिंग ऐप्स” सूची है, जिसके ठीक पीछे Xiaomi की ऑटोस्टार्ट और बैटरी सेवर हैं। दो व्यावहारिक बचाव:
- ऐप-के-भीतर डायग्नॉस्टिक बैनर। अगर उपयोगकर्ता के रिमाइंडर चालू होने के बावजूद 24 घंटों में कोई सूचना फायर नहीं हुई, तो एक छोटा बैनर दिखाएँ जिसमें सही OEM सेटिंग्स पेज तक “इसे ठीक करें” डीप-लिंक हो। Stack Overflow और Don’t Kill My App प्रोजेक्ट इन डीप-लिंक्स को अद्यतन रखते हैं; इन्हें स्थानीय रूप से कैश करें।
- बैटरी व्हाइटलिस्ट को उत्सुकता से मत माँगें। यह उपयोगकर्ताओं को डराती है और Play इसे नापसंद करता है। इसे उस उपयोगकर्ता के लिए बचाकर रखें जो पहले ही कोई छूटा हुआ रिमाइंडर देख चुका है।
वह पैटर्न जो आख़िरकार काम कर गया
Hydrame पर तीन पुनरावृत्तियों के बाद, वह आर्किटेक्चर जो आख़िरकार भरोसेमंद महसूस हुआ:
- एक आवधिक
WorkManagerजॉब हर रात चलता है। यह उपयोगकर्ता का शेड्यूल पढ़ता है और अगले 24 घंटों के सटीक अलार्म डालता है। - हर सटीक अलार्म एक
BroadcastReceiverके ज़रिए सूचना पोस्ट करता है। रिसीवर बुद्धू है — कोई DB कॉल नहीं, कोई नेटवर्क नहीं। - रिबूट + टाइमज़ोन-बदलाव + ऐप-अपडेट रिसीवर शेड्यूल दोबारा बनाने के लिए उसी रात्रिकालीन जॉब को मैन्युअल रूप से ट्रिगर करते हैं।
- एक हार्टबीट मीट्रिक (आख़िरी सफल सूचना का टाइमस्टैम्प, DataStore में संग्रहीत) ऐप-के-भीतर “आपके रिमाइंडर आपके फ़ोन द्वारा मारे जा सकते हैं” बैनर को शक्ति देता है।
यह उससे ज़्यादा वायरिंग है जितनी मैं लिखता अगर मैंने अपनी पहली प्रवृत्ति (“बस WorkManager इस्तेमाल करो”) पर भरोसा किया होता। लेकिन हर टुकड़ा इसलिए मौजूद है क्योंकि उसके बिना कुछ चुपचाप टूट गया था।
फिर से, असली फ़ोनों पर परीक्षण
मैं अपनी लिखी हर Android पोस्ट की वही पंक्ति दोहराऊँगा: आप भरोसेमंद रिमाइंडर सिर्फ़ एमुलेटर पर परीक्षण नहीं कर सकते। एक सस्ता Samsung, एक सस्ता Xiaomi, और एक Pixel लें। अभी से 30 मिनट बाद का रिमाइंडर सेट करें। फ़ोन को लॉक करें और डेस्क पर छोड़ दें। वापस आएँ और देखें कि क्या फायर हुआ और क्या नहीं। वह एक प्रयोग किसी भी ब्लॉग पोस्ट से ज़्यादा मूल्यवान है।
इस पोस्ट सहित। जाइए, इसे परखिए।
// संबंधित पठन
जर्नल से और भी
Android नोटिफ़िकेशन एक्शन सही तरीके से: बिना ऐप खोले एक खुराक को ली गई के रूप में चिह्नित करना
Android नोटिफ़िकेशन एक्शन बटन के लिए एक व्यावहारिक गाइड — PendingIntent, activity-trampoline प्रतिबंध, goAsync(), और Room स्टेट को सुरक्षित रूप से अपडेट करना।
ऐसा दवा रूटीन बनाना जिस पर आप वाकई टिके रहें
दवा को समय पर लेने की एक व्यावहारिक गाइड — लोग खुराक क्यों छोड़ देते हैं, रिमाइंडर का समय असल में कैसे काम करता है, और एक ऐसा रूटीन कैसे बनाएं जो एक खराब हफ्ते में भी टिका रहे।
एक हाइड्रेशन रूटीन जो इच्छाशक्ति पर निर्भर नहीं करता
ज़्यादातर हाइड्रेशन सलाह 'ज़्यादा पानी पिएं' पर सिमट कर रह जाती है और उम्मीद करती है कि बाकी का काम इच्छाशक्ति कर देगी। यहां एक ऐसा रूटीन है जो इच्छाशक्ति की बजाय संकेतों (cues) और हल्के रिमाइंडर्स पर बना है।