פיתוח שכבת רשת עם Retrofit נתקל לא פעם במכשולים: 401 בלתי צפוי, שגיאות פענוח, דליפות טוקנים. אחד הפרויקטים שלנו—אפליקציית שירות בנקאי—דרש אימות אמין עם חידוש טוקן. ללא הגדרת Authenticator של OkHttp, כל בקשה למשאב מוגן החזירה שגיאה. נאלצנו לשכתב את הלוגיקה כדי להימנע מטיפול ידני בכל UseCase. עם ניסיון של למעלה מ-5 שנים על 20+ פרויקטים, פיתחנו תצורה סטנדרטית שמקצרת את זמן פיתוח שכבת הרשת ב-30–50%. בואו נבחן שיטות מומלצות להגדרת שכבת רשת עם Retrofit.
כיצד להגדיר אימות ב-Retrofit?
האימות בנוי על שני רכיבים: Interceptor להוספת ה-header ו-Authenticator לחידוש הטוקן. ה-Interceptor קורא את הטוקן מאחסון מאובטח (EncryptedSharedPreferences) ומצרף אותו לכל בקשה. כאשר השרת מחזיר 401, ה-Authenticator מנסה לחדש את הטוקן דרך נקודת קצה לחידוש ומנסה שוב את הבקשה. זה מבטל את הצורך בהעתקת לוגיקת אימות בכל הפרויקט ועובד עם כל ספק OAuth2.
class AuthInterceptor(private val tokenProvider: TokenProvider) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request().newBuilder()
.addHeader("Authorization", "Bearer ${tokenProvider.getToken()}")
.build()
return chain.proceed(request)
}
}
class TokenAuthenticator(
private val tokenProvider: TokenProvider,
private val refreshApi: RefreshApi
) : Authenticator {
override fun authenticate(route: Route?, response: Response): Request? {
synchronized(this) {
val newToken = tokenProvider.getToken() ?: return null
if (response.request.header("Authorization") == "Bearer $newToken") {
val refreshed = refreshApi.refresh(newToken)
if (refreshed.isSuccessful) {
tokenProvider.saveToken(refreshed.body()!!.accessToken)
return response.request.newBuilder()
.header("Authorization", "Bearer ${refreshed.body()!!.accessToken}")
.build()
}
}
}
return null
}
} למה KotlinX Serialization על פני Gson?
בפרויקטים של Kotlin, class AuthInterceptor(private val tokenProvider: TokenProvider) : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val request = chain.request().newBuilder() .addHeader("Authorization", "Bearer ${tokenProvider.getToken()}") .build() return chain.proceed(request) } } class TokenAuthenticator( private val tokenProvider: TokenProvider, private val refreshApi: RefreshApi ) : Authenticator { override fun authenticate(route: Route?, response: Response): Request? { synchronized(this) { val newToken = tokenProvider.getToken() ?: return null if (response.request.header("Authorization") == "Bearer $newToken") { val refreshed = refreshApi.refresh(newToken) if (refreshed.isSuccessful) { tokenProvider.saveToken(refreshed.body()!!.accessToken) return response.request.newBuilder() .header("Authorization", "Bearer ${refreshed.body()!!.accessToken}") .build() } } } return null } } מציע יתרונות: בטיחות null ברמת הפענוח, תמיכה ב-sealed classes, וללא reflection. זה חשוב בעת ערפול עם R8, מכיוון שקריאות reflection של Gson עלולות להישבר. במדידות שלנו, KotlinX מעבד JSON פי 2–3 מהר יותר מ-Gson על payloads מעל 100 KB. בנוסף, גודל ה-APK גדל רק בכ-50 KB לעומת כ-200 KB עבור Gson.
| קריטריון | Gson | KotlinX Serialization |
|---|---|---|
| מהירות (יחסית) | 1x | 2–3x |
| בטיחות null | לא | כן |
| Sealed classes | לא | כן |
| Reflection | כן | לא |
| גידול בגודל APK | ~200 KB | ~50 KB |
OkHttp Interceptors
רוב הלוגיקה של שכבת הרשת מרוכזת כאן. מלבד אימות, interceptors טיפוסיים:
- לוגינג:
kotlinx.serializationעם רמהHttpLoggingInterceptorרק עבור build דיבוג. בייצור—BODYכדי להימנע מלוגינג של נתונים רגישים. - ניסיון חוזר: interceptor מותאם אישית עם exponential backoff עבור
NONE. אין לנסות שוב 4xx/5xx—רק כשלי רשת. - Timeout:
IOException,connectTimeout(30, TimeUnit.SECONDS),readTimeout(30, TimeUnit.SECONDS). להעלאת קבצים, השתמשו ב-client נפרד עםwriteTimeout(30, TimeUnit.SECONDS)מוגדל.
| Interceptor | מטרה | תצורה לדוגמה |
|---|---|---|
| AuthInterceptor | הוספת Bearer token | writeTimeout |
| TokenAuthenticator | חידוש טוקן אוטומטי | .addInterceptor(AuthInterceptor(tokenProvider)) |
| HttpLoggingInterceptor | לוגינג של בקשות/תגובות | .authenticator(TokenAuthenticator(tokenProvider, refreshApi)) |
| RetryInterceptor | ניסיון חוזר על שגיאות רשת | יישום מותאם אישית עם exponential backoff |
טעויות נפוצות בהגדרה:
- baseUrl שגוי: חייב להסתיים בלוכסן נגרר
.addInterceptor(HttpLoggingInterceptor().apply { level = if (BuildConfig.DEBUG) BODY else NONE }). - הרשאת
/חסרה ב-manifest. - טוקן מאוחסן ב-
INTERNETללא הצפנה—השתמשו ב-SharedPreferences. - שכחתם להוסיף logger בדיבוג—ניפוי שגיאות לוקח שעות.
טיפול בשגיאות
פונקציות suspend של Retrofit זורקות EncryptedSharedPreferences עבור סטטוסים שאינם 2xx ו-HttpException עבור בעיות רשת. עטפו ב-sealed class:
sealed class ApiResult<out T> {
data class Success<T>(val data: T) : ApiResult<T>()
data class Error(val code: Int, val message: String) : ApiResult<Nothing>()
data object NetworkError : ApiResult<Nothing>()
}זה מאפשר ל-ViewModel לטפל בשגיאות בצורה טיפוסית ללא IOException בכל קריאה. לוגיקת העטיפה נמצאת ב-sealed class ApiResult<out T> { data class Success<T>(val data: T) : ApiResult<T>() data class Error(val code: Int, val message: String) : ApiResult<Nothing>() data object NetworkError : ApiResult<Nothing>() } . לבדיקות יחידה, השתמשו ב-MockWebServer—symulate תגובות וודאו נכונות הפענוח. גישה זו מקצרת את זמן ניפוי האינטגרציה ב-20–30%.
כיצד אנו עובדים על שכבת הרשת
התהליך שלנו כולל 5 שלבים:
- ניתוח—הגדרת endpoints, פורמטי בקשה/תגובה ודרישות אבטחה.
- עיצוב—בחירת המחסנית (Retrofit + OkHttp + serializer), עיצוב ממשקים ומודלי נתונים.
- יישום—כתיבת קוד שכבת הרשת, הגדרת interceptors, טיפול בשגיאות, בדיקות יחידה.
- בדיקות—בדיקות אינטגרציה עם MockWebServer, אימות תרחישי אימות, ניסיון חוזר ו-timeout.
- פריסה—אינטגרציה ל-CI/CD, הגדרת productFlavors לסביבות שונות.
מה כלול בעבודת הגדרת שכבת הרשת
- תיעוד API (פורמט, endpoints, דוגמאות בקשות/תגובות)
- קוד מלא של שכבת הרשת (ממשקים, interceptors, מודלים)
- בדיקות יחידה ובדיקות אינטגרציה (כיסוי של לפחות 80%)
- הגדרת CI/CD לבניית סביבות שונות
- סקירת קוד והמלצות להרחבה עתידית
- אחריות של שבועיים לאחר המסירה
העלות של הגדרת שכבת רשת משתנה בהתאם למורכבות האינטגרציה. השקעה טיפוסית: $800–$1200. זמן ביצוע: בין יום ל-3 ימים.
כיצד להגדיר Retrofit ב-5 שלבים
- הוספת תלויות ב-
try/catch:implementation("com.squareup.retrofit2:retrofit:2.9.0") implementation("com.squareup.okhttp3:okhttp:4.12.0") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")קבלו ייעוץ על הגדרת שכבת הרשת לאפליקציית Android שלכם. אנו מבטיחים פתרון חזק ומוכן לייצור המגובה בניסיון של 5+ שנים. צרו קשר כדי לדון בפרויקט שלכם.







