<?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: Julien Foratier</title>
    <description>The latest articles on DEV Community by Julien Foratier (@jforatier).</description>
    <link>https://dev.to/jforatier</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%2F367223%2F3191d85d-1f18-49ab-86a2-97e7b4992a52.jpg</url>
      <title>DEV Community: Julien Foratier</title>
      <link>https://dev.to/jforatier</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jforatier"/>
    <language>en</language>
    <item>
      <title>Build, Test and Deploy your Android Application📱  with GitHub Actions 🤖</title>
      <dc:creator>Julien Foratier</dc:creator>
      <pubDate>Fri, 26 Nov 2021 08:10:39 +0000</pubDate>
      <link>https://dev.to/jforatier/build-test-and-deploy-your-android-application-with-github-actions-hh1</link>
      <guid>https://dev.to/jforatier/build-test-and-deploy-your-android-application-with-github-actions-hh1</guid>
      <description>&lt;h3&gt;
  
  
  My Workflow
&lt;/h3&gt;

&lt;p&gt;As an Android developer, I would like to put under control the developments of an &lt;a href="https://github.com/boitakub/Bogadex" rel="noopener noreferrer"&gt;oss sandbox application&lt;/a&gt; gathering some practices in a functional application.&lt;/p&gt;

&lt;p&gt;In a craftmanship approach I like to work with practices such as industrialization, continuous quality control, functional orientation and fast delivery.&lt;/p&gt;

&lt;p&gt;You will find in this repo a some practices and patterns on workflow files that I will detail below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Submission Category: Phone Friendly
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Yaml File / Link to Code
&lt;/h3&gt;

&lt;p&gt;In the project you can find different workflow files :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/boitakub/Bogadex/blob/main/.github/workflows/main.yml" rel="noopener noreferrer"&gt;CI Workflow&lt;/a&gt; - Make build, test and quality check&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/boitakub/Bogadex/blob/main/.github/workflows/main.yml" rel="noopener noreferrer"&gt;Release Workflow&lt;/a&gt; - Deal with release control and deployment&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/boitakub/Bogadex/blob/main/.github/workflows/lint.yml" rel="noopener noreferrer"&gt;Super-linter Workflow&lt;/a&gt; - Check all files with common lint rules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is the main &lt;strong&gt;Build workflow&lt;/strong&gt; 👉&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Build

on:
  push:
    branches: [ main ] # Just in case main was not up to date while merging PR
  pull_request:
    types: [ opened, synchronize ]

