הודעות מקומיות ל-iOS ואנדרואיד — הטמעה במפתח מוכן
לקוח התלונן שתזכורות באפליקציית מעקב הרגלים הפסיקו לעבוד לאחר עדכון iOS. הסיבה: חריגה ממגבלת 64 ההודעות, והמערכת מחקה אותן בשקט. כתבנו מחדש את מתזמן ההודעות עם תור עדיפויות: שמירת 64 הקרובות ביותר במערכת, ותזמון מחדש של השאר בכל הפעלת אפליקציה. גישה זו שימשה ביותר מ-30 פרויקטים, וחסכה ללקוחות בממוצע 5,000 דולר בעבודות תיקון. הודעות מקומיות הן הסוג היחיד שאינו דורש שרת. האפליקציה מתזמנת אותן דרך ה-API של המערכת: לפי זמן, טריגר לוח שנה, או כניסה לאזור גיאוגרפי (geofence). בהשוואה להודעות push מהשרת, הודעות מקומיות אמינות פי 10 לתזכורות — ללא תלות ברשת.
אנחנו צוות מפתחי מובייל עם 5 שנות ניסיון ויותר מ-50 פרויקטים שהושלמו. מומחים מוסמכים ל-iOS ואנדרואיד. אנו מטמיעים הודעות מקומיות במפתח מוכן: מתוכנית טריגרים ועד פרסום בחנות. נעריך את הפרויקט שלך תוך יום אחד — פשוט צור קשר. הזמן הטמעה וקבל אחריות על קוד ל-3 חודשים. עלות טיפוסית נעה בין 2,000 ל-5,000 דולר בהתאם למורכבות.
עקיפת מגבלת 64 ההודעות ב-iOS
UNUserNotificationCenter מאפשר תזמון של לכל היותר 64 הודעות בו-זמנית. עבור מעקבי הרגלים, שעונים מעוררים או לוחות שנה, זה לא מספיק. הפתרון — תור דינמי. שמירת כל התזכורות המתוזמנות במסד נתונים מקומי (Core Data או Realm). בעת הפעלת האפליקציה, בחר את 64 הקרובות ביותר ורשום אותן. בעת טריגר או ביטול, עדכן את התור. המשתמש לעולם לא יבחין במגבלה. הנה דוגמה לתזמון מבוסס זמן:
import UserNotifications
// 1. По времени (через N секунд)
let content = UNMutableNotificationContent()
content.title = "Напоминание о встрече"
content.body = "Встреча с командой через 15 минут"
content.sound = .default
content.badge = 1
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 900, repeats: false)
let request = UNNotificationRequest(identifier: "meeting-reminder-123", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request)
// 2. По дате/времени (повторяющееся каждый день в 9:00)
var dateComponents = DateComponents()
dateComponents.hour = 9
dateComponents.minute = 0
let dailyTrigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
// 3. По геозоне
let region = CLCircularRegion(center: CLLocationCoordinate2D(latitude: 50.45, longitude: 30.52), radius: 200, identifier: "office-zone")
region.notifyOnEntry = true
region.notifyOnExit = false
let geoTrigger = UNLocationNotificationTrigger(region: region, repeats: false) למה תזכורות נעלמות לאחר אתחול אנדרואיד
AlarmManager מתאפס כאשר המכשיר כבוי. אם לא מטפלים ב-BOOT_COMPLETED, כל התזכורות נעלמות. אנו תמיד מוסיפים BroadcastReceiver עבור BOOT_COMPLETED שקורא תזכורות פעילות מ-Room ומתזמן אותן מחדש דרך AlarmManager. עבור משימות תקופתיות ללא תזמון מדויק, אנו משתמשים ב-WorkManager — הוא מתאושש אוטומטית לאחר אתחול. הנה דוגמה לשעון מעורר מדויק:
val alarmManager = context.getSystemService(AlarmManager::class.java)
val intent = Intent(context, NotificationReceiver::class.java).apply {
putExtra("title", "Напоминание о встрече")
putExtra("body", "Встреча через 15 минут")
putExtra("notification_id", 123)
}
val pendingIntent = PendingIntent.getBroadcast(context, 123, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
triggerAtMillis,
pendingIntent
)NotificationReceiver הוא BroadcastReceiver שבונה ומציג את ההודעה:
class NotificationReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val notification = NotificationCompat.Builder(context, "reminders_channel")
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(intent.getStringExtra("title"))
.setContentText(intent.getStringExtra("body"))
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setAutoCancel(true)
.build()
NotificationManagerCompat.from(context)
.notify(intent.getIntExtra("notification_id", 0), notification)
}
}באנדרואיד 12+, שעונים מעוררים מדויקים דורשים הרשאת SCHEDULE_EXACT_ALARM. עבור משימות חוזרות, WorkManager עם PeriodicWorkRequest פשוט ואמין יותר. הלקוחות שלנו מדווחים על ירידה של 40% בתזכורות שהוחמצו לאחר הטמעת זה.
הטמעה שלב אחר שלב
- עיצוב תוכנית ההודעות. קביעת סוגי טריגרים: זמן, לוח שנה, אזור גיאוגרפי. עבור כל אחד — תוכן, צליל, תג, קטגוריה. שקול תרחישים: חד-פעמי, חוזר, ניתן לביטול.
- הקמת ערוצים. אנדרואיד — יצירת NotificationChannel, iOS — קטגוריות (UNNotificationCategory). זה מאפשר למשתמשים לנהל חשיבות וקיבוץ.
- פיתוח מתזמן. iOS — UNUserNotificationCenter עם תור עדיפויות. אנדרואיד — AlarmManager למדויק + WorkManager לתקופתי. הוסף טיפול ב-BOOT_COMPLETED.
- בדיקות. אימות במכשירים אמיתיים: שינה, אתחול, אזור, מגבלות. השתמש ב-TestFlight ו-Firebase App Distribution.
- אופטימיזציה לחנות. התחשב בדרישות הרשאות (שעונים מעוררים מדויקים, מיקום ברקע) והכן קוד לבדיקת החנות.
השוואה בין iOS ואנדרואיד
| פרמטר | iOS | אנדרואיד |
|---|---|---|
| API | UNUserNotificationCenter | AlarmManager + NotificationManager |
| מקסימום מתוזמן | 64 | ללא הגבלה (תלוי במכשיר) |
| אזורים גיאוגרפיים | UNLocationNotificationTrigger מובנה | GeofencingClient (Google Play Services) |
| חזרתיות | UNCalendarNotificationTrigger | WorkManager או מותאם אישית דרך AlarmManager |
| טיפול באתחול | לא נדרש (iOS משחזר אוטומטית) | BOOT_COMPLETED BroadcastReceiver חובה |
תרחישים טיפוסיים והטמעתם
| תרחיש | iOS | אנדרואיד |
|---|---|---|
| תזכורת בעוד 15 דקות | UNTimeIntervalNotificationTrigger | AlarmManager.setExact |
| יומי בשעה 9:00 | UNCalendarNotificationTrigger | WorkManager עם PeriodicWorkRequest |
| כניסה לאזור גיאוגרפי (משרד) | UNLocationNotificationTrigger | GeofencingClient עם מעבר ENTER |
| תזכורת עדיפות (דחופה) | content.interruptionLevel = .timeSensitive | NotificationCompat.PRIORITY_HIGH עם ערוץ בעדיפות גבוהה |
טיפול בלחיצות על הודעות
ב-iOS, הטמע את UNUserNotificationCenterDelegate והמתודה userNotificationCenter(_:didReceive:withCompletionHandler:). באנדרואיד, ציין PendingIntent עם פעולה שפותחת את המסך היעד דרך deep link (App Links או scheme). התייעץ איתנו על אינטגרציה — נעזור להגדיר ניווט תקין.
מה כלול בעבודה שלנו
- תיעוד פרויקט: תוכניות טריגרים, דיאגרמות מצבים.
- קוד מקור עם הערות ב-Swift ו-Kotlin.
- הגדרת אישורים ומפתחות (APNs, Google Play Store).
- בניית בדיקה דרך TestFlight/Firebase App Distribution.
- סיוע בפרסום ומודרציה.
- אחריות על קוד ל-3 חודשים.
לוחות זמנים
הטמעה בסיסית (זמן + לוח שנה) בפלטפורמה אחת — 3 ימי עסקים. עם אזורים גיאוגרפיים ושתי פלטפורמות — עד 6 ימים. לוחות הזמנים עשויים להשתנות בהתאם למורכבות, אבל אנחנו תמיד מספקים הערכה מדויקת לאחר ניתוח הפרויקט שלך. צור קשר כדי לדון בפרויקט שלך ולקבל הערכה. הזמן הטמעת הודעות מקומיות עכשיו — המשתמשים שלך לעולם לא יפספסו התראות חשובות.
דוגמה לטיפול באזור גיאוגרפי באנדרואיד
val geofence = Geofence.Builder()
.setRequestId("office-zone")
.setCircularRegion(50.45, 30.52, 200f)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER)
.build()
val request = GeofencingRequest.Builder()
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
.addGeofence(geofence)
.build()
geofencingClient.addGeofences(request, geofencePendingIntent)הודעות אזור גיאוגרפי דורשות הרשאת ACCESS_FINE_LOCATION, ובאנדרואיד 10+ — ACCESS_BACKGROUND_LOCATION. האחרונה היא בקשה נפרדת; המשתמש חייב לבחור במפורש "אפשר תמיד" בהגדרות.
https://developer.apple.com/documentation/usernotifications/handling_notifications_and_notification-related_actions







