Production-grade Android networking SDK built in Kotlin on top of Retrofit, OkHttp, Coroutines, and Flow.
Add JitPack to your root repository list:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven("https://jitpack.io")
}
}Add the SDK dependency:
dependencies {
implementation("com.github.imrun.SimpleNetworking:network-sdk:<tag>")
}Replace <tag> with a GitHub release tag such as 1.0.0.
SimpleNetworking
├── build.gradle.kts
├── gradle.properties
├── settings.gradle.kts
├── README.md
└── network-sdk
├── build.gradle.kts
├── consumer-rules.pro
├── proguard-rules.pro
└── src/main
├── AndroidManifest.xml
└── java/com/simplenetworking/sdk
├── auth
│ └── TokenAuthenticator.kt
├── core
│ ├── ApiServiceFactory.kt
│ ├── NetworkClient.kt
│ └── NetworkConfig.kt
├── error
│ ├── ApiErrorResponse.kt
│ ├── ErrorMapper.kt
│ └── NetworkException.kt
├── interceptor
│ ├── ErrorInterceptor.kt
│ ├── HeaderInterceptor.kt
│ ├── LoggingInterceptor.kt
│ ├── RateLimitInterceptor.kt
│ ├── RetryInterceptor.kt
│ └── TokenInterceptor.kt
├── model
│ └── ApiErrorResponse.kt
├── monitor
│ └── NetworkMonitor.kt
├── pagination
│ ├── PagingState.kt
│ └── Paginator.kt
├── result
│ └── ApiResult.kt
└── util
├── FlowApiCall.kt
└── SafeApiCall.kt
└── sample-app
├── build.gradle.kts
└── src/main
├── AndroidManifest.xml
├── java/com/simplenetworking/sample
│ ├── MainActivity.kt
│ ├── MainViewModel.kt
│ ├── SampleApplication.kt
│ └── data
│ ├── PostDto.kt
│ ├── SampleApi.kt
│ └── SampleRepository.kt
└── res
├── layout/activity_main.xml
└── values
├── strings.xml
└── themes.xml
NetworkClient.initialize(
baseUrl = "https://api.example.com/",
debug = BuildConfig.DEBUG,
connectTimeout = 30,
readTimeout = 30,
headersProvider = {
mapOf(
"Accept" to "application/json",
"X-App-Version" to "1.0.0"
)
},
tokenProvider = { sessionManager.accessToken },
refreshTokenProvider = { authRepository.refreshToken() },
retryCount = 3,
rateLimitRequests = 10,
rateLimitWindowSeconds = 1
)
NetworkClient.attachNetworkMonitor(applicationContext)interface UserApi {
@GET("users/profile")
suspend fun getProfile(): Response<UserDto>
}
val userApi = NetworkClient.createService<UserApi>()suspend fun loadProfile(): ApiResult<UserDto> {
return NetworkClient.safeApiCall {
userApi.getProfile()
}
}fun observeProfile(): Flow<ApiResult<UserDto>> {
return NetworkClient.flowApiCall {
userApi.getProfile()
}
}viewModelScope.launch {
observeProfile().collect { result ->
when (result) {
is ApiResult.Loading -> showLoading()
is ApiResult.Success -> render(result.data)
is ApiResult.Empty -> showEmptyState()
is ApiResult.Error -> showError(result.exception.message.orEmpty())
}
}
}The included sample-app module shows a real consumer integration:
SampleApplicationinitializesNetworkClientwith a base URL, debug flag, headers provider, and connectivity monitor.SampleApidefines a standard Retrofit interface.SampleRepositorywraps the transport call behind an app-facing boundary.MainViewModelcollectsFlow<ApiResult<PostDto>>.MainActivityrenders loading, success, empty, and error states.AuthDemoActivityshows bearer-token wiring throughtokenProviderand a samplerefreshTokenProvider.
Open the sample-app module in Android Studio and run it on an emulator or device. Tapping Fetch Post calls https://jsonplaceholder.typicode.com/posts/1 through the SDK.
Open Auth Demo to inspect the current bearer token, trigger an authenticated request, expire the local token, and manually invoke the refresh lambda. The sample backend does not return 401, so automatic authenticator retry is configured in code but not triggered by this public endpoint.
val paginator = Paginator<UserDto> { page, cursor ->
val response = userApi.getUsers(page = page ?: 1, cursor = cursor)
val body = response.body() ?: error("Missing response body")
Paginator.PaginationResult(
items = body.items,
endReached = body.nextPage == null && body.nextCursor == null,
nextPage = body.nextPage,
nextCursor = body.nextCursor
)
}debug = truepreserves backend response bodies, HTTP codes, and throwable details where available.debug = falsemaps errors into simplified user-safe messages such asNo Internet Connection,Network Timeout,Server Error,Unauthorized, andUnexpected Error.TokenAuthenticatorretries one failed request after calling the configured refresh lambda on401.RetryInterceptorperforms exponential backoff retries for transient I/O failures.RateLimitInterceptorblocks bursts that exceed the configured request window.
Install the sample app with:
./gradlew :sample-app:installDebug