<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Lahiru Jayawickrama </title>
    <description>The latest articles on DEV Community by Lahiru Jayawickrama  (@stargatex).</description>
    <link>https://dev.to/stargatex</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1180008%2F0444dfbc-2a77-4ab0-a8e5-b1031bf46856.png</url>
      <title>DEV Community: Lahiru Jayawickrama </title>
      <link>https://dev.to/stargatex</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/stargatex"/>
    <language>en</language>
    <item>
      <title>Konsist: Protect Kotlin Multiplatform projects from architecture guidelines violations.</title>
      <dc:creator>Lahiru Jayawickrama </dc:creator>
      <pubDate>Sun, 08 Oct 2023 12:50:02 +0000</pubDate>
      <link>https://dev.to/stargatex/konsist-protect-kotlin-multiplatform-projects-from-architecture-guidelines-violations-32pc</link>
      <guid>https://dev.to/stargatex/konsist-protect-kotlin-multiplatform-projects-from-architecture-guidelines-violations-32pc</guid>
      <description>&lt;p&gt;Step-by-step instructions on integrating &lt;strong&gt;Konsist&lt;/strong&gt; with &lt;strong&gt;Kotlin Multiplatform Mobile&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let’s say you have created a project architecture and you expect your team members to follow the architecture guidelines. But there might be a developer who does not follow the guidelines strictly always. Depending on the scope of the project, developers may get reassigned, or teams may be divided into multiple small teams where they must focus on specific modules. So most of the team members will not have a holistic view of the project and with time, things can get messy.&lt;/p&gt;

&lt;p&gt;And here comes the Linter tool to save your day. Even though it won’t solve your personal debt and problems, it certainly prevents you from accumulating technical debt and also provides visibility into your code health.&lt;/p&gt;

&lt;p&gt;So to have consistency through the project structure and to test whether the project architecture guideline hasn’t been violated we can use an architectural linter called &lt;strong&gt;Konsist&lt;/strong&gt;. Konsist is a Kotlin static code analyzer that supports Kotlin-based projects including Android, Kotlin Multiplatform, and Spring. Although this library is in its early stages of development, it covers the problems and usecases we see every day today.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Konsist&lt;/strong&gt; offers two types of checks: Declaration Checks, which test for declaration-level violations, and Architectural Checks, which test for architectural guidelines and boundaries.&lt;/p&gt;

