משתמש פותח את האפליקציה שלך ברכבת התחתית — ללא רשת. במקום תוכן, מסך לבן או נתונים מיושנים ללא חותמת זמן. אובדן אמון ועזיבה. לפי סטטיסטיקות, 70% מהמשתמשים מצפים שהאפליקציה תעבוד ללא אינטרנט, אך רק 20% מהמפתחים מקדישים תשומת לב נאותה לבדיקות אופליין. בדקנו מעל 50 פרויקטים עם מצב אופליין ואנחנו מכירים את המלכודות האופייניות. לדוגמה, בפרויקט אחד 80% מתקלות האופליין היו קשורות לקאש — הקאש לא התרענן כשהאפליקציה הייתה מקוונת, והציג נתונים פגומים כשהייתה אופליין. בעיות אלה ניתנות לפתרון בשלב הבדיקות. הזמינו בדיקות אופליין כדי להימנע מאובדן משתמשים והכנסות. שירותי בדיקות האופליין לאפליקציות ניידות שלנו מכסים את כל התרחישים, עם דגש ספציפי על בדיקות פונקציונליות אופליין וקאש נתונים ב-iOS, קאש נתונים ב-Android, תור פעולות אופליין, סנכרון בעת חידוש חיבור, פתרון קונפליקטים בסנכרון ותרחישי בדיקות אופליין.
מה אנחנו בודקים: שלושה תרחישים קריטיים
- הפעלה ללא רשת: האפליקציה חייבת להציג את הנתונים האחרונים שנשמרו בקאש עם חותמת זמן (לדוגמה, "עודכן לפני שעתיים"), לא מסך ריק. אנו מוודאים תקינות קאש וממשק גיבוי.
- אובדן חיבור במהלך שימוש: התוכן נשאר נגיש. פעולות שלא הושלמו (שליחת טופס, עריכה) נשמרות כטיוטות או בתור.
- חידוש חיבור: נתונים מסונכרנים, תור הפעולות הדחויות מתבצע, וקונפליקטים נפתרים ללא התערבות משתמש.
איך אנחנו מבטיחים עקביות נתונים אופליין?
קאש מקומי הוא הבסיס למצב אופליין. ב-iOS אנו משתמשים ב-NSURLCache לתגובות HTTP (עם כותרות Cache-Control מתאימות), Core Data או Realm לנתונים מובנים, UserDefaults להגדרות. למדיה — FileManager עם תיקיית קאש מותאמת אישית. ב-Android — Room לנתונים מובנים, DataStore להגדרות, Cache-Control דרך OkHttp. גישה זו מפחיתה בקשות רשת ב-70% כאשר קיים קאש פעיל.
val cacheSize = 10 * 1024 * 1024L // 10 MB
val cache = Cache(context.cacheDir, cacheSize)
val okHttpClient = OkHttpClient.Builder()
.cache(cache)
.addNetworkInterceptor { chain ->
val response = chain.proceed(chain.request())
response.newBuilder()
.header("Cache-Control", "public, max-age=300") // 5 минут
.build()
}
.addInterceptor { chain ->
val request = if (isNetworkAvailable()) {
chain.request()
} else {
chain.request().newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=${60 * 60 * 24}") // 24 часа из кэша
.build()
}
chain.proceed(request)
}
.build()
val cacheSize = 10 * 1024 * 1024L // 10 MB val cache = Cache(context.cacheDir, cacheSize) val okHttpClient = OkHttpClient.Builder() .cache(cache) .addNetworkInterceptor { chain -> val response = chain.proceed(chain.request()) response.newBuilder() .header("Cache-Control", "public, max-age=300") // 5 минут .build() } .addInterceptor { chain -> val request = if (isNetworkAvailable()) { chain.request() } else { chain.request().newBuilder() .header("Cache-Control", "public, only-if-cached, max-stale=${60 * 60 * 24}") // 24 часа из кэша .build() } chain.proceed(request) } .build() + only-if-cached — אנו קוראים מהקאש גם אם הנתונים מיושנים, כל עוד אנחנו אופליין. זהו תבנית קאש מרכזית ל-Android.
דוגמת מקרה בדיקה לקאש (iOS)
- הגדר את Network Link Conditioner ל-100% אובדן.
- פתח את האפליקציה — ודא שהנתונים מהקאש מוצגים עם תווית "עודכן לפני N דקות".
- סגור את האפליקציה, הפעל רשת, פתח מחדש — הנתונים צריכים להתרענן.
למה טיפול נכון בקונפליקטים בסנכרון הוא קריטי?
משתמש ערך רשומה אופליין, בעוד משתמש אחר שינה את אותה רשומה מקוון. בעת חידוש החיבור — קונפליקט. אסטרטגיות עיקריות:
| אסטרטגיה | תיאור | מתי ליישם |
|---|---|---|
| last-write-wins | הכתיבה האחרונה מנצחת | נתונים פשוטים, סיכון נמוך |
| server-wins | גרסת השרת בעדיפות | חיזוי על פני שמירת עריכות |
| merge | מיזוג גרסאות | נתונים מורכבים, אובדן מינימלי |
| הודעת משתמש | דיאלוג בחירת גרסה | כאשר נדרשת שליטת משתמש |
לרוב האפליקציות, הצגת דיאלוג למשתמש מספיקה. במקרים מורכבים, אנו מיישמים מדיניות מיזוג מותאמת אישית המבוססת על חותמות זמן וסוגי שינויים.
באיזו אסטרטגיית סנכרון לבחור?
הבחירה תלויה בקריטיות הנתונים. לנתונים פשוטים (לייקים, צפיות), last-write-wins עובד. לפעולות פיננסיות — server-wins או הודעת משתמש. אסטרטגיית מיזוג מפחיתה אובדן נתונים פי 2 בהשוואה ל-last-write-wins באפליקציות עם עריכה אינטנסיבית.
איך ליישם תור פעולות דחויות?
פעולות משתמש אופליין חייבות להישמר ולהתבצע כשהרשת חוזרת. ב-Android אנו משתמשים ב-WorkManager עם max-stale:
fun scheduleOfflineAction(action: UserAction) {
val data = workDataOf("action_json" to action.toJson())
val request = OneTimeWorkRequestBuilder<SyncWorker>()
.setConstraints(Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build())
.setInputData(data)
.build()
WorkManager.getInstance(context).enqueue(request)
}הפעולה נשמרת במסד הנתונים, שורדת אתחולי מכשיר. ב-iOS — מסגרת BackgroundTasks (last-write-wins) או תור מקומי ב-Core Data עם ניסיון חוזר ב-server-wins ושינויי רשת דרך merge. WorkManager ב-Android אמין פי 3 מ-AlarmManager מכיוון שהוא מתחשב במצב רשת וסוללה. BackgroundTasks ב-iOS מספק יכולות דומות.
אילו כלים לדמות רשתות אופליין?
| פלטפורמה | כלי | פקודה/פעולה |
|---|---|---|
| iOS | Network Link Conditioner | Hardware → Network Link Conditioner → 100% Loss |
| iOS (CLI) | xcrun simctl | last-write-wins עם שינוי הגדרות רשת |
| Android | adb | server-wins |
| Android (בדיקות אוטומטיות) | Detox | merge |
Network Link Conditioner נוח פי 2 מאמולציה ידנית של הגדרות iOS מכיוון שהוא מאפשר מעבר בין פרופילים ללא אתחול.
איך מתבצעות בדיקות אופליין?
- ניתוח. אנו לומדים דרישות, יישום נוכחי, תרחישי שימוש.
- עיצוב בדיקות. אנו יוצרים רשימת תרחישי אופליין, מגדירים מדדים.
- יישום בדיקות. אנו כותבים בדיקות אוטומטיות באמצעות בדיקות אוטומטיות Detox, מגדירים כלי אמולציה.
- ביצוע בדיקות. אנו מוודאים קאש, תור, סנכרון, קונפליקטים.
- ניתוח ודוח. אנו מתעדים תקלות, מספקים המלצות.
תוצרים
- דוח מפורט עם תוצאות בדיקות.
- רשימת תרחישים מאומתים.
- המלצות לתיקון תקלות עם דוגמאות קוד.
- תיעוד של היישום האופליין הנוכחי.
- גישה לסביבות בדיקה והדרכה אופציונלית לצוות שלך.
- תמיכה במהלך תיקון תקלות (אופציונלי).
לוחות זמנים ועלות
זמן משוער — 2 עד 3 ימים לבדיקת הרשימה והכנת הדוח. החל מ-$500 לביקורת בסיסית, חיסכון מתיקון תקלות מפחית עזיבה בעד 20%. העלות מחושבת באופן אישי לפי מורכבות האפליקציה. צרו קשר להערכה חינמית של הפרויקט שלכם. הזמינו בדיקות אופליין כדי להבטיח את אמינות האפליקציה שלכם.