jobs:
  build-and-test:
    name: Build, Lint and Test
    runs-on: macos-latest
    timeout-minutes: 20

    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Set up our JDK environment
        uses: actions/setup-java@v2
        with:
          distribution: 'adopt'
          java-version: '11'

      - name: Cache Gradle and wrapper
        uses: actions/cache@v2
        with:
          path: |
            ~/.gradle/caches
            ~/.gradle/wrapper
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
          restore-keys: |
            ${{ runner.os }}-gradle-

      # Decode Google services configuration file from secrets
      # - name: Decode google-services.json
      #  env:
      #    FIREBASE_CONFIG: ${{ secrets.FIREBASE_CONFIG }}
      #  run: echo $FIREBASE_CONFIG &amp;gt; app/google-services.json

      # Run emulator
      - name: Run integration test on emulator
        uses: reactivecircus/android-emulator-runner@v2
        with:
          api-level: 29
          script: ./gradlew createDebugCoverageReport --stacktrace

      # Generate jacoco report
      - name: Generate report
        run: ./gradlew jacocoTestReport

      # Upload report
      - name: Upload Reports
        uses: actions/upload-artifact@v2
        if: always()
        with:
          name: reports
          path: |
            /build/coverage-report
            app/build/reports

      # Upload coverage report to Codacy
      - name: Run codacy-coverage-reporter
        uses: codacy/codacy-coverage-reporter-action@v1
        with:
          project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}

  static-analysis:
    name: Execute analyse on code
    continue-on-error: true
    runs-on: ubuntu-latest
    timeout-minutes: 20

    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Set up our JDK environment
        uses: actions/setup-java@v2
        with:
          distribution: 'adopt'
          java-version: '11'

      - name: Cache Gradle and wrapper
        uses: actions/cache@v2
        with:
          path: |
            ~/.gradle/caches
            ~/.gradle/wrapper
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
          restore-keys: |
            ${{ runner.os }}-gradle-

      # Check the code with detekt, you can remove this job if you don't use detekt
      - name: Run detekt Linter
        run: ./gradlew detekt

      # Check the code with ktlint, you can remove this job if you don't use ktlint
      - name: Run Kotlin Linter
        run: ./gradlew ktlintCheck

      # Check the code with Android linter (need assemble)
      - name: Run Android Linter
        run: ./gradlew lint

      # Check the code with Spotless
      - name: Run Spotless
        run: ./gradlew spotlessCheck

  generate-release-apk:
    name: Try generate Releasable
    runs-on: ubuntu-latest
    environment: Release
    timeout-minutes: 20
    needs:
      - build-and-test

    steps:
      - name: Checkout
        uses: actions/checkout@v2
        with:
          fetch-depth: 0

      - name: Set up our JDK environment
        uses: actions/setup-java@v2
        with:
          distribution: 'adopt'
          java-version: '11'

      - name: Decode Keystore
        env:
          ENCODED_STRING: ${{ secrets.KEYSTORE }}
        run: |
          TMP_KEYSTORE_FILE_PATH="${RUNNER_TEMP}"/keystore
          mkdir "${TMP_KEYSTORE_FILE_PATH}"
          echo $ENCODED_STRING | base64 -di &amp;gt; "${TMP_KEYSTORE_FILE_PATH}"/keystore_file.jks

      - name: Cache Gradle and wrapper
        uses: actions/cache@v2
        with:
          path: |
            ~/.gradle/caches
            ~/.gradle/wrapper
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
          restore-keys: |
            ${{ runner.os }}-gradle-

      - name: Build Release
        run: ./gradlew app:assembleRelease
        env:
          SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS }}
          SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }}
          SIGNING_STORE_PASSWORD: ${{ secrets.SIGNING_STORE_PASSWORD }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In this file you can see 3 main sections :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;build-and-test&lt;/li&gt;
&lt;li&gt;static-analysis&lt;/li&gt;
&lt;li&gt;generate-release-apk&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8aadgrv441wy5vfs8drd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8aadgrv441wy5vfs8drd.jpg" alt="CI workflow chaining"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;build-and-test&lt;/em&gt; part is in charge of building application (and check for build failure) and running tests, both unit and instrumented. For instrumented it used &lt;a href="https://github.com/marketplace/actions/android-emulator-runner" rel="noopener noreferrer"&gt;android-emulator-runner&lt;/a&gt; to prepare a device in order to run. At the end a Jacoco task is merging different coverage result and upload them to &lt;a href="https://app.codacy.com/gh/boitakub/Bogadex/dashboard" rel="noopener noreferrer"&gt;Codacy&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In parallel of this task, &lt;em&gt;static-analysis&lt;/em&gt; is running some of android popular linters : &lt;strong&gt;ktLint&lt;/strong&gt;, &lt;strong&gt;detekt&lt;/strong&gt;, &lt;strong&gt;Android lint&lt;/strong&gt;, &lt;strong&gt;Spotless&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The last task &lt;em&gt;generate-release-apk&lt;/em&gt; is waiting for &lt;em&gt;build-and-test&lt;/em&gt; to complete and succeed before running then it will try to build an releaseable apk without publish it.&lt;/p&gt;

&lt;p&gt;The real publishing task is in the &lt;a href="https://github.com/boitakub/Bogadex/blob/main/.github/workflows/main.yml" rel="noopener noreferrer"&gt;Release Workflow&lt;/a&gt; which do the same job but in an other part of the delivery workflow, when a new &lt;a href="https://semver.org/lang/fr/" rel="noopener noreferrer"&gt;version-tag&lt;/a&gt; is added. You can notice that the workflow deploy the final apk to firebase through &lt;a href="https://github.com/marketplace/actions/firebase-app-distribution" rel="noopener noreferrer"&gt;firebase-app-distribution&lt;/a&gt; task.&lt;/p&gt;

&lt;p&gt;Finally the *.apk file is available to Firebase App Distribution&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm78bexnl28etp5e47ll8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm78bexnl28etp5e47ll8.jpg" alt="App distribution ready to serve"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Additional Resources / Info
&lt;/h3&gt;

&lt;p&gt;Do not hesitate to explore the repository &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/boitakub" rel="noopener noreferrer"&gt;
        boitakub
      &lt;/a&gt; / &lt;a href="https://github.com/boitakub/Bogadex" rel="noopener noreferrer"&gt;
        Bogadex
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      🎲 BoardGameGeek collections explorer application using Hilt,  Coroutines, Flow, Jetpack (Room, ViewModel) based on MVVM architecture.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Bogadex
&lt;/h1&gt;
&lt;p&gt;
&lt;a href="https://github.com/boitakub/Bogadex" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fboitakub%2FBogadex%2Fmain%2Fapp%2Fsrc%2Fmain%2Fres%2Fmipmap-xxhdpi%2Fic_launcher_foreground.png" width="150" alt="Bogadex"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="https://github.com/boitakub/Bogadex/actions/workflows/main.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/boitakub/Bogadex/actions/workflows/main.yml/badge.svg" alt="Build"&gt;&lt;/a&gt;
&lt;a href="https://sonarcloud.io/summary/new_code?id=boitakub_Bogadex" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a50cd222835c83bb994bb7895a801a64d7c38b9b585d68ccabc96f601229e32e/68747470733a2f2f736f6e6172636c6f75642e696f2f6170692f70726f6a6563745f6261646765732f6d6561737572653f70726f6a6563743d626f6974616b75625f426f6761646578266d65747269633d7371616c655f726174696e67" alt="Maintainability Rating"&gt;&lt;/a&gt;
&lt;a href="https://sonarcloud.io/summary/new_code?id=boitakub_Bogadex" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c23cc51590559a43edffd0c82011609263f3fc817de7eca817484da87a923241/68747470733a2f2f736f6e6172636c6f75642e696f2f6170692f70726f6a6563745f6261646765732f6d6561737572653f70726f6a6563743d626f6974616b75625f426f6761646578266d65747269633d72656c696162696c6974795f726174696e67" alt="Reliability Rating"&gt;&lt;/a&gt;
&lt;a href="https://sonarcloud.io/summary/new_code?id=boitakub_Bogadex" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/21e3f8ac9d7df700bdb942a4950b400b0575566d9454bc96215b6bca0a86badf/68747470733a2f2f736f6e6172636c6f75642e696f2f6170692f70726f6a6563745f6261646765732f6d6561737572653f70726f6a6563743d626f6974616b75625f426f6761646578266d65747269633d73656375726974795f726174696e67" alt="Security Rating"&gt;&lt;/a&gt;
&lt;a href="https://sonarcloud.io/summary/new_code?id=boitakub_Bogadex" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/71d2d3ed99674cb0305eb2052a08584e1d9325399be6d5171400286d9e94cf1a/68747470733a2f2f736f6e6172636c6f75642e696f2f6170692f70726f6a6563745f6261646765732f6d6561737572653f70726f6a6563743d626f6974616b75625f426f6761646578266d65747269633d62756773" alt="Bugs"&gt;&lt;/a&gt;
&lt;a href="https://sonarcloud.io/summary/new_code?id=boitakub_Bogadex" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/cb6ff0328d8d56772eac8d61ee1d62c8df33803f66670babf3164658ad63cd15/68747470733a2f2f736f6e6172636c6f75642e696f2f6170692f70726f6a6563745f6261646765732f6d6561737572653f70726f6a6563743d626f6974616b75625f426f6761646578266d65747269633d76756c6e65726162696c6974696573" alt="Vulnerabilities"&gt;&lt;/a&gt;
&lt;a href="https://sonarcloud.io/summary/new_code?id=boitakub_Bogadex" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/fc35a85ba7921fec19b302845f26d446e6321f1fc5177ae16f1a601dd63f2c28/68747470733a2f2f736f6e6172636c6f75642e696f2f6170692f70726f6a6563745f6261646765732f6d6561737572653f70726f6a6563743d626f6974616b75625f426f6761646578266d65747269633d7371616c655f696e646578" alt="Technical Debt"&gt;&lt;/a&gt;
&lt;a href="https://sonarcloud.io/summary/new_code?id=boitakub_Bogadex" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/51e94910f5e0f10e41fccf6929f1ee90eddb5f691ce70e83e8e8006e09fef967/68747470733a2f2f736f6e6172636c6f75642e696f2f6170692f70726f6a6563745f6261646765732f6d6561737572653f70726f6a6563743d626f6974616b75625f426f6761646578266d65747269633d636f64655f736d656c6c73" alt="Code Smells"&gt;&lt;/a&gt;
&lt;a href="https://sonarcloud.io/summary/new_code?id=boitakub_Bogadex" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7a4a0aa8208fcecfd0d11b2ef49ae6959f1635d316f00eeeee9e16fa49845031/68747470733a2f2f736f6e6172636c6f75642e696f2f6170692f70726f6a6563745f6261646765732f6d6561737572653f70726f6a6563743d626f6974616b75625f426f6761646578266d65747269633d6e636c6f63" alt="Lines of Code"&gt;&lt;/a&gt;
&lt;a href="https://sonarcloud.io/summary/new_code?id=boitakub_Bogadex" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/169c64776a28e0a84104e3dca67bfc2ca61772c63ca63e685460d09adf4fbc47/68747470733a2f2f736f6e6172636c6f75642e696f2f6170692f70726f6a6563745f6261646765732f6d6561737572653f70726f6a6563743d626f6974616b75625f426f6761646578266d65747269633d636f766572616765" alt="Coverage"&gt;&lt;/a&gt;
&lt;a href="https://kotlinlang.org" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9512ec8f602c4046b303aa0d492a6ee7b0e66c4e71178dcf1bf687ef394391be/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4b6f746c696e2d312e382e31302d626c75652e7376673f7374796c653d666c6174" alt="Kotlin"&gt;&lt;/a&gt;
&lt;a href="https://android-arsenal.com/api?level=23" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e7ce1768000fb61d452bcb69f56f0bc11b44424b6ab860e1927294fd6d71a158/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4150492d32332532422d627269676874677265656e2e7376673f7374796c653d666c6174" alt="API"&gt;&lt;/a&gt;
&lt;a href="https://github.com/boitakub/BogadexLICENSE.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6fa4a2793d7a3b857f7b2a786c79b3f9d10e9a57a7e8fba20507801b042c5b10/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f626f6974616b75622f626f6761646578" alt="License"&gt;&lt;/a&gt;
&lt;a href="https://github.com/carloscuesta/gitmoji" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ccc06dc967eb203cffa032df1a00b8d319680dd8fb9bc7ffd2173f9fa682ad64/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6769746d6f6a692d2532302546302539462539382539432532302546302539462539382538442d4646444436372e737667" alt="gitmoji"&gt;&lt;/a&gt;
&lt;a href="http://twitter.com/jforatier" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6b3e8bd66ed03797afc1585208dc7366fe26b368816b2d216dcd2e9c782bbff9/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f547769747465722d406a666f7261746965722d626c75652e7376673f7374796c653d666c6174" alt="Twitter"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
Bogadex is a small demo and functionnal application based on modern Android application tech-stacks and MVVM architecture.&lt;br&gt;This project aim to regroup and present most of current practices and patterns.&lt;br&gt;
Also dealing with data (from &lt;a href="https://www.boardgamegeek.com/" rel="nofollow noopener noreferrer"&gt;BoardGameGeek&lt;/a&gt;) and presenting them in elegants ways
&lt;/p&gt;



&lt;p&gt;
&lt;a rel="noopener noreferrer" href="https://github.com/boitakub/Bogadex/docs/assets/capture_1.gif"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fboitakub%2FBogadex%2Fdocs%2Fassets%2Fcapture_1.gif" height="500" alt="Bogadex - Screenshot"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Download 📲&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;Go to the &lt;a href="https://github.com/boitakub/Bogadex/releases" rel="noopener noreferrer"&gt;Releases&lt;/a&gt; to download the latest APK.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features ✨&lt;/h2&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Free and open source&lt;/li&gt;
&lt;li&gt;List, Sort and Filter all you &lt;a href="https://boardgamegeek.com/" rel="nofollow noopener noreferrer"&gt;BGG BoardGameGeekCollection&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Tech Stack &amp;amp; Libraries 🧬&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;This project takes advantage of best practices, and many popular libraries and tools in the Android ecosystem.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://kotlinlang.org/" rel="nofollow noopener noreferrer"&gt;Kotlin&lt;/a&gt; - 100% Kotlin - Code and Scripts&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/" rel="nofollow noopener noreferrer"&gt;Flow&lt;/a&gt; for asynchronous.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lifecycle - dispose of observing data when lifecycle state changes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ViewModel - UI related data holder, lifecycle aware.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://dagger.dev/hilt/" rel="nofollow noopener noreferrer"&gt;Hilt-Dagger&lt;/a&gt; for dependency injection.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://developer.android.com/jetpack" rel="nofollow noopener noreferrer"&gt;JetPack&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.android.com/jetpack/compose?hl=fr" rel="nofollow noopener noreferrer"&gt;Compose&lt;/a&gt; - UI build 100% with Jetpack Compose&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.android.com/topic/libraries/architecture/workmanager" rel="nofollow noopener noreferrer"&gt;WorkManager&lt;/a&gt; - Updating and maintaining data up-to-date periodically and asynchronous&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.android.com/topic/libraries/architecture/datastore" rel="nofollow noopener noreferrer"&gt;DataStore&lt;/a&gt; - for shared preferences&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.android.com/training/data-storage/room" rel="nofollow noopener noreferrer"&gt;Room&lt;/a&gt; -…&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;
&lt;/div&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/boitakub/Bogadex" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;And some of the &lt;a href="https://github.com/marketplace?type=actions" rel="noopener noreferrer"&gt;Github Actions&lt;/a&gt; it used :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/boitakub/Bogadex/blob/main/.github/workflows" rel="noopener noreferrer"&gt;Workflow folder&lt;/a&gt; - All Github Actions workflows&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/marketplace/actions/android-emulator-runner" rel="noopener noreferrer"&gt;Android emulator for instrumented - GHAction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/marketplace/actions/super-linter" rel="noopener noreferrer"&gt;Super-linter - GHAction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/marketplace/actions/firebase-app-distribution" rel="noopener noreferrer"&gt;Firebase App Distribution - GHAction&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>actionshackathon21</category>
      <category>android</category>
      <category>kotlin</category>
      <category>github</category>
    </item>
  </channel>
</rss>