&lt;p&gt;Without further delay, let’s dive right in.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Prerequisites&lt;/strong&gt;
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://kotlinlang.org/docs/multiplatform-mobile-getting-started.html"&gt;#Kotlin Multiplatform Mobile Project&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://docs.konsist.lemonappdev.com/getting-started/readme"&gt;#Konsist&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For this example, I’m using a Multi-Module Kotlin Multiplatform Mobile project with the following structure. Alternatively, you can use Kotlin Multiplatform Mobile’s default structure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hgF34I3k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2A5Czgp5Pxyi0UCEtUOBx9gw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hgF34I3k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2A5Czgp5Pxyi0UCEtUOBx9gw.png" alt="" width="800" height="800"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Multi-Module KMM&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Configuration&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;As a first step, we’ll create a new module for the Konsist Test that separates the &lt;em&gt;konsist test&lt;/em&gt; from the &lt;em&gt;unit test&lt;/em&gt; to improve readability.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Right click on the shared module.&lt;/li&gt;
&lt;li&gt;Select &lt;em&gt;New&lt;/em&gt; then &lt;em&gt;Module&lt;/em&gt; to open the &lt;em&gt;Create New Module&lt;/em&gt; window.&lt;/li&gt;
&lt;li&gt;Select the Kotlin &lt;em&gt;Multiplatform Shared Module&lt;/em&gt; Template&lt;/li&gt;
&lt;li&gt;Enter your desired module name. Ex: &lt;em&gt;:shared:konsisttest.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Name your package. The rest is the same as the following image, so click &lt;em&gt;Finish&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HdkaVlPF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AqBhryHjPTsHTrQRQv_JZyg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HdkaVlPF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AqBhryHjPTsHTrQRQv_JZyg.png" alt="" width="800" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sLWM1rJW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AApft1p-1mdgJSxm9dVzZZQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sLWM1rJW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AApft1p-1mdgJSxm9dVzZZQ.png" alt="" width="800" height="542"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will then be able to see your new module on the project as follows.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---IxzyvQt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AqkdJUQYdd0AAn2gTVB5xcg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---IxzyvQt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AqkdJUQYdd0AAn2gTVB5xcg.png" alt="" width="800" height="986"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Dependency&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Add &lt;em&gt;mavenCentral&lt;/em&gt; repository&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;repositories {
    //...
    mavenCentral()
    //...    
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Next, we will configure the Gradle file for :shared:konsisttest.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Remove the Android Gradle plugin from the &lt;em&gt;:shared:konsisttest&lt;/em&gt; module’s Gradle, along with its corresponding ‘&lt;em&gt;android()&lt;/em&gt;’ Kotlin Target&lt;/li&gt;
&lt;li&gt;Add the ‘&lt;em&gt;jvm()&lt;/em&gt;’ Kotlin Target and ‘&lt;em&gt;jvmTest&lt;/em&gt;’ source set.&lt;/li&gt;
&lt;li&gt;Add the Konsist dependency to ‘&lt;em&gt;jvmTest&lt;/em&gt;’ in the &lt;em&gt;:shared:konsisttest&lt;/em&gt; module’s Gradle.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val jvmTest by getting {
    dependencies {
        implementation("com.lemonappdev:konsist:{VERSION}")
    }
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Following these steps, create a file in your ‘jvmTest’ source set that will be used to write test methods.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select &lt;em&gt;New&lt;/em&gt; then &lt;em&gt;Directory&lt;/em&gt; from the right-click menu on the module (&lt;em&gt;:shared:konsisttest&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;Create the source set directory (&lt;em&gt;src/jvmTest/kotlin&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;Create your package (Ex: &lt;em&gt;com.stargatex.mt.lahiru.konsisttest&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;Create a file (Ex: &lt;em&gt;AppKonsistTest&lt;/em&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--32-mx0XL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AVeZKzj8iNKWUiK6y0yOfrA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--32-mx0XL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AVeZKzj8iNKWUiK6y0yOfrA.png" alt="" width="800" height="598"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Directory creation&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tLonvwLt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AHsVQ1bmGsebmMVaXX8goSA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tLonvwLt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AHsVQ1bmGsebmMVaXX8goSA.png" alt="" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;jvmTest source set directory&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1GeAOnhL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AW3pPL-vlRPAXP_Gs8JHEtQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1GeAOnhL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AW3pPL-vlRPAXP_Gs8JHEtQ.png" alt="" width="800" height="460"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Package creation&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kqSxtHyc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2A8UZWG0QuTqEkO58Krbyk9g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kqSxtHyc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2A8UZWG0QuTqEkO58Krbyk9g.png" alt="" width="800" height="230"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Test file creation&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Implementation
&lt;/h4&gt;

&lt;p&gt;First let’s take a look at the steps for ‘&lt;em&gt;declaration check&lt;/em&gt;’.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;As a first step, we need to determine the scope, which includes files from an entire project, a module, a package, or just one Kotlin file. (&lt;a href="https://docs.konsist.lemonappdev.com/writing-tests/koscope"&gt;&lt;em&gt;Create the scope&lt;/em&gt;&lt;/a&gt;&lt;em&gt;)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Scope for Kotlin files availble in the project
Konsist.scopeFromProject() 
// Scope for Kotlin files availble in the 'app' module
Konsist.scopeFromModule("app")
// Scope for Kotlin files availble in the 'test' source set
Konsist.scopeFromSourceSet("test")
// Scope for Kotlin files availble for production code
Konsist.scopeFromProduction()

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;We then query all items in the scope and filter them according to our needs. (&lt;a href="https://docs.konsist.lemonappdev.com/writing-tests/declaration-query-and-filter"&gt;&lt;em&gt;Query and Filter&lt;/em&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Finally, we define the assertion. (&lt;a href="https://docs.konsist.lemonappdev.com/writing-tests/declaration-assert"&gt;&lt;em&gt;Assert&lt;/em&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--799l6uUg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2APe5WXu8I_DxTN2DZSYAHVQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--799l6uUg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2APe5WXu8I_DxTN2DZSYAHVQ.png" alt="" width="800" height="823"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let’s examine the steps for ‘&lt;em&gt;architecture check&lt;/em&gt;’.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;As a first step, we need to determine the scope.&lt;/li&gt;
&lt;li&gt;Next, we define layers of the project and assertions using the ‘&lt;em&gt;assertArchiteture&lt;/em&gt;’ method
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Konsist
    .scopeFromProduction() // Define the scope
    .assertArchitecture { // Assert architecture
        // Define layers
        val domain = Layer("Domain", "com.stargatex.mt.kmm.lahiru.shared.domain..")

        // Define the relations between each layer for architecture assertions
        domain.dependsOnNothing()
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rZG_aSVQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2ABm57jsFLq8kKAPiBajnUzQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rZG_aSVQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2ABm57jsFLq8kKAPiBajnUzQ.png" alt="" width="800" height="993"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lastly, both ‘&lt;em&gt;declaration check&lt;/em&gt;’ and ‘&lt;em&gt;architecture check&lt;/em&gt;’ of Konsist test code will be executed as unit tests.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  Use cases
&lt;/h4&gt;

&lt;p&gt;Here are some examples of use cases you might need to test in a project.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;For more examples, They have provided good examples that you can use as inspiration on how this can be used (&lt;a href="https://docs.konsist.lemonappdev.com/inspiration/snippets"&gt;Snippets&lt;/a&gt; /  &lt;a href="https://docs.konsist.lemonappdev.com/getting-started/getting-started/articles"&gt;Articles&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;All right, that’s it. Using this library correctly could mean you don’t accumulate technical debt resulting from architectural violations and those violations might be found in reviews rather than going unnoticed. I have begun integrating this library into my current organization’s Kotlin Android and Kotlin Multiplatform Mobile projects. It was a pleasant experience thanks to good documentation, seamless integration abilities, and extensibility for custom needs.&lt;/p&gt;

&lt;p&gt;I hope you found this useful. Until next time 🙏 👋&lt;/p&gt;

</description>
      <category>kotlinmultiplatform</category>
      <category>staticcodeanalysis</category>
      <category>konsist</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Token refresh implementation with Ktor in Kotlin Multiplatform Mobile</title>
      <dc:creator>Lahiru Jayawickrama </dc:creator>
      <pubDate>Sun, 13 Aug 2023 10:58:31 +0000</pubDate>
      <link>https://dev.to/stargatex/token-refresh-implementation-with-ktor-in-kotlin-multiplatform-mobile-823</link>
      <guid>https://dev.to/stargatex/token-refresh-implementation-with-ktor-in-kotlin-multiplatform-mobile-823</guid>
      <description>&lt;p&gt;Hey everyone, This is a short step-by-step guide for integrating a token refresh implementation with Ktor in Kotlin Multiplatform Mobile. &lt;a href="https://ktor.io/"&gt;&lt;strong&gt;Ktor&lt;/strong&gt;&lt;/a&gt; offers an easy and straightforward approach to implementing a token refresh feature and managing the lifecycle of tokens. Without any further delay, let’s dive right in.&lt;/p&gt;

&lt;p&gt;In this example, I will also be using &lt;a href="https://insert-koin.io/"&gt;&lt;strong&gt;Koin&lt;/strong&gt;&lt;/a&gt; DI framework to get &lt;strong&gt;HttpClientEngine&lt;/strong&gt; (&lt;em&gt;platform-specific engine for processing network requests&lt;/em&gt;) and a secure store for storing and retrieving tokens (&lt;em&gt;called&lt;/em&gt; &lt;em&gt;UserManager&lt;/em&gt;).&lt;/p&gt;

&lt;h4&gt;
  
  
  Prerequisites
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://insert-koin.io/docs/quickstart/kmm/"&gt;Kotlin Multiplatform Mobile with Koin&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ktor.io/"&gt;ktor&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/AAkira/Napier"&gt;Napier&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Add dependencies&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Nyzgk1_d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AZs0Rz0ZByB1NIby0o8OUdQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Nyzgk1_d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AZs0Rz0ZByB1NIby0o8OUdQ.png" alt="" width="800" height="772"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Implementation
&lt;/h4&gt;

&lt;p&gt;First we will assume that we have configured Koin DI for our KMM project. Then we will configure the platform specific Ktor &lt;strong&gt;HttpClientEngine&lt;/strong&gt; with &lt;strong&gt;OkHttp&lt;/strong&gt; for Android and &lt;strong&gt;Darwin&lt;/strong&gt; for IOS.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;commonMain&lt;/strong&gt; define your expected declaration for &lt;strong&gt;HttpClientEngine&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VLNjIUWg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AJo5PDX7L76i6MfnNUxTTSw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VLNjIUWg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AJo5PDX7L76i6MfnNUxTTSw.png" alt="" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;AndroidMain&lt;/strong&gt; , define your platform-specific actual declaration for the &lt;strong&gt;HttpClientEngine&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JaNRNpms--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AU4As6l6OvcARBmOVGFldIg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JaNRNpms--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AU4As6l6OvcARBmOVGFldIg.png" alt="" width="800" height="574"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;IosMain,&lt;/strong&gt; define your platform-specific actual declaration for the &lt;strong&gt;HttpClientEngine&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jKE18_zh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2ALhVrIl4k2y8YYCDVMjqrtA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jKE18_zh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2ALhVrIl4k2y8YYCDVMjqrtA.png" alt="" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then add your declaration to the &lt;strong&gt;startKoin&lt;/strong&gt; function.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QsZqwD0b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AjJQuRQ9d1UDu5BnemmUMnQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QsZqwD0b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AjJQuRQ9d1UDu5BnemmUMnQ.png" alt="" width="800" height="557"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Token Refresh
&lt;/h4&gt;

&lt;p&gt;Our next step will be to configure the token refresh feature using the &lt;strong&gt;refreshTokens&lt;/strong&gt; ktor API.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--P5PGZgqF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AskJwwrF0zVvRs7WURuo1ig.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P5PGZgqF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AskJwwrF0zVvRs7WURuo1ig.png" alt="" width="800" height="468"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Full &lt;strong&gt;HttpClient&lt;/strong&gt; configuration,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pUbIe2R2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2ALDnqp7ajbM-xv4O70rr4NQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pUbIe2R2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2ALDnqp7ajbM-xv4O70rr4NQ.png" alt="" width="800" height="1078"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Accordingly, what this code does is. A request will be made with a token to the protected API. API will respond with a 401 unauthorized response if the token is expired, and this will trigger the refreshTokens block to retrieve new tokens. Once the token has been retrieved, it will request the same protected API that previously responded with a 401 unauthorized response.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Code Snippets — &lt;a href="https://gist.github.com/stargatex/7678d15a6e7bef0b3cf1262f38a7a31d"&gt;https://gist.github.com/stargatex/7678d15a6e7bef0b3cf1262f38a7a31d&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I hope you found this useful. Until next time 🙏 👋&lt;/p&gt;

</description>
      <category>refreshtoken</category>
      <category>ktor</category>
      <category>koin</category>
      <category>kotlinmultiplatform</category>
    </item>
    <item>
      <title>Configure SonarQube in a Android Project using Docker</title>
      <dc:creator>Lahiru Jayawickrama </dc:creator>
      <pubDate>Thu, 25 Aug 2022 18:19:12 +0000</pubDate>
      <link>https://dev.to/stargatex/configure-sonarqube-in-a-android-project-using-docker-4245</link>
      <guid>https://dev.to/stargatex/configure-sonarqube-in-a-android-project-using-docker-4245</guid>
      <description>&lt;p&gt;Hey everyone,&lt;/p&gt;

&lt;p&gt;This is a step-by-step guide for integrating SonarQube for Android project using docker. Without any further delay, let’s dive right in.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;What is SonarQube?&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;According to the official documentation,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“SonarQube is an automatic code review tool to detect bugs, vulnerabilities, and code smells in your code.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;What is Docker?&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Docker simplifies the process of developing applications. It provides a set of tools that allow developers to create, test and deploy applications in loosely isolated environments.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Prerequisites&lt;/strong&gt;
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;Docker (&lt;a href="https://cutt.ly/WG4feRX"&gt;https://cutt.ly/WG4feRX&lt;/a&gt;)&lt;br&gt;&lt;br&gt;
 Android Development Environment&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Starting SonarQube&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Start the Docker engine and log in to your account. Next, Install the SonarQube image and run it with the below command in the terminal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jNFZtL_d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/994/1%2AqnYnRMhwLxdB9uhRT50gJQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jNFZtL_d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/994/1%2AqnYnRMhwLxdB9uhRT50gJQ.png" alt="" width="800" height="32"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this, it will print the container ID once SonarQube is up and running successfully. To access it: “&lt;a href="http://localhost:9000/"&gt;http://localhost:9000/&lt;/a&gt;”. The default user and password is “admin”&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Configure a SonarQube Project.&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Once you logged in to your SonarQube instance. Select the project creation option as “&lt;em&gt;Manually&lt;/em&gt;” to run the scan from your local codebase.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lRpdsKcy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2Aq2w3NqI-2bUkXaP8fO_f9Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lRpdsKcy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2Aq2w3NqI-2bUkXaP8fO_f9Q.png" alt="" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To set up the project provide a Display Name and Project Key.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nkB91Fuo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2APHsY11o59Q8YaNyruVGpZQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nkB91Fuo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2APHsY11o59Q8YaNyruVGpZQ.png" alt="" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, provide “&lt;em&gt;Locally&lt;/em&gt;” as the way you want to analyse your repository.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6br_QqPk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AhW9UAtAYqI2oIIMqWOg8Dw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6br_QqPk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AhW9UAtAYqI2oIIMqWOg8Dw.png" alt="" width="800" height="327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To authenticate the user to perform the analysis, generate the token by providing a name&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vhyIUxCz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AmQmeQ4pH5bZggM3-zMUNJg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vhyIUxCz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AmQmeQ4pH5bZggM3-zMUNJg.png" alt="" width="800" height="303"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Performing an analysis&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Add the sonar scanner plugin in your Project level Gradle.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wwAQ4acV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2A9H2WknP0TmlMqR6XXRYt_g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wwAQ4acV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2A9H2WknP0TmlMqR6XXRYt_g.png" alt="" width="800" height="205"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, in your App level Gradle configure as below&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1bX_Pl35--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AKAF69JuMqpYXgDrBHrZYMw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1bX_Pl35--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AKAF69JuMqpYXgDrBHrZYMw.png" alt="" width="800" height="570"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Replace the &lt;em&gt;PROJECT-NAME, PROJECT-KEY,&lt;/em&gt; and &lt;em&gt;TOKEN&lt;/em&gt; with the generated and provided values in the previous steps. Inclusion and exclusion depend on your requirement.&lt;/p&gt;

&lt;p&gt;Sync your Gradle and run the following command on your terminal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3v1RPvbY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/504/1%2AOx-xr37H0m5d3z0OuU2O7g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3v1RPvbY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/504/1%2AOx-xr37H0m5d3z0OuU2O7g.png" alt="" width="504" height="52"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the build is successful access your project at “&lt;a href="http://localhost:9000/projects"&gt;http://localhost:9000/projects&lt;/a&gt;” to view your project report&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--d9Qq4bpx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AHIwbljjok71XfHUluv-D2w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--d9Qq4bpx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AHIwbljjok71XfHUluv-D2w.png" alt="" width="800" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s it. Now you can review your project and improve your code quality. But this is a basic SonarQube Android setup. There are a lot of things you can do with SonarQube. Learn it, research it &amp;amp; share it. I hope you found this useful. Until next time 🙏 👋&lt;/p&gt;

</description>
      <category>codequality</category>
      <category>android</category>
      <category>sonarqube</category>
    </item>
  </channel>
</rss>
