{"id":19600632,"url":"https://github.com/stanwood/framework-network-android","last_synced_at":"2025-08-20T23:12:49.204Z","repository":{"id":56067408,"uuid":"114127226","full_name":"stanwood/framework-network-android","owner":"stanwood","description":"A set of hopefully useful classes for common networking use cases.","archived":false,"fork":false,"pushed_at":"2024-02-14T16:46:00.000Z","size":307,"stargazers_count":12,"open_issues_count":1,"forks_count":3,"subscribers_count":8,"default_branch":"develop","last_synced_at":"2025-04-27T16:42:51.952Z","etag":null,"topics":["android","library","okhttp"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stanwood.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-12-13T13:56:31.000Z","updated_at":"2025-03-30T00:44:15.000Z","dependencies_parsed_at":"2025-04-27T16:42:49.041Z","dependency_job_id":null,"html_url":"https://github.com/stanwood/framework-network-android","commit_stats":null,"previous_names":[],"tags_count":27,"template":false,"template_full_name":null,"purl":"pkg:github/stanwood/framework-network-android","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stanwood%2Fframework-network-android","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stanwood%2Fframework-network-android/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stanwood%2Fframework-network-android/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stanwood%2Fframework-network-android/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stanwood","download_url":"https://codeload.github.com/stanwood/framework-network-android/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stanwood%2Fframework-network-android/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271400259,"owners_count":24752830,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-20T02:00:09.606Z","response_time":69,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","library","okhttp"],"created_at":"2024-11-11T09:15:42.963Z","updated_at":"2025-08-20T23:12:49.186Z","avatar_url":"https://github.com/stanwood.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Release](https://jitpack.io/v/stanwood/framework-network-android.svg?style=flat-square)](https://jitpack.io/#stanwood/framework-network-android)\n[![Build Status](https://app.bitrise.io/app/983e6342cc5e0e24/status.svg?token=QtXUf2lbVhJrANROaTkluQ\u0026branch=develop)](https://app.bitrise.io/app/983e6342cc5e0e24)\n[![API](https://img.shields.io/badge/API-16%2B-blue.svg?style=flat)](https://android-arsenal.com/api?level=16)\n\n# stanwood Network Utilities (Android)\n\nA set of hopefully useful classes for common networking use cases.\n\n## Import\n\nThe stanwood Network Utilities are hosted on JitPack. Therefore you can simply\nimport them by adding\n\n```groovy\nallprojects {\n    repositories {\n        ...\n        maven { url \"https://jitpack.io\" }\n    }\n}\n```\n\nto your project's `build.gradle`.\n\nThen add this to you app's `build.gradle`:\n\n```groovy\ndependencies {\n    implementation 'com.github.stanwood.framework-network-android:arch:\u003cinsert latest version here\u003e' // aar version available as well\n    implementation 'com.github.stanwood.framework-network-android:cache:\u003cinsert latest version here\u003e' // aar version available as well\n    implementation 'com.github.stanwood.framework-network-android:core:\u003cinsert latest version here\u003e' // aar version available as well, automatically included when pulling in one of the other libraries\n}\n```\n\n## Usage\n\nRefer to the extensive javadoc of the provided classes for details on how to\nuse them. Right now there are solutions for the following use cases:\n\n- handle offline situations and caching when using OkHttp (`cache` library)\n- generic token based authentication handling with OkHttp (`auth` library)\n- generic network related utility classes (some specific to apps developed over here at _stanwood_) (`core`library)\n\n### cache\n\nSee javadoc of the classes in the library.\n\n### auth\n\nThe `auth` library contains classes for handling token based authentication with OkHttp. Generally this is done via Authenticators and Interceptors.\n\nIf you are using plain username/password authentication you obviously won't need the following classes as there will never be a need to refresh the data and authentication is straightforward.\n\nIntegration into both existing means of token retrieval as well as from scratch is simple.\n\nFirst you need to implement both `TokenReaderWriter` and `AuthenticationProvider`. The first is used for reading (to find out whether we are still using an old token) and writing (for authentication) tokens from/to requests. The second provides means to get authentication data (such as tokens and sign-in status) and should also be used by you directly during initial authentication (i.e. right after user log-in/registration) for consistency reasons. The `AuthenticationProvider` usually makes use of an `AuthManager` to store retrieved login data. You can get a sample implementation of such an `AuthManager` by using the _stanwood Android Studio Plugin_ (see **AuthManager** section further below). Refer to the javadoc of the aforementioned classes for more details on how to implement these interfaces.\n\nIn the future optional modules will provide implementations for common use cases.\n\nThen create an instance of `io.stanwood.framework.network.auth.Authenticator`:\n\n```java\nAuthenticator authenticator = new Authenticator(\n    authenticationProvider,\n    tokenReaderWriter,\n    null\n);\n```\n\nAnd an instance of `AuthInterceptor`:\n\n```java\nAuthInterceptor authInterceptor = new AuthInterceptor(\n    new ConnectionState(appContext),\n    authenticationProvider,\n    tokenReaderWriter,\n    null\n);\n```\n\nConstruct an `OkHttpClient` and pass the interceptor and the authenticator:\n\n```java\nnew OkHttpClient.Builder()\n        .authenticator(authenticator) // takes care of 401 (invalid token, get fresh one and retry)\n        .addInterceptor(authInterceptor) // adds authentication data to every request\n        .build();\n```\n\nThat's it. When using this `OkHttpClient` instance you'll benefit from fully transparent token handling.\n\n__Hint 1:__ *If your app uses multiple authentication methods make sure to\nimplement an own subclass of `AuthenticationProvider` for each method and use\nan own `OkHttpClient` for each!*\n\n__Hint 2:__ *In case you are using OkHttp/Retrofit to retrieve tokens: As the\n`Authenticator` locks all other `Authenticators` and `AuthInterceptors` with\nthe same `AuthenticationProvider` it makes sense to provide an own\n`OkHttpClient` instance (and thus also an own Retrofit instance if you use it)\nfor all calls you need to receive new tokens. If try to serve all calls with\nthe same client instance, it may happen that you run out of connections/threads\nwhile trying to get a token because there might be a whole slew of requests\nalready waiting for that token call to succeed. Alternatively you can also try\nto increase the executor pool size, but this is not recommended as you never\nknow for sure how many requests are executed at a given point in time - and you\ndefinitely always want a thread ready for your token request.*\n\n__Hint 3:__ *Rules of thumb (exceptions apply):* \n1. one `AuthenticationProvider` per authentication method (however you can also try to wrap multiple ones in one `AuthenticationProvider` which can ease DI quite a bit - we recommend to define each method in one provider and then pass those providers to the wrapper provider to have clean separate implementations)\n2. one `TokenReaderWriter` and `AuthManager` per Api\n\n#### A note on authentication exception handling\n\nThe library provides an own exception class called `AuthenticationException`.\nYou can listen for this class in your Retrofit\n`Callback.onFailure(Call, Throwable)` to check for authentication related\nerrors.\n\nIf you're having problems retrieving a token in the `AuthenticationProvider`\n(e.g. due to an invalid refresh token) always try to resolve those issues there\nas well if possible. Throwing an `AuthenticationException` should just be a\nlast resort.\n\nAlternatively you can also subclass the `Authenticator` class and override\n`onAuthenticationFailed()` if you want to trigger special handling for failed\nauthentication from which we couldn't recover with our default handling. This\nusually tends to be a bit harder to get right as it expects you to modify the\nfailed request directly without any means of intercepting the response. Thus\nhandling token retrieval issues should preferably handled in the\n`AuthenticationProvider` as explained above.\n\n#### AuthManager\n\nThe [stanwood Android Plugin](https://github.com/stanwood/android-studio-plugin/) provides a template for an `AuthManager` which takes care of storing and providing authentication info like tokens and usernames. It will automatically be generated for you when running the _NetworkModule_ assistant in the _New -\u003e Stanwood_ menu.\n\nYou can extend it with authentication types for all your authentication providers for easy and streamlined authentication state handling.\n\n### core\n\nThe `util` package contains generic network related classes. The `util.stanwood`\npackage contains classes for apps developed over here at _stanwood_.\n\n## Quick start for simple networking in our own stanwood apps\n\nYou can find an example [over here](https://github.com/stanwood/architecture_sample_github_android) (private for now).\n\nAdd the following dependencies (replace versions here with current versions):\n\n```groovy\ndef retrofit_version = '2.5.0'\nimplementation \"com.squareup.retrofit2:retrofit:$retrofit_version\"\nimplementation \"com.squareup.retrofit2:converter-gson:$retrofit_version\"\nimplementation \"com.squareup.retrofit2:adapter-rxjava2:$retrofit_version\"\n\nimplementation 'com.google.code.gson:gson:2.8.5'\n\nimplementation 'com.squareup.okhttp3:logging-interceptor:3.13.1'\n```\n\nWrite an interface class with Retrofit API definition and put it in the `datasources.net.\u003capi\u003e` package:\n\n```kotlin\ninterface GithubApi {\n\n    @Headers(\n        \"Accept: application/vnd.github.mercy-preview+json\"\n    )\n    @GET(\"search/repositories\")\n    fun getMostPopularAndroidRepositories(\n        @Query(\"q\") query: String = \"topic:Android\",\n        @Query(\"sort\") sort: String = \"stars\",\n        @Query(\"order\") order: String = \"desc\"\n    ): Single\u003cSearchRepositoriesResponse\u003e  // this is for RX\n}\n```\n\nTo define models classes use curl or postman or insomnia to execute the request and get a sample response. Then use the _JSON to Kotlin Class_ Android Studio plugin and paste the response there. We use GSON for de-/serialization of JSON so use the proper annotation settings in the plugin. Configure the plugin so that it uses `val`s and try the _Auto determine Nullable or not from JSON Value_ setting (make sure to revisit the generated classes later to check whether the properties are fine). Additionally switch on _Enable Map Type when JSON field key is primitive type_ in _other_ settings.\n\nPut the generated classes in the `datasources.net.\u003capi\u003e.model` package.\n\nThen define a `NetworkModule` similar to the following one:\n\n```kotlin\n@Module\nclass NetworkModule {\n\n    @Provides\n    @Singleton\n    fun provideGson(): Gson = GsonBuilder()\n        .setDateFormat(\"YYYY-MM-DDTHH:MM:SSZ\")\n        .create()\n\n    @Provides\n    fun provideHttpLoggingInterceptor(): HttpLoggingInterceptor =\n        HttpLoggingInterceptor().apply {\n            level = HttpLoggingInterceptor.Level.BASIC\n        }\n\n    @Provides\n    fun provideGithubOkHttpClient(\n        httpLoggingInterceptor: HttpLoggingInterceptor,\n        application: Application\n    ): OkHttpClient {\n        val client = OkHttpClient.Builder()\n            .readTimeout(TIMEOUT_MS, TimeUnit.MILLISECONDS)\n            .connectTimeout(TIMEOUT_MS, TimeUnit.MILLISECONDS)\n            .cache(Cache(application.cacheDir, CACHE_SIZE))\n            .addInterceptor(TestfairyHttpInterceptor()) // only if you use the stanwood analytics library\n            .addInterceptor(StanwoodHeaderInterceptor(\n                // make sure that app name is language independent, maybe use a flavor or a static BuildConfig String\n                application.getString(R.string.app_name),\n                BuildConfig.VERSION_NAME,\n                BuildConfig.BUILD_TYPE\n            )\n\n        if (BuildConfig.DEBUG) {\n            client.addInterceptor(httpLoggingInterceptor)\n        }\n\n        return client.build()\n    }\n\n    @Provides\n    @Singleton\n    fun provideGithubRetrofit(\n        okHttpClient: OkHttpClient,\n        gson: Gson\n    ): Retrofit = Retrofit.Builder()\n        .baseUrl(BuildConfig.GITHUB_API)\n        .client(okHttpClient)\n        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())\n        .addConverterFactory(GsonConverterFactory.create(gson))\n        .build()\n        \n    @Provides\n    fun provideGithubApi(retrofit: Retrofit): GithubApi = retrofit.create(GithubApi::class.java)\n}\n```\n\nAdd the `NetworkModule` as an _include_ to your `AppModule` and you can start injecting your API class to perform network requests.\n\n## Contribute\n\nThis project follows the [Android Kotlin Code Style](https://android.github.io/kotlin-guides/style.html)\nfor all Kotlin classes. We use\n[ktlint](https://github.com/shyiko/ktlint) for automated checks.\n\nThe [ktlint-gradle-plugin](https://github.com/JLLeitschuh/ktlint-gradle) is already integrated into this project which means you need nearly no setup on your end.\n\nJust execute those two calls to configure your IDE *for this project* and add a pre-commit hook to do the checking (and if necessary formatting for you).\n\n```bash\n./gradlew ktlintApplyToIdea\n./gradlew addKtlintFormatGitPreCommitHook\n```\n\nMake sure to check the _Run Git hooks_ checkbox if you commit via Android Studio (should be set by default).\n\nLast thing to do is setting line length to 140 (Preferences -\u003e Editor -\u003e Code Style) - unfortunately `ktlintApplyToIdea` can't do that for you.\n\nThe CI will check formatting as well and won't allow non style conform commits to be merged.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstanwood%2Fframework-network-android","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstanwood%2Fframework-network-android","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstanwood%2Fframework-network-android/lists"}