<?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: Mubarak Basha</title>
    <description>The latest articles on DEV Community by Mubarak Basha (@mubaraknative).</description>
    <link>https://dev.to/mubaraknative</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%2F2834224%2F3b52192f-4794-46d7-8ac4-67f2924f28f9.png</url>
      <title>DEV Community: Mubarak Basha</title>
      <link>https://dev.to/mubaraknative</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mubaraknative"/>
    <language>en</language>
    <item>
      <title>How I Optimize My Android App from 15MB to under &lt;2MB</title>
      <dc:creator>Mubarak Basha</dc:creator>
      <pubDate>Mon, 30 Jun 2025 11:03:26 +0000</pubDate>
      <link>https://dev.to/mubaraknative/how-i-optimize-my-android-app-from-15mb-to-under-2mb-32pk</link>
      <guid>https://dev.to/mubaraknative/how-i-optimize-my-android-app-from-15mb-to-under-2mb-32pk</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.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%2F0pwfe20ie4rowet8zils.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F0pwfe20ie4rowet8zils.png" alt="How I Optimize My Android App from 15MB to under 2MB" width="800" height="534"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;How I Optimize My Android App from 15MB to under 2MB [IMG Credit: (Mubarak Basha)]&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In this blog, I’m going to share my &lt;strong&gt;personal experience of how I Optimized my FOSS Android app by ~90%&lt;/strong&gt; , which led to more downloads and positive feedback. I will also share some &lt;strong&gt;practical ways you can do the same for your app&lt;/strong&gt; and more. Let’s begin.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Update (July 2025):&lt;/strong&gt;&lt;br&gt;
This article was featured at #2 in &lt;a href="https://androidweekly.net/issues/issue-682" rel="noopener noreferrer"&gt;Android Weekly Issue #682&lt;/a&gt;.&lt;br&gt;
Also, my open-source app &lt;a href="https://github.com/mubaraknative/MBCompass" rel="noopener noreferrer"&gt;MBCompass&lt;/a&gt; got featured in the following issue &lt;a href="https://androidweekly.net/issues/issue-683" rel="noopener noreferrer"&gt;#683&lt;/a&gt; under Libraries &amp;amp; Code!&lt;/p&gt;
&lt;h3&gt;
  
  
  Why is optimizing necessary ??
&lt;/h3&gt;

&lt;p&gt;Optimizing Android apps offers several benefits, including but not limited to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Faster downloads&lt;/li&gt;
&lt;li&gt;Reduced storage consumption&lt;/li&gt;
&lt;li&gt;Improved overall performance.&lt;/li&gt;
&lt;li&gt;Reduce internet bandwidth and many more.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  The app that I optimized.
&lt;/h4&gt;

&lt;p&gt;In this blog, I’m going to share &lt;a href="https://github.com/MubarakNative/MBCompass" rel="noopener noreferrer"&gt;&lt;strong&gt;MBCompass&lt;/strong&gt;&lt;/a&gt; as an example, which is an open-source, &lt;strong&gt;simple yet feature-rich Android Compass app&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When I first built MBCompass with &lt;strong&gt;new features and improvements on&lt;/strong&gt; &lt;a href="https://github.com/MubarakNative/MBCompass/releases/tag/v1.1.4" rel="noopener noreferrer"&gt;&lt;strong&gt;v1.1.4&lt;/strong&gt;&lt;/a&gt;, like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Showing the current location on the map.&lt;/li&gt;
&lt;li&gt;Updated Compass rose.&lt;/li&gt;
&lt;li&gt;Day/Light theme support.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this process the APK size was &lt;strong&gt;&lt;em&gt;significantly increased to 15.5MB&lt;/em&gt;&lt;/strong&gt;. Most users expect these tools to be lightweight, ideally a few MBs at most.&lt;/p&gt;

&lt;p&gt;People even &lt;strong&gt;complaining about my app on its size&lt;/strong&gt; when I posted it on platform like reddit.&lt;/p&gt;

&lt;p&gt;So, &lt;strong&gt;I decided to reduce the APK size&lt;/strong&gt; but &lt;em&gt;without compromising the feature that has already before&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  What Was Taking Up Space??
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fbe7zvec5e1dwsbpxeugv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fbe7zvec5e1dwsbpxeugv.png" alt="MBCompass v1.1.4 APK increased to 15MB compared to previous release" width="800" height="349"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;MBCompass v1.1.4 APK increased to 15MB compared to previous release&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When I analyze the MBCompass APK using &lt;strong&gt;Android Studio’s&lt;/strong&gt; &lt;a href="https://developer.android.com/studio/debug/apk-analyzer" rel="noopener noreferrer"&gt;&lt;strong&gt;APK Analyzer&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;tool&lt;/strong&gt; , the issue was clear, most of the space was taken by &lt;strong&gt;MapLibre’s native binaries,&lt;/strong&gt; which I use this library to just show the current location on the map.&lt;/p&gt;

&lt;p&gt;That was one of the features the library provides. For that single feature, I’ve used the big, powerful library.&lt;/p&gt;
&lt;h4&gt;
  
  
  Switching to a Lightweight Alternative
&lt;/h4&gt;

&lt;p&gt;I started looking for a smaller, simpler map library. That’s when I found &lt;a href="https://github.com/osmdroid/osmdroid" rel="noopener noreferrer"&gt;&lt;strong&gt;osmdroid&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;(&lt;/strong&gt;which is a low-level library*&lt;em&gt;) -&lt;/em&gt;* a lightweight replacement for Android’s MapView.&lt;/p&gt;

&lt;p&gt;After switching to osmdroid, I had to manually handle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Location permissions&lt;/li&gt;
&lt;li&gt;Map tile loading&lt;/li&gt;
&lt;li&gt;Overlays and markers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It was a bit more work, but gave me full control and customization.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step-by-Step Optimizations Process
&lt;/h3&gt;

&lt;p&gt;After switching to a different library, some other processes still have to be done before releasing the app to production.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Replaced MapLibre with osmdroid&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Dropped the MapLibre dependency and rewrote the location feature using osmdroid.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Shrink resources using R8 + Proguard&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In build.gradle(:app):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 buildTypes {
        release {
            isDebuggable = false
            // Enables code-related app optimization.
            isMinifyEnabled = true

            // Enables resource shrinking.
            isShrinkResources = true

            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }

    }
// ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;isMinifyEnabled = true: removes unused code/imports.&lt;/li&gt;
&lt;li&gt;isShrinkResources = true: removes unused icons, drawables, layouts, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Optimized Image Assets&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Replace the use PNGs/JPEGs with WebP for Images.webp&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Final Result
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F314k71fmo1y4hvehmjl4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F314k71fmo1y4hvehmjl4.png" alt="MBCompass v1.1.8 APK reduced to just 1.7MB" width="800" height="389"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;MBCompass v1.1.8 APK reduced to just 1.7MB&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;After these steps on&lt;/em&gt; &lt;a href="https://github.com/MubarakNative/MBCompass/releases/tag/v1.1.8" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;em&gt;v1.1.8&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;&lt;em&gt;latest release&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;, I brought the size down to just&lt;/em&gt; &lt;strong&gt;&lt;em&gt;1.7MB — &lt;/em&gt;&lt;/strong&gt; &lt;em&gt;a reduction of around 90%. And importantly! The core experience didn’t change instead it improved.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  What I Learned
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Don’t use a third-party library when you’re not fully utilizing it.&lt;/li&gt;
&lt;li&gt;Use Prograud and R8 to optimize APK.&lt;/li&gt;
&lt;li&gt;Smaller apps == happier users, especially on low-end devices&lt;/li&gt;
&lt;li&gt;Keep utility apps small, users appreciate it&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  You Can Try It
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/mubaraknative/MBCompass" rel="noopener noreferrer"&gt;MBCompass on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://f-droid.org/packages/com.mubarak.mbcompass/" rel="noopener noreferrer"&gt;F-Droid Page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://news.ycombinator.com/item?id=44155741" rel="noopener noreferrer"&gt;MBCompass on Hacker News&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;That’s pretty much it, I talked about how I found what was bloating my APK, switched to a lighter map library, enabled R8 and resource shrinking, and cleaned up resources. All of that helped me bring my app &lt;strong&gt;from 15MB down to 1.7MB without losing features&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you’re working on something similar, give these steps a try.&lt;br&gt;&lt;br&gt;
And if you’re curious, you can check out &lt;strong&gt;MBCompass&lt;/strong&gt; on &lt;a href="https://github.com/mubaraknative/MBCompass" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; or F-Droid. Feedback or contributions are always welcome! Thanks for reading. I will see you on my next interesting topic.&lt;/p&gt;

&lt;p&gt;Signing off, &lt;a href="https://mubaraknative.github.io/" rel="noopener noreferrer"&gt;Mubarak Basha&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/mubaraknative/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://github.com/MubarakNative/" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, &lt;a href="https://x.com/MubarakNative" rel="noopener noreferrer"&gt;X&lt;/a&gt;&lt;/p&gt;




</description>
      <category>android</category>
      <category>apk</category>
      <category>androidappdevelopment</category>
      <category>androiddev</category>
    </item>
    <item>
      <title>Building Accessible Android UIs with Jetpack Compose</title>
      <dc:creator>Mubarak Basha</dc:creator>
      <pubDate>Sun, 25 May 2025 09:57:29 +0000</pubDate>
      <link>https://dev.to/mubaraknative/building-accessible-android-uis-with-jetpack-compose-1a65</link>
      <guid>https://dev.to/mubaraknative/building-accessible-android-uis-with-jetpack-compose-1a65</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.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%2Foq2vov86cp8my57uij78.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Foq2vov86cp8my57uij78.png" alt="Building Accessible Android UIs with Jetpack Compose" width="800" height="534"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;IMG Credit (Mubarak Basha)&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In this blog, we are going to learn the importance of accessible UI and practical ways to make your app accessible in Compose for users with disabilities, with complete, real code examples. Let’s Begin.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  Why Accessibility Matters
&lt;/h4&gt;

&lt;p&gt;More than a billion, or 1 in 6 of us people live with some form of disability. Accessible apps support:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Screen reader users (&lt;a href="https://developer.android.com/guide/topics/ui/accessibility/testing#talkback" rel="noopener noreferrer"&gt;TalkBack&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Motor-impaired users (who use switch devices)&lt;/li&gt;
&lt;li&gt;Color blind and low-vision users&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Compose brings built-in support for accessibility with testing using various API’s, like Semantics, TalkBack, making this faster and seamless.&lt;/p&gt;
&lt;h4&gt;
  
  
  Semantics: Providing Meaning to UI Elements
&lt;/h4&gt;

&lt;p&gt;Accessibility services such as screen readers rely on &lt;a href="https://developer.android.com/develop/ui/compose/accessibility/semantics#properties" rel="noopener noreferrer"&gt;semantic information&lt;/a&gt; to interpret UI components correctly. It is important to provide meaningful descriptions rather than relying solely on visual things.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Icon(
    imageVector = Icons.Default.Home,
    contentDescription = "Navigate to home screen"
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SettingcontentDescription to &lt;code&gt;null&lt;/code&gt; to interactive elements (unless they are purely decorative items) leaves assistive technologies without contextual information, impairing the experience of users with disabilities.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note:&lt;/em&gt;&lt;/strong&gt;  &lt;strong&gt;&lt;em&gt;Most of the Material Compose Components like&lt;/em&gt; Checkbox_,_ RadioButton_,_ Switch_,_ Slider_, and_ Surface &lt;em&gt;implement accessibility by default&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;and come with the built-in semantics, but based on our use case, we might want to do it manually. Even for that, compose has a range of useful API’s&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Custom Composables and Accessibility Roles
&lt;/h4&gt;

&lt;p&gt;When creating custom interactive UI components, explicitly define their semantic roles (UI Meanings) and content descriptions to ensure they are announced properly. Jetpack Compose’s semantics modifier is key here (see &lt;a href="https://developer.android.com/develop/ui/compose/accessibility/merging-clearing" rel="noopener noreferrer"&gt;merging and clearing semantics&lt;/a&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Box(
    modifier = Modifier
        .clickable { /* Handle upload action */ }
        .semantics {
            contentDescription = "Upload file"
            role = Role.Button
        }
        .padding(16.dp)
) {
    Icon(Icons.Default.CloudUpload, contentDescription = null)
    Text("Upload")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach allows TalkBack and similar tools to identify the composable as a button with the specified action.&lt;/p&gt;

&lt;h4&gt;
  
  
  Adequate Touch Target Size
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F9o4r4hm1ygtvjks6loon.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F9o4r4hm1ygtvjks6loon.png" alt="Provide Adequate Touch Target Size" width="240" height="132"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;IMG Credit: (Developer Docs) Touch Target Size&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Ensure touch targets meet the recommended minimum size of &lt;strong&gt;48x48dp&lt;/strong&gt; for comfortable interaction, following Android accessibility design guidelines (&lt;a href="https://m3.material.io/foundations/overview/assistive-technology" rel="noopener noreferrer"&gt;Material Accessible Design&lt;/a&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Button(
    onClick = { /* Handle click */ },
    modifier = Modifier.sizeIn(minWidth = 48.dp, minHeight = 48.dp)
) {
    Icon(Icons.Default.Favorite, contentDescription = "Like")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This improves accessibility for users with motor impairments.&lt;/p&gt;

&lt;h4&gt;
  
  
  Managing Focus with Keyboard and Assistive Devices
&lt;/h4&gt;

&lt;p&gt;Not all users interact via touch. Keyboard navigation and switches require explicit focus order management, which Compose supports via focusRequesterand focusOrder (detailed in the &lt;a href="https://developer.android.com/develop/ui/compose/touch-input/focus/change-focus-traversal-order" rel="noopener noreferrer"&gt;focus traversal order docs&lt;/a&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val focusRequester1 = remember { FocusRequester() }
val focusRequester2 = remember { FocusRequester() }

TextField(
    value = username,
    onValueChange = { username = it },
    label = { Text("Username") },
    modifier = Modifier
        .focusRequester(focusRequester1)
        .focusOrder { next = focusRequester2 }
)

TextField(
    value = password,
    onValueChange = { password = it },
    label = { Text("Password") },
    modifier = Modifier.focusRequester(focusRequester2)
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code ensures a logical order of focus between inputs.&lt;/p&gt;

&lt;h4&gt;
  
  
  Maintaining Adequate Color Contrast
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fag08j6llmxnq09hn7zi9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fag08j6llmxnq09hn7zi9.png" alt="Maintain Adequate Color Contrast" width="658" height="207"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;IMG Credit: (Developer Docs) Increase text visibility&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Using your theme’s color scheme to maintain appropriate contrast ratios in both light and dark modes, as emphasized by &lt;a href="https://developer.android.com/guide/topics/ui/accessibility/apps#text-visibility" rel="noopener noreferrer"&gt;Material Design accessibility standards.&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Text(
    text = "Welcome",
    style = MaterialTheme.typography.titleLarge,
    color = MaterialTheme.colorScheme.onBackground
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Proper contrast improves readability for users with visual impairments.&lt;/p&gt;

&lt;h4&gt;
  
  
  Testing Accessibility
&lt;/h4&gt;

&lt;p&gt;Use both automated checks and manual tools for testing accessibility:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.android.com/develop/ui/compose/testing" rel="noopener noreferrer"&gt;Automated Compose test&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@get:Rule
val composeTestRule = createComposeRule()

@Before
fun setup() {
    AccessibilityChecks.enable()
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Manual testing tools:&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;TalkBack&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://support.google.com/accessibility/android/answer/6376570?hl=en" rel="noopener noreferrer"&gt;Accessibility Scanner&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developer.android.com/guide/topics/ui/accessibility/testing#switch-access" rel="noopener noreferrer"&gt;Switch Access&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Reference
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.android.com/develop/ui/compose/accessibility" rel="noopener noreferrer"&gt;Compose Accessibility Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://m3.material.io/foundations/accessible-design/overview" rel="noopener noreferrer"&gt;Material Design: Accessible Design&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.android.com/codelabs/jetpack-compose-accessibility" rel="noopener noreferrer"&gt;Accessibility in Jetpack Compose codelab&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In this quick blog, we learned the importance of accessible UI and also learned its practical uses with an example_._ I hope you will like this article. If so, please like👏 this story and share it with your friends and family, don’t forget to follow me. And I will see you in the next upcoming article with an interesting topic.&lt;/p&gt;

&lt;p&gt;Signing off, &lt;a href="https://mubaraknative.github.io" rel="noopener noreferrer"&gt;Mubarak Basha&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/mubaraknative/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://github.com/MubarakNative/" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, &lt;a href="https://github.com/MubarakNative/" rel="noopener noreferrer"&gt;X&lt;/a&gt;&lt;/p&gt;




</description>
      <category>jetpackcompose</category>
      <category>a11y</category>
      <category>androiddev</category>
      <category>kotlin</category>
    </item>
    <item>
      <title>Getting Started with Material Design 3 in Jetpack Compose</title>
      <dc:creator>Mubarak Basha</dc:creator>
      <pubDate>Thu, 17 Apr 2025 13:36:41 +0000</pubDate>
      <link>https://dev.to/mubaraknative/getting-started-with-material-design-3-in-jetpack-compose-j0</link>
      <guid>https://dev.to/mubaraknative/getting-started-with-material-design-3-in-jetpack-compose-j0</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2Aa-qJK7BMHy55qFN1" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2Aa-qJK7BMHy55qFN1" width="1024" height="1024"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Photo by Daniel Korpai on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In this article, you’ll learn how to integrate Material 3 in your Compose app, use the updated components, and apply best practices for building beautiful Android UIs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Why Material 3?
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://developer.android.com/develop/ui/compose/designsystems/material3" rel="noopener noreferrer"&gt;Material Design 3&lt;/a&gt; is Google’s latest design system, aiming to create a more expressive, adaptive, and accessible UI across Android apps. Some key benefits include:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic color&lt;/strong&gt; that matches the user’s wallpaper (Android 12+)&lt;/li&gt;
&lt;li&gt;New UI components like FilledTonalButton, AssistChip, and BottomAppBar&lt;/li&gt;
&lt;li&gt;Better control over shape, elevation, and typography&lt;/li&gt;
&lt;li&gt;Native support in Jetpack Compose&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Step 1: Add Material 3 to Your Project
&lt;/h4&gt;

&lt;p&gt;In your build.gradle(:app) file, add: Find the latest version &lt;a href="https://developer.android.com/jetpack/androidx/releases/compose-material3" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dependencies {
   implementation("androidx.compose.material3:material3:1.3.2")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 2: Set Up Your Theme with Material 3
&lt;/h4&gt;

&lt;p&gt;Create or update your Theme.kt to use MaterialTheme with dynamic color support:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Composable
fun MyAppTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    dynamicColor: Boolean = true,
    content: @Composable () -&amp;gt; Unit
) {
    val context = LocalContext.current
    val colorScheme = when {
        dynamicColor &amp;amp;&amp;amp; Build.VERSION.SDK_INT &amp;gt;= Build.VERSION_CODES.S -&amp;gt; {
            if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
        }
        darkTheme -&amp;gt; darkColorScheme()
        else -&amp;gt; lightColorScheme()
    }

    MaterialTheme(
        colorScheme = colorScheme,
        typography = Typography,
        content = content
    )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then wrap your app’s setContent with it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;setContent {
    MyAppTheme {
        Scaffold() {
            // Your UI goes here
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Custom Color Scheme
&lt;/h4&gt;

&lt;p&gt;If you don’t want to rely on dynamic colors or manually create a color scheme, you can create your own custom color scheme that might reflect your branding to do this —Material 3 provides a &lt;a href="https://developer.android.com/develop/ui/compose/designsystems/material3#generate_color_schemes" rel="noopener noreferrer"&gt;Theme builder&lt;/a&gt; where you generate Color and Theme by mentioning your base color.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3: Use Material 3 Components
&lt;/h4&gt;

&lt;p&gt;Material 3 introduces redesigned components with updated styling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Composable
fun Material3Buttons() {
    Column(modifier = Modifier.padding(16.dp)) {
        Button(onClick = { /*TODO*/ }) {
            Text("Default Button")
        }

        FilledTonalButton(onClick = { }) {
            Text("Tonal Button")
        }

        ElevatedButton(onClick = { }) {
            Text("Elevated Button")
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try Card, TextField, TopAppBar, NavigationBar, and more — The full list can be founded &lt;a href="https://developer.android.com/develop/ui/compose/components" rel="noopener noreferrer"&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Typography &amp;amp; Shapes
&lt;/h4&gt;

&lt;p&gt;Material 3 introduces modern typography styles like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;displayLarge, headlineSmall, titleMedium, labelLarge, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can customize them in your Typography.kt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val Typography = Typography(
    titleLarge = TextStyle(
        fontWeight = FontWeight.Bold,
        fontSize = 22.sp,
        letterSpacing = 0.15.sp
    )
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same goes for &lt;a href="https://developer.android.com/develop/ui/compose/designsystems/material3#shapes" rel="noopener noreferrer"&gt;shapes&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val Shapes = Shapes(
    small = RoundedCornerShape(8.dp),
    medium = RoundedCornerShape(16.dp),
    large = RoundedCornerShape(24.dp)
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Dynamic Color on Android 12+
&lt;/h4&gt;

&lt;p&gt;One of the coolest features of M3 is &lt;a href="https://developer.android.com/develop/ui/compose/designsystems/material3#dynamic_color_schemes" rel="noopener noreferrer"&gt;&lt;strong&gt;dynamic theming&lt;/strong&gt;&lt;/a&gt;. On Android 12+, the system can generate color schemes from the user’s wallpaper.&lt;/p&gt;

&lt;p&gt;This happens automatically when you use dynamicDarkColorScheme() or dynamicLightColorScheme() — it just works.&lt;/p&gt;

&lt;p&gt;On older versions, you can fall back to predefined colors with lightColorScheme() and darkColorScheme().&lt;/p&gt;

&lt;h4&gt;
  
  
  Best Practices
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Use MaterialTheme.colorScheme and MaterialTheme.typography instead of hardcoded values&lt;/li&gt;
&lt;li&gt;Test your UI in light/dark mode and with accessibility settings&lt;/li&gt;
&lt;li&gt;Avoid mixing Material 2 and Material 3 unless necessary&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Sample Project
&lt;/h4&gt;

&lt;p&gt;Check out this GitHub repo for a full Material 3 Compose sample:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/MubarakNative/WikiNewsFeed" rel="noopener noreferrer"&gt;GitHub - MubarakNative/WikiNewsFeed: WikiNewsApp: A modern Android app for fetching and displaying global news from the open-source WikiNews platform https://www.wikinews.org/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this quick blog, we learned &lt;em&gt;how to set up material 3 design system in jetpack compose and also learned its advantages.&lt;/em&gt; I hope you will like this article. If so, please like👏 this story and share it with your friends and family, don’t forgot to follow me. And I will see you in the next upcoming article with an interesting topic.&lt;/p&gt;

&lt;p&gt;Signing off, &lt;a href="https://mubaraknative.github.io" rel="noopener noreferrer"&gt;Mubarak.M Basha&lt;/a&gt;&lt;/p&gt;




</description>
      <category>jetpackcompose</category>
      <category>material3</category>
      <category>androiddev</category>
      <category>android</category>
    </item>
    <item>
      <title>How to Publish Your App on F-Droid: A Beginner’s Guide</title>
      <dc:creator>Mubarak Basha</dc:creator>
      <pubDate>Tue, 25 Mar 2025 15:20:57 +0000</pubDate>
      <link>https://dev.to/mubaraknative/how-to-publish-your-app-on-f-droid-a-beginners-guide-2emg</link>
      <guid>https://dev.to/mubaraknative/how-to-publish-your-app-on-f-droid-a-beginners-guide-2emg</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.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%2Frf36i6p1vfsbfg0zdcsw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Frf36i6p1vfsbfg0zdcsw.png" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This article covers how to publish your app to f-droid, I also pleasure to share my own experience when publishing my first app on f-droid.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  What is F-Droid?
&lt;/h3&gt;

&lt;p&gt;When you come across this blog post you most probably know what f-droid is But I just want to introduce you f-droid simply.&lt;/p&gt;

&lt;p&gt;F-droid is a FOSS (free and open-source) app store for Android, similar to the Google Play Store, but the f-droid software repo hoisted on GitLab contains only free and open-source apps and the &lt;strong&gt;components of that app itself must comply with OSS terms&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;Read more about F-Droid’s Inclusion Policy:&lt;/strong&gt; &lt;a href="https://f-droid.org/docs/Inclusion_Policy/" rel="noopener noreferrer"&gt;F-Droid Inclusion Policy&lt;/a&gt; 🔗 &lt;strong&gt;Read about Repository Styling Guidelines:&lt;/strong&gt; &lt;a href="https://fdroid.org/docs/Repository_Style_Guide/" rel="noopener noreferrer"&gt;F-Droid Repository Style Guide&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Publish on F-Droid?
&lt;/h3&gt;

&lt;p&gt;Publishing on F-Droid has several advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No account registration required&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy-friendly&lt;/strong&gt; (no data sharing with third parties)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Completely free&lt;/strong&gt; (no fees to publish your app)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How to Publish Your App on F-Droid
&lt;/h3&gt;

&lt;p&gt;There are two primary ways to submit your app to F-Droid:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. GitLab Submission Queue (Beginner-Friendly)
&lt;/h3&gt;

&lt;p&gt;This method involves creating an issue on &lt;a href="https://gitlab.com/fdroid/rfp/-/issues" rel="noopener noreferrer"&gt;&lt;strong&gt;GitLab to request app packaging&lt;/strong&gt;&lt;/a&gt;. It’s the simplest way to submit an app but also the slowest, because reviewers manually build the APK from the source.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fr9xt06spu7pbw7jh8wrs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fr9xt06spu7pbw7jh8wrs.png" alt="MBCompass app on F-droid." width="391" height="664"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;MBCompass app on F-droid: &lt;a href="https://f-droid.org/packages/com.mubarak.mbcompass/" rel="noopener noreferrer"&gt;https://f-droid.org/packages/com.mubarak.mbcompass/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I submitted &lt;a href="https://github.com/MubarakNative/MbCompass/" rel="noopener noreferrer"&gt;&lt;strong&gt;MBCompass&lt;/strong&gt;&lt;/a&gt;, my compass application, using this approach . It took about a &lt;a href="https://gitlab.com/fdroid/fdroiddata/-/blob/master/metadata/com.mubarak.mbcompass.yml" rel="noopener noreferrer"&gt;&lt;strong&gt;month&lt;/strong&gt;&lt;/a&gt; for my app to be included in &lt;a href="https://f-droid.org/packages/com.mubarak.mbcompass/" rel="noopener noreferrer"&gt;F-Droid&lt;/a&gt;, even though it contained no non-free assets.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  2. Metadata Merge Request (Advanced Method)
&lt;/h3&gt;

&lt;p&gt;This method involves manually writing the F-Droid metadata and submitting a merge request to the &lt;a href="https://gitlab.com/fdroid/fdroiddata/" rel="noopener noreferrer"&gt;fdroiddata&lt;/a&gt; GitLab repository.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Advantages:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Faster approval process&lt;/li&gt;
&lt;li&gt;Reduces manual work for F-Droid reviewers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This guide will focus on the &lt;strong&gt;GitLab Submission Queue&lt;/strong&gt; , as it is the best option for beginners.&lt;/p&gt;

&lt;p&gt;🔗&lt;a href="https://f-droid.org/docs/Inclusion_How-To/" rel="noopener noreferrer"&gt;See: F-droid Inclusion How to&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Steps to Publish Your App on F-Droid
&lt;/h3&gt;
&lt;h3&gt;
  
  
  Step 1: Prepare Your App
&lt;/h3&gt;

&lt;p&gt;Before submitting your app, ensure it’s ready for production:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add an &lt;strong&gt;app icon&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Conduct &lt;strong&gt;thorough testing&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Follow &lt;strong&gt;versioning and minification best practices&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔗 &lt;strong&gt;Refer to the Android Developer Docs:&lt;/strong&gt; &lt;a href="https://developer.android.com/studio/publish" rel="noopener noreferrer"&gt;Publish Your App&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 2: Ensure Reproducible Builds
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What are Reproducible Builds (RB)?&lt;/strong&gt; A reproducible build ensures that the APK built from your source code is identical every time, preventing tampering or unintended modifications.&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;Learn more about Reproducible Builds:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Reproducible_builds" rel="noopener noreferrer"&gt;Wikipedia: Reproducible Builds&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://f-droid.org/docs/Reproducible_Builds/" rel="noopener noreferrer"&gt;F-Droid Reproducible Builds&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://reproducible-builds.org/" rel="noopener noreferrer"&gt;Reproducible Builds Official Site&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Steps to Enable Reproducible Builds:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Generate a signed APK&lt;/strong&gt; :&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Open &lt;strong&gt;Android Studio&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Build&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Generate Signed APK&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Use a &lt;strong&gt;release signing key&lt;/strong&gt; instead of a debug key&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Upload the signed APK&lt;/strong&gt; to your remote Git repository&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔗 &lt;strong&gt;More about App Signing and RB Build:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.android.com/studio/publish/app-signing.html#generate-key" rel="noopener noreferrer"&gt;Android App Signing Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gitlab.com/IzzyOnDroid/repo/-/wikis/Reproducible-Builds" rel="noopener noreferrer"&gt;Reproducible Build Guide on IzzyOnDroid&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Step 3: Use Fastlane for Metadata &amp;amp; Screenshots
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://fastlane.tools/" rel="noopener noreferrer"&gt;Fastlane&lt;/a&gt; is an open-source automation tool that helps with app metadata management, screenshots, and deployment, and it is maintained by google now.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;F-droid uses fastlane for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add &lt;strong&gt;app descriptions and title&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Upload &lt;strong&gt;screenshots&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Provide &lt;strong&gt;app details for the F-Droid listing&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔗 &lt;strong&gt;How to Set Up Fastlane:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Follow this guide: &lt;a href="https://gitlab.com/-/snippets/1895688" rel="noopener noreferrer"&gt;Fastlane Snippet&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Check an example setup: &lt;a href="https://github.com/MubarakNative/MBCompass/tree/main/fastlane/metadata/android/en-US" rel="noopener noreferrer"&gt;MBCompass Metadata&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Step 4: Add APK Signing Blocks
&lt;/h3&gt;

&lt;p&gt;F-Droid requires proper signing metadata to ensure secure and verified builds.&lt;/p&gt;

&lt;p&gt;Add this &lt;em&gt;dependenciesInfo&lt;/em&gt; block on*&lt;em&gt;build.gradle.kts(Module:app)&lt;/em&gt;*&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;android {
    ...
    dependenciesInfo {
        includeInApk = false
        includeInBundle = false
    }
    ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🔗 &lt;strong&gt;More about APK Signing:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/obfusk/31c332b884464cd8aa06ce1ba1583c05" rel="noopener noreferrer"&gt;Signing Block Explanation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gitlab.com/fdroid/fdroidserver/-/issues/1056" rel="noopener noreferrer"&gt;F-Droid Issue on Signing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Final Step: Submit Your App to the GitLab Submission Queue
&lt;/h3&gt;

&lt;p&gt;Once your app is ready:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F5n79do5h2feuw0lwv9vs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F5n79do5h2feuw0lwv9vs.png" width="392" height="856"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;F-droid RFP issue template&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;F-Droid’s GitLab Request for Packaging (RFP) Issues&lt;/strong&gt;: &lt;a href="https://gitlab.com/fdroid/rfp/-/issues/" rel="noopener noreferrer"&gt;Submit Your App&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Create a new issue by selecting Minimal template.&lt;/li&gt;
&lt;li&gt;Add necessary info like &lt;strong&gt;Category, Summary, and license&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Wait for the review process (this can take several weeks to a month, depending on the app).&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In this blog, I just shared my experience when uploading my one of my apps in F-droid, and I included all the possible useful links that helped me. Hopefully, it also helped you if you please❤️ this blog and share it with your niche dev. If you face some problems or challenges, feel free to reach out me. I always like to help someone throughout my journey.&lt;/p&gt;

&lt;p&gt;Signing off, &lt;a href="https://mubaraknative.github.io/" rel="noopener noreferrer"&gt;Mubarak Native&lt;/a&gt;, &lt;a href="https://github.com/MubarakNative/" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, &lt;a href="https://x.com/mubarakNative" rel="noopener noreferrer"&gt;X&lt;/a&gt;&lt;/p&gt;

</description>
      <category>androiddev</category>
      <category>fdroid</category>
      <category>apppublishing</category>
      <category>android</category>
    </item>
    <item>
      <title>Getting Started with MapLibre on Android</title>
      <dc:creator>Mubarak Basha</dc:creator>
      <pubDate>Wed, 12 Mar 2025 04:32:21 +0000</pubDate>
      <link>https://dev.to/mubaraknative/getting-started-with-maplibre-on-android-45df</link>
      <guid>https://dev.to/mubaraknative/getting-started-with-maplibre-on-android-45df</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.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%2Fi95zbhr3zs4jsldz8sjn.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fi95zbhr3zs4jsldz8sjn.jpeg" alt="All you need to know about MapLibre" width="800" height="534"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;All you need to know about MapLibre&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In this article, we are going to learn what &lt;strong&gt;MapLibre Native&lt;/strong&gt; is for rendering vector maps in Android. We will also explore the benefits of using MapLibre over other map rendering SDKs, some customization options, and more. Let’s begin!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;What is MapLibre Native ??&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;MapLibre Native is an &lt;strong&gt;open-source&lt;/strong&gt; vector map rendering library for Android. It is part of the &lt;a href="https://maplibre.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;MapLibre Organization&lt;/strong&gt;&lt;/a&gt;, which provides open-source mapping solutions for various platforms, including &lt;a href="https://github.com/maplibre/maplibre-native" rel="noopener noreferrer"&gt;&lt;strong&gt;Android, iOS&lt;/strong&gt;&lt;/a&gt;, and &lt;a href="https://github.com/maplibre/maplibre-gl-js" rel="noopener noreferrer"&gt;&lt;strong&gt;Web&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Originally, it was a &lt;a href="https://github.com/maplibre/maplibre-native/blob/main/FORK.md" rel="noopener noreferrer"&gt;&lt;strong&gt;community-led fork of Mapbox GL Native for Android&lt;/strong&gt;&lt;/a&gt; before Mapbox &lt;a href="https://github.com/mapbox/mapbox-gl-native-android/blob/main/CHANGELOG.md#930---july-15-2020" rel="noopener noreferrer"&gt;&lt;strong&gt;closed-sourced&lt;/strong&gt;&lt;/a&gt; their implementation. Since then, the project has replaced the closed-source components with &lt;strong&gt;fully open-source alternatives&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Why MapLibre Native ??&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You might wonder why we need to use MapLibre Native when we already have Google Maps, Mapbox, Here SDKs, and other mapping providers.&lt;/p&gt;

&lt;p&gt;Yes, many software SDKs and libraries exist to integrate maps into products, but they often come with &lt;strong&gt;vendor lock-in&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example, if you want to set up your own map server to &lt;strong&gt;reduce the cost of monthly/annual billing&lt;/strong&gt; , you &lt;strong&gt;can’t do that&lt;/strong&gt; with proprietary SDKs. Additionally, they offer &lt;strong&gt;limited customization options&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In short, &lt;strong&gt;MapLibre Native allows you to swap out implementations easily&lt;/strong&gt; , offering greater flexibility and control.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;How to work with MapLibre Native??&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Before diving into integration, let’s discuss how MapLibre Native handles &lt;strong&gt;map data&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;MapLibre Native is a &lt;strong&gt;map renderer&lt;/strong&gt;  — to display a map, we need &lt;strong&gt;map data&lt;/strong&gt;. In my previous article, I explained the &lt;a href="https://medium.com/@mubaraknative/how-to-build-offline-maps-with-openstreetmap-on-android-dc44112f82ef" rel="noopener noreferrer"&gt;&lt;strong&gt;types of map tiles&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;MapLibre Native renders &lt;strong&gt;vector tile data&lt;/strong&gt; , which can be &lt;strong&gt;self-hosted&lt;/strong&gt; using a tile server (e.g., &lt;strong&gt;TileServer GL&lt;/strong&gt; with a simple &lt;strong&gt;S3 CDN&lt;/strong&gt; ). Alternatively, multiple &lt;strong&gt;vector tile providers&lt;/strong&gt; are available.&lt;/p&gt;

&lt;p&gt;For a high-level understanding, we need to display data in &lt;strong&gt;Mapbox Vector Tile (MVT) format&lt;/strong&gt;, such as this example:&lt;br&gt;&lt;br&gt;
 &lt;a href="https://demotiles.maplibre.org/style.json" rel="noopener noreferrer"&gt;https://demotiles.maplibre.org/style.json&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;More details: &lt;a href="https://maplibre.org/maplibre-style-spec/" rel="noopener noreferrer"&gt;https://maplibre.org/maplibre-style-spec/&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;What do we build ??&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In this demo, we will build a views (XML) based &lt;strong&gt;simple app&lt;/strong&gt; that uses &lt;a href="https://openfreemap.org/" rel="noopener noreferrer"&gt;OpenFreeMap&lt;/a&gt; tile data to display a world map.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Feg62o84su9zoasqwgj8p.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Feg62o84su9zoasqwgj8p.jpeg" alt="Sample app uses Maplibre to render global map from openfreemap" width="474" height="1053"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For production apps, you can &lt;strong&gt;self-host&lt;/strong&gt; your data using &lt;a href="https://protomaps.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Protomaps&lt;/strong&gt;&lt;/a&gt; or &lt;a href="https://github.com/maptiler/tileserver-gl" rel="noopener noreferrer"&gt;&lt;strong&gt;TileServer GL&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: There is a community folk for &lt;strong&gt;MapLibre Native for Jetpack Compose&lt;/strong&gt; checkout &lt;a href="https://github.com/sargunv/maplibre-compose" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;build.gradle.kts(Module:app)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can find the latest version of this maplibre native SDK at Maven Central &lt;a href="https://central.sonatype.com/artifact/org.maplibre.gl/android-sdk/versions" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;em&gt;here&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;.&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;    dependencies {
       // ...
    implementation ("org.maplibre.gl:android-sdk:11.8.2")
       // ...
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don’t forget to add internet permission to your app for fetching map tiles from the server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AndroidManifest.xml&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;
&amp;lt;!-- ... --&amp;gt;
&amp;lt;uses-permission android:name="android.permission.INTERNET" /&amp;gt;
&amp;lt;!-- ... --&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 1:&lt;/p&gt;

&lt;p&gt;Let’s start by adding &lt;a href="https://maplibre.org/maplibre-native/android/api/-map-libre%20-native%20-android/org.maplibre.android.maps/-map-view/index.html" rel="noopener noreferrer"&gt;MapView&lt;/a&gt;in your XML layout on your Activity/fragment .&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;org.maplibre.android.maps.MapView
    android:id="@+id/mapView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 2: Initialize this MapView in your fragment or Activity&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.LayoutInflater
import org.maplibre.android.MapLibre
import org.maplibre.android.camera.CameraPosition
import org.maplibre.android.geometry.LatLng
import org.maplibre.android.maps.MapView

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    // Declare a variable for MapView
    private lateinit var mapView: MapView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Get an instance of MapLibre.
        MapLibre.getInstance(this)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        // Init the MapView
        mapView = binding.mapView
        mapView.getMapAsync { map -&amp;gt;
            map.setStyle("https://tiles.openfreemap.org/styles/liberty")
            // Shows full world view
            map.cameraPosition = CameraPosition.Builder().target(LatLng(0.0,0.0)).zoom(1.0).build()
        }
    }

    override fun onStart() {
        super.onStart()
        mapView.onStart()
    }

    override fun onResume() {
        super.onResume()
        mapView.onResume()
    }

    override fun onPause() {
        super.onPause()
        mapView.onPause()
    }

    override fun onStop() {
        super.onStop()
        mapView.onStop()
    }

    override fun onLowMemory() {
        super.onLowMemory()
        mapView.onLowMemory()
    }

    override fun onDestroy() {
        super.onDestroy()
        mapView.onDestroy()
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        mapView.onSaveInstanceState(outState)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we run the app, it successfully shows the world map from OpenFreeMap data for other data sources checkout &lt;a href="https://github.com/maplibre/maplibre-native/blob/main/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/styles/TestStyles.kt" rel="noopener noreferrer"&gt;TestStyles&lt;/a&gt; from &lt;a href="https://github.com/maplibre/maplibre-native/tree/main/platform/android/MapLibreAndroidTestApp" rel="noopener noreferrer"&gt;&lt;strong&gt;MapLibreAndroidTestApp&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;That’s it we learned &lt;strong&gt;What is MapLibre Native&lt;/strong&gt; , &lt;strong&gt;why we use MapLibre&lt;/strong&gt; and also learned &lt;strong&gt;its benefits over other sdk&lt;/strong&gt; for complete source code with a additional map features, checkout the repository down below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/MubarakNative/MbCompass/" rel="noopener noreferrer"&gt;GitHub - MubarakNative/MBCompass: A fully functional jetpack compose compass app that uses device magnetometer to find cardinal direction&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://maplibre.org/maplibre-native/android/api/index.html" rel="noopener noreferrer"&gt;MapLibre Native API Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://maplibre.org/maplibre-native/android/examples/" rel="noopener noreferrer"&gt;MapLibre Native Sample Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you found this article helpful and learned something new, please consider &lt;strong&gt;❤️&lt;/strong&gt; and sharing it with your friends. This is a niche topic, and very few articles cover it in detail. Creating content like this takes hours of effort — from designing a thumbnail to structuring the information in an easy-to-understand way.&lt;/p&gt;

&lt;p&gt;Your support motivates me to keep writing more valuable articles. See you in the next one! 🚀&lt;/p&gt;

</description>
      <category>androiddev</category>
      <category>openstreetmap</category>
      <category>maplibre</category>
      <category>kotlin</category>
    </item>
    <item>
      <title>How to Build Offline Maps with OpenStreetMap on Android</title>
      <dc:creator>Mubarak Basha</dc:creator>
      <pubDate>Sat, 08 Feb 2025 13:41:27 +0000</pubDate>
      <link>https://dev.to/mubaraknative/how-to-build-offline-maps-with-openstreetmap-on-android-4j4</link>
      <guid>https://dev.to/mubaraknative/how-to-build-offline-maps-with-openstreetmap-on-android-4j4</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.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%2Fcpoju71fzwpwsgkqgl1p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fcpoju71fzwpwsgkqgl1p.png" alt="All you need to know about OSM on android and ways to integrate" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How to build offline maps with OpenStreetMap on android
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Want to add &lt;strong&gt;offline maps&lt;/strong&gt; to your Android app without relying on paid mapping services? &lt;strong&gt;OpenStreetMap (OSM)&lt;/strong&gt; is a powerful, free, and open-source alternative that lets you integrate &lt;strong&gt;customizable, offline-friendly maps&lt;/strong&gt; into your project.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this guide, we’ll cover:&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;What is OpenStreetMap (OSM)?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Types of map tiles (Raster vs. Vector) &amp;amp; their differences&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Best libraries for rendering offline vector tiles on Android&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;How to build an offline map app using the Mapsforge library&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By the end, you’ll have a working &lt;strong&gt;offline OpenStreetMap-based Android app&lt;/strong&gt; without needing a tile server. Let’s get started! 🚀&lt;/p&gt;
&lt;h4&gt;
  
  
  What is OpenStreetMap 🌍?
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://wiki.openstreetmap.org/wiki/About_OpenStreetMap" rel="noopener noreferrer"&gt;OpenStreetMap&lt;/a&gt; (OSM) provides open map data that is built by a community of mappers around the world and maintains the info about roads, trails, hospitals, railway stations, and much more.&lt;/p&gt;
&lt;h4&gt;
  
  
  Why OSM ?
&lt;/h4&gt;

&lt;p&gt;Because &lt;strong&gt;OpenStreetMap is free and open map data&lt;/strong&gt; and it is community driven means you are free to use it for any purpose as long as you credit OpenStreetMap and its contributors.&lt;/p&gt;

&lt;p&gt;“Used in popular free navigation apps like &lt;strong&gt;Organic Maps&lt;/strong&gt; and  &lt;strong&gt;OsmAnd&lt;/strong&gt; ”&lt;/p&gt;

&lt;p&gt;“No licensing fees like Google Maps”&lt;/p&gt;

&lt;p&gt;More about OSM see &lt;a href="https://wiki.openstreetmap.org/wiki/FAQ#Why_OpenStreetMap?" rel="noopener noreferrer"&gt;FAQ WIKI&lt;/a&gt; and &lt;a href="https://www.openstreetmap.org/copyright" rel="noopener noreferrer"&gt;License&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;
  
  
  🗺️Map tiles available in OSM ?
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://wiki.openstreetmap.org/wiki/Rendering" rel="noopener noreferrer"&gt;Map rendering&lt;/a&gt; refers to the process of taking raw geospatial data and making a visual map from it.&lt;/p&gt;

&lt;p&gt;There are two different types of tiles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Raster tiles&lt;/li&gt;
&lt;li&gt;Vector tiles&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://wiki.openstreetmap.org/wiki/Raster_tiles" rel="noopener noreferrer"&gt;Raster tiles&lt;/a&gt; are just &lt;strong&gt;pre-rendered images&lt;/strong&gt; , (ex: &lt;a href="https://tile.openstreetmap.org/7/63/42.png" rel="noopener noreferrer"&gt;&lt;em&gt;here&lt;/em&gt;&lt;/a&gt;) and they are displayed in a grid arrangement to form a visual map. Raster maps are usually harder to customize on the client side and require a &lt;a href="https://wiki.openstreetmap.org/wiki/Tile_servers" rel="noopener noreferrer"&gt;tile server&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://wiki.openstreetmap.org/wiki/Vector_tiles" rel="noopener noreferrer"&gt;Vector tiles&lt;/a&gt; are just like raster tiles, but instead of pre-rendered images as a tile, &lt;strong&gt;the return data contains&lt;/strong&gt; &lt;a href="https://openlayers.org/en/latest/examples/osm-vector-tiles.html" rel="noopener noreferrer"&gt;&lt;strong&gt;map data&lt;/strong&gt;&lt;/a&gt;, thus adding complexity to the client application that they need to render its data on the fly to form a visual representation of map in it.&lt;/p&gt;

&lt;p&gt;Also, vector tiles address some limitations of raster tiles, like. &lt;strong&gt;Customization, smooth zooming and more&lt;/strong&gt;. Read more about it &lt;a href="https://wiki.openstreetmap.org/wiki/Vector_tiles#Motivation" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: In this article we are focused on the Vector tile rendering library on Android, because it is easy to implement it on an &lt;strong&gt;offline OSM-based map app, and it doesn’t require a tile server&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As I mentioned earlier, vector maps are somewhat complex to render them on the client side (Mobile, Desktop, and Web) because they only contain map data. Fortunately, the rendering libraries handle the complex &lt;a href="https://wiki.openstreetmap.org/wiki/Vector_tiles#Rendering_libraries" rel="noopener noreferrer"&gt;tasks&lt;/a&gt; for us. We will see these libraries in the details in the next section.&lt;/p&gt;
&lt;h3&gt;
  
  
  Offline Vector Rendering libraries
&lt;/h3&gt;

&lt;p&gt;In this section, we are more specifically going to explore the available libraries for rendering &lt;strong&gt;offline vector map based on OSM&lt;/strong&gt; for Android &amp;amp; Java platforms.&lt;/p&gt;


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


&lt;p&gt;Apart from these mentioned libraries, there are other libraries as mentioned in the &lt;a href="https://wiki.openstreetmap.org/wiki/Android" rel="noopener noreferrer"&gt;&lt;strong&gt;Android Wiki of OSM&lt;/strong&gt;&lt;/a&gt;. The reason why I am not listing those libraries is because &lt;strong&gt;they often have a vendor-lock-in, which means proprietary licensing terms and don’t completely support the offline maps.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Integrating Offline OSM Maps in an Android App
&lt;/h3&gt;

&lt;p&gt;In today’s article I am going to show an example of Mapsforge library as a vector map renderer for android, because it fully supports offline maps, and has a lot of online &lt;a href="https://github.com/mapsforge/mapsforge/blob/master/docs/Mapsforge-Maps.md" rel="noopener noreferrer"&gt;map providers&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: I am not a member or a contributor of any listed libraries here, and I am not promoting any libraries, so, it is full of my research effects and things I learnt that I am happy to share with you without expecting any profits.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s begin by adding the necessary dependencies for Mapsforge. Check out the latest version &lt;a href="https://github.com/mapsforge/mapsforge/releases" rel="noopener noreferrer"&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Mapsforge Core
    implementation ("org.mapsforge:mapsforge-core:0.23.0")
    implementation ("org.mapsforge:mapsforge-map:0.23.0")
    implementation ("org.mapsforge:mapsforge-map-reader:0.23.0")
    implementation ("org.mapsforge:mapsforge-themes:0.23.0")

// Android dependencies for Mapsforge
    implementation ("org.mapsforge:mapsforge-map-android:0.23.0")
    implementation ("com.caverock:androidsvg:1.4")

    // Mapsforge POI core (OPTIONAL)
    implementation ("org.mapsforge:mapsforge-poi:0.23.0")

    // Mapsforge POI android specific (OPTIONAL)
    implementation ("org.mapsforge:mapsforge-poi-android:0.23.0")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here, we are going to create a basic application (see &lt;a href="https://github.com/mapsforge/mapsforge/blob/master/mapsforge-samples-android/src/main/java/org/mapsforge/samples/android/MapsforgeMapViewer.java" rel="noopener noreferrer"&gt;MapForgeMapView.java&lt;/a&gt; ) that renders the osm vector map that is already stored in our mobile file system. &lt;a href="https://github.com/mapsforge/mapsforge/blob/master/docs/Mapsforge-Maps.md" rel="noopener noreferrer"&gt;&lt;strong&gt;Download&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;the map that you want to display in the app.&lt;/strong&gt;&lt;/p&gt;


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



&lt;p&gt;And its corresponding MainActivity.kt&lt;/p&gt;


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


&lt;p&gt;&lt;a href="https://media2.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%2F0e4s5lqu8oujd5sjdtlo.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F0e4s5lqu8oujd5sjdtlo.jpeg" alt="Mapsforge demo" width="800" height="689"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;MapsForge Application Demo&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is only a simple demo. Mapsforge can do more than this. Don’t forget to read all the docs on the Mapsforge page.&lt;/p&gt;

&lt;p&gt;As I mentioned previously, vector tiles can be easily styled. The mapsforge library also supports styling using the XML format. See &lt;a href="https://github.com/mapsforge/mapsforge/blob/master/docs/Rendertheme.md" rel="noopener noreferrer"&gt;here&lt;/a&gt; for more details. I am also working on an OSM-based offline map app, which is in an development state right now.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/MubarakNative/OSMDemo/" rel="noopener noreferrer"&gt;GitHub - MubarakNative/OSMDemo: A Demo android application to integrate OpenStreetMap based map using Mapsforge library&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Contributing to OpenStreetMap
&lt;/h4&gt;

&lt;p&gt;If you want to give back to the community and improve OpenStreetMap by adding missing places or updating existing data, you’re always &lt;a href="https://wiki.openstreetmap.org/wiki/Editors" rel="noopener noreferrer"&gt;welcome&lt;/a&gt;! Several tools make contributing easy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;On Android&lt;/strong&gt; : Use &lt;a href="https://github.com/streetcomplete/StreetComplete" rel="noopener noreferrer"&gt;&lt;strong&gt;StreetComplete&lt;/strong&gt;&lt;/a&gt; — Easy to use OpenStreetMap editor for Android&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On Desktop&lt;/strong&gt; : Use &lt;a href="https://wiki.openstreetmap.org/wiki/JOSM" rel="noopener noreferrer"&gt;&lt;strong&gt;JOSM&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;(Java OpenStreetMap Editor)&lt;/strong&gt; — A powerful tool for advanced editing and customization.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;I hope you found this article helpful! If you appreciate my research and effort, 🙏 please consider ❤️ and sharing it . Your support motivates me to continue creating high-quality, free content for everyone. Happy mapping!🌍&lt;/p&gt;

</description>
      <category>vectormaps</category>
      <category>openstreetmap</category>
      <category>androiddevelopment</category>
      <category>android</category>
    </item>
    <item>
      <title>Comprehensive Guide: Get User Location on Android with Jetpack Compose</title>
      <dc:creator>Mubarak Basha</dc:creator>
      <pubDate>Thu, 09 Jan 2025 09:33:22 +0000</pubDate>
      <link>https://dev.to/mubaraknative/comprehensive-guide-get-user-location-on-android-with-jetpack-compose-2mo1</link>
      <guid>https://dev.to/mubaraknative/comprehensive-guide-get-user-location-on-android-with-jetpack-compose-2mo1</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.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%2Fn69ywwcsoc22rpaft392.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fn69ywwcsoc22rpaft392.png" alt="Get user location on android using google’s fused location provider" width="800" height="457"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Get user location on android using google’s fused location provider and Jetpack Compose&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In this article, we are going to learn about &lt;strong&gt;Google’s fused location provider client&lt;/strong&gt; for accessing user location on Android, compare it with Android’s native LocationManager API, permission handling for location, build a real-world compose app and more. Let’s begin.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  What is Fused Location Provider ?
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://developers.google.com/location-context/fused-location-provider" rel="noopener noreferrer"&gt;Fused location provider&lt;/a&gt; is a location API from Google Play Services. It combines several additional services from Android to get the location, like Wi-Fi and GPS based on their availability for battery efficiency.&lt;/p&gt;
&lt;h4&gt;
  
  
  Why Fused Location Provider API ??
&lt;/h4&gt;

&lt;p&gt;To access the device’s geographical location, &lt;strong&gt;Android natively has a&lt;/strong&gt; &lt;a href="https://developer.android.com/reference/android/location/LocationManager" rel="noopener noreferrer"&gt;&lt;strong&gt;LocationManager&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;api&lt;/strong&gt;. Why do we need this API? Well, Android has this LocationManager API to access all the location updates. But when we have a requirement to combine different services, as I mentioned above based on availability. We need to write a lot of boilerplate code to achieve the same thing in the fused provider client. &lt;strong&gt;It offers a simple API to work with considering power efficiency.&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Key Components when requesting Location
&lt;/h4&gt;

&lt;p&gt;Before we implementing requesting location on a android, We must know what are the type of location service available for us. here it follows&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Foreground Location&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;last known location&lt;/li&gt;
&lt;li&gt;location updates&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Background Location&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: In this article we are going to only focus on foreground location access, especially (2. location updates in detail). Not all apps have a requirement for accessing locations in the background. Special use cases only have this requirement, like for &lt;a href="https://en.wikipedia.org/wiki/Geofence" rel="noopener noreferrer"&gt;Geo-fencing&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;last known location:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Using the fused location provider, we are able to get the last known location of the device using the &lt;a href="https://developers.google.com/android/reference/com/google/android/gms/location/FusedLocationProviderClient.html#getLastLocation()" rel="noopener noreferrer"&gt;getLastLocation()&lt;/a&gt;function. It returns the cached &lt;a href="https://developer.android.com/reference/android/location/Location#getLatitude()" rel="noopener noreferrer"&gt;location&lt;/a&gt; object from the past currently available. It may return null if there are no cached values available.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fusedLocationClient.lastLocation
        .addOnSuccessListener { location : Location? -&amp;gt;
            // last known location. this can be null.
        }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;For use cases like map, driving, walking, apps the&lt;/strong&gt; &lt;a href="https://developers.google.com/android/reference/com/google/android/gms/location/FusedLocationProviderClient#requestLocationUpdates(com.google.android.gms.location.LocationRequest,%20java.util.concurrent.Executor,%20com.google.android.gms.location.LocationListener)" rel="noopener noreferrer"&gt;location updates&lt;/a&gt; &lt;strong&gt;would be more appropriate.&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;location updates&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For current continued location update at a specific intervals &lt;strong&gt;location updates&lt;/strong&gt; will be used. it return the updates based on the currently-available location service such as Wi-Fi and GPS.&lt;/p&gt;
&lt;h3&gt;
  
  
  Request the location permissions.
&lt;/h3&gt;

&lt;p&gt;To access system location, we need to request two permissions at runtime, &lt;a href="https://developer.android.com/reference/android/Manifest.permission#ACCESS_FINE_LOCATION" rel="noopener noreferrer"&gt;ACCESS_FINE_LOCATION&lt;/a&gt; and &lt;a href="https://developer.android.com/reference/android/Manifest.permission#ACCESS_COARSE_LOCATION" rel="noopener noreferrer"&gt;ACCESS_COARSE_LOCATION&lt;/a&gt;, because on Android 12 (API level 31) or higher, users have a choice to provide a coarse location (approx. location) only, even if we declare fine permissions on the manifest. Read more about it &lt;a href="https://developer.android.com/develop/sensors-and-location/location/permissions/runtime#approximate-request" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    &amp;lt;uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /&amp;gt;
    &amp;lt;uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Handling permission request
&lt;/h4&gt;

&lt;p&gt;Here, the below code implementation uses google &lt;a href="https://google.github.io/accompanist/permissions/" rel="noopener noreferrer"&gt;Accompanist Permissions library&lt;/a&gt; to make things easier for this demo, If you like to handle the permissions yourself in a jetpack compose, I recommend using &lt;a href="https://developer.android.com/reference/kotlin/androidx/activity/compose/package-summary#rememberlauncherforactivityresult" rel="noopener noreferrer"&gt;rememberLauncherForActivityResult()&lt;/a&gt; API.&lt;/p&gt;


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



&lt;p&gt;In this implementation, we have a better way to request &lt;a href="https://developer.android.com/develop/sensors-and-location/location/permissions/runtime" rel="noopener noreferrer"&gt;location permissions&lt;/a&gt; as per our need for both &lt;a href="https://developer.android.com/reference/android/Manifest.permission#ACCESS_FINE_LOCATION" rel="noopener noreferrer"&gt;ACCESS_FINE_LOCATION&lt;/a&gt; and &lt;a href="https://developer.android.com/reference/android/Manifest.permission#ACCESS_COARSE_LOCATION" rel="noopener noreferrer"&gt;ACCESS_COARSE_LOCATION&lt;/a&gt;, and we also handle the permission rejection by &lt;strong&gt;showing a rational alert dialog to the user&lt;/strong&gt; if they deny the permission we have requested.&lt;/p&gt;

&lt;p&gt;See how this example app requests the permission (gif) &lt;a href="https://cdn-images-1.medium.com/max/1024/1*T5Awbi9PCij8XW8CWLOiPg.gif" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Start location request
&lt;/h3&gt;

&lt;p&gt;Before we going to receive the location update, we need to request the location that specifies the required level of accuracy/power consumption and desired update interval, and the device automatically makes the appropriate changes to system settings. These settings are defined by the &lt;a href="https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest" rel="noopener noreferrer"&gt;LocationRequest&lt;/a&gt; data object.&lt;/p&gt;

&lt;p&gt;The LocationRequest object has multiple parameters to configure. Here are some important parameters as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developers.google.com/android/reference/com/google/android/gms/location/Priority" rel="noopener noreferrer"&gt;&lt;strong&gt;Priority&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sets the &lt;a href="https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest.Builder#public-locationrequest.builder-setpriority-int-priority" rel="noopener noreferrer"&gt;setPriority(int priority)&lt;/a&gt; of the location request.&lt;/p&gt;

&lt;p&gt;The default value is &lt;a href="https://developers.google.com/android/reference/com/google/android/gms/location/Priority#PRIORITY_BALANCED_POWER_ACCURACY" rel="noopener noreferrer"&gt;Priority.PRIORITY_BALANCED_POWER_ACCURACY&lt;/a&gt;— Use this setting to request location precision to within a city block, which is an accuracy of approximately 100 meters.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developers.google.com/android/reference/com/google/android/gms/location/Priority#PRIORITY_HIGH_ACCURACY" rel="noopener noreferrer"&gt;Priority.PRIORITY_HIGH_ACCURACY&lt;/a&gt; — Use this setting to request the most precise location possible.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest.Builder#public-locationrequest.builder-setintervalmillis-long-intervalmillis" rel="noopener noreferrer"&gt;&lt;strong&gt;Update interval&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest#setInterval(long)" rel="noopener noreferrer"&gt;setInterval&lt;/a&gt;(long intervalMillis) — Sets the desired interval of location updates.&lt;/p&gt;

&lt;p&gt;Create the location request and set the parameters as shown in this code sample:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  fun createLocationRequest() {
    val locationRequest = LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 2000)
        .build()
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;The priority of &lt;a href="https://developers.google.com/android/reference/com/google/android/gms/location/Priority#PRIORITY_HIGH_ACCURACY" rel="noopener noreferrer"&gt;PRIORITY_HIGH_ACCURACY&lt;/a&gt; is ideal for map apps, the requires current real time locations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once the location request is in place, we can start the regular location updates by calling &lt;a href="https://developers.google.com/android/reference/com/google/android/gms/location/FusedLocationProviderClient.html#public-abstract-taskvoid-requestlocationupdates-locationrequest-request,-pendingintent-pendingintent" rel="noopener noreferrer"&gt;requestLocationUpdates()&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: requestLocationUpdates() has two function overloads. One parameter is (&lt;a href="https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest" rel="noopener noreferrer"&gt;LocationRequest&lt;/a&gt;request, &lt;a href="https://developers.google.com/android/reference/com/google/android/gms/location/LocationCallback" rel="noopener noreferrer"&gt;LocationCallback&lt;/a&gt; callback, &lt;a href="https://developer.android.com/reference/android/os/Looper.html" rel="noopener noreferrer"&gt;Looper&lt;/a&gt; looper) and the second one is (LocationRequest with a &lt;a href="https://developers.google.com/android/reference/com/google/android/gms/location/FusedLocationProviderClient.html#public-abstract-taskvoid-requestlocationupdates-locationrequest-request,-pendingintent-pendingintent" rel="noopener noreferrer"&gt;&lt;strong&gt;Pending Intent&lt;/strong&gt;&lt;/a&gt;.) If you receive location updates in the background, pending intent overload will be used. &lt;strong&gt;For foreground use cases, prefer to listen for location updates via a listener or callback instead of a pending intent.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here, we receive updates in the foreground, so let’s use the&lt;a href="https://developers.google.com/android/reference/com/google/android/gms/location/LocationCallback.html" rel="noopener noreferrer"&gt;LocationCallback&lt;/a&gt;approach. Call &lt;a href="https://developers.google.com/android/reference/com/google/android/gms/location/FusedLocationProviderClient.html#requestLocationUpdates(com.google.android.gms.location.LocationRequest,%20com.google.android.gms.location.LocationCallback,%20android.os.Looper)" rel="noopener noreferrer"&gt;requestLocationUpdates()&lt;/a&gt;, passing it your instance of the &lt;a href="https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest.html" rel="noopener noreferrer"&gt;LocationRequest&lt;/a&gt; object, and a &lt;a href="https://developers.google.com/android/reference/com/google/android/gms/location/LocationCallback.html" rel="noopener noreferrer"&gt;LocationCallback&lt;/a&gt;.&lt;/p&gt;


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



&lt;blockquote&gt;
&lt;p&gt;Note: Here we use DisposableEffect for receiving and removing listing updates for location, based on application lifecycle. &lt;strong&gt;Receive when the application is in the foreground using our requestLocationUpdates and stop when the application is in the background using&lt;/strong&gt; &lt;a href="https://developers.google.com/android/reference/com/google/android/gms/location/FusedLocationProviderClient.html#public-abstract-taskvoid-removelocationupdates-locationcallback-callback" rel="noopener noreferrer"&gt;removeLocationUpdates(locationCallback)&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Finally, receive updates using location update callback
&lt;/h3&gt;

&lt;p&gt;With our &lt;a href="https://developers.google.com/android/reference/com/google/android/gms/location/LocationCallback.html#onLocationResult(com.google.android.gms.location.LocationResult)" rel="noopener noreferrer"&gt;LocationCallback.onLocationResult()&lt;/a&gt; callback method we get the &lt;a href="https://developers.google.com/android/reference/com/google/android/gms/location/LocationResult" rel="noopener noreferrer"&gt;LocationResult&lt;/a&gt;. Using this we get a &lt;a href="https://developer.android.com/reference/android/location/Location" rel="noopener noreferrer"&gt;Location&lt;/a&gt;objects containing location’s latitude and longitude. The following snippet shows how you can do that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    // Only register the location updates effect when we have a locationRequest
    if (locationRequest != null) {
        LocationUpdatesEffect(locationRequest!!) { locationResult -&amp;gt;
            for (currentLocation in locationResult.locations) {
                // Update UI with location data as per your needs.
            }
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the full implementation of this code by building a LocateU jetpack compose location demo app:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F0af4j9a7hbhhp15j2znn.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F0af4j9a7hbhhp15j2znn.jpeg" alt="LocateU app demo" width="800" height="689"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;LocateU App&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/MubarakNative/LocateU" rel="noopener noreferrer"&gt;GitHub - MubarakNative/LocateU: Location aware android app demo using google fusedlocationprovider&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In this article, I explained what is fused location provider API is, and how to implement it in our Android project and more. I hope you like this article and learn its use-cases. If yes, please consider supporting me 👏. To stay motivated to creating high-quality free articles, I will see you on my next interesting topic with an interesting article.&lt;/p&gt;

&lt;p&gt;Signing off, &lt;a href="https://mubaraknative.github.io/blog.html" rel="noopener noreferrer"&gt;Mubarak Native&lt;/a&gt;&lt;/p&gt;

</description>
      <category>jetpackcompose</category>
      <category>fusedlocationprovider</category>
      <category>kotlin</category>
      <category>androiddev</category>
    </item>
    <item>
      <title>A Modern WebView Alternative: AndroidX Browser for Jetpack Compose</title>
      <dc:creator>Mubarak Basha</dc:creator>
      <pubDate>Sat, 14 Dec 2024 07:22:31 +0000</pubDate>
      <link>https://dev.to/mubaraknative/a-modern-webview-alternative-androidx-browser-for-jetpack-compose-3oca</link>
      <guid>https://dev.to/mubaraknative/a-modern-webview-alternative-androidx-browser-for-jetpack-compose-3oca</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.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%2F8t40dy0tn6ginpt5rwx9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F8t40dy0tn6ginpt5rwx9.png" alt="A Modern WebView Alternative: AndroidX Browser for Jetpack Compose&amp;lt;br&amp;gt;
" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Welcome back! In this article, we are going to learn what is androidx.browser library, and how it is the best way to display web content in our android app, also learn how to integrate this into our android studio project, and explore some customization in it for displaying web content and more. Let’s begin.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  What is browser library in androidx package?
&lt;/h4&gt;

&lt;p&gt;androidx.browser library helps us to display the web pages in the user’s default browser through &lt;a href="https://developer.chrome.com/docs/android/custom-tabs" rel="noopener noreferrer"&gt;&lt;strong&gt;Android Custom Tabs&lt;/strong&gt;&lt;/a&gt;. For instance, in a news app, when the user clicks on the detail page for specific news that go to the specific website, we can show this webpage in our app from a user’s default browser application. It might be chrome, or any other browser they’ve set as default. This approach ensures a better user experience while leveraging the browser’s capabilities and security features.&lt;/p&gt;
&lt;h4&gt;
  
  
  Why android custom tabs?
&lt;/h4&gt;

&lt;p&gt;Displaying web pages as a part of our application is a common requirement for android apps. I see a lot of apps that use WebView for just displaying web pages within their app. It comes with several drawbacks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Heavy Context Switch: It launches the actual browser, which is a heavy context switch for users that isn’t also customizable like &lt;strong&gt;It doesn’t include the features of a fully developed web browser, such as navigation controls or an address bar&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Compose Integration Challenges: Apart from this, WebView is from the Views System, so there is no straight forward implementation to integrate into a compose project. &lt;strong&gt;While interoperability APIs like&lt;/strong&gt; &lt;a href="https://developer.android.com/develop/ui/compose/migrate/interoperability-apis/views-in-compose" rel="noopener noreferrer"&gt;AndroidView&lt;/a&gt; &lt;strong&gt;can bridge the gap, this isn’t an ideal or elegant solution&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, why stick with WebView for displaying web pages? Instead, use &lt;strong&gt;Custom Tabs&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Ff4ophh7f0xercifssdj8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Ff4ophh7f0xercifssdj8.gif" alt="WikiNews App demo that has Custom Tab implementation" width="513" height="1067"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;WikiNews App demo that has Custom Tab implementation&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Integrating on a Compose Project
&lt;/h4&gt;

&lt;p&gt;Add the &lt;a href="https://developer.android.com/jetpack/androidx/releases/browser#declaring_dependencies" rel="noopener noreferrer"&gt;dependencies&lt;/a&gt; for the artifacts you need in the build.gradle file for your app or module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dependencies {
    implementation("androidx.browser:browser:1.8.0")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use the &lt;a href="https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsIntent.Builder" rel="noopener noreferrer"&gt;CustomTabsIntent.Builder&lt;/a&gt; to create a &lt;a href="https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsIntent" rel="noopener noreferrer"&gt;CustomTabsIntent&lt;/a&gt; and launch the Custom Tab by calling &lt;a href="https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsIntent#launchUrl(android.content.Context,android.net.Uri)" rel="noopener noreferrer"&gt;launchUrl()&lt;/a&gt; and passing an &lt;a href="https://developer.android.com/reference/android/net/Uri" rel="noopener noreferrer"&gt;Uri&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val url = "https://kotlinlang.org/docs/home.html"

val intent = CustomTabsIntent.Builder()
        .setShowTitle(true) //
        .setUrlBarHidingEnabled(true)
        .build()
    intent.launchUrl(this@MainActivity, Uri.parse(url))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.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%2Fxsequ349yzt3qitux8fi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fxsequ349yzt3qitux8fi.png" alt="WikiNewsFeed app as example uses Chrome Custom tabs for displaying news within the app" width="354" height="788"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Customizing the appearances
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val intent = CustomTabsIntent.Builder()
…
.setShowTitle(true)
.setStartAnimations(MainActivity.this, R.anim.slide_in_right, R.anim.slide_out_left)
.setExitAnimations(MainActivity.this, android.R.anim.slide_in_left, android.R.anim.slide_out_right)
.setUrlBarHidingEnabled(true)
.build();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;.&lt;/em&gt;&lt;a href="https://developer.android.com/reference/kotlin/androidx/browser/customtabs/CustomTabsIntent.Builder#setShowTitle(boolean)" rel="noopener noreferrer"&gt;&lt;em&gt;setShowTitle&lt;/em&gt;&lt;/a&gt;&lt;em&gt;(true)&lt;/em&gt; — Sets whether the web page title should be shown in the custom tab.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;.&lt;/em&gt;&lt;a href="https://developer.android.com/reference/kotlin/androidx/browser/customtabs/CustomTabsIntent.Builder#setStartAnimations(android.content.Context,int,int)" rel="noopener noreferrer"&gt;&lt;em&gt;setStartAnimations&lt;/em&gt;&lt;/a&gt;&lt;em&gt;(…)&lt;/em&gt; and &lt;em&gt;.&lt;/em&gt;&lt;a href="https://developer.android.com/reference/kotlin/androidx/browser/customtabs/CustomTabsIntent.Builder#setExitAnimations(android.content.Context,int,int)" rel="noopener noreferrer"&gt;&lt;em&gt;setExitAnimations&lt;/em&gt; &lt;/a&gt;— Enter and Exit animations when user enters and leaves the web page.&lt;/li&gt;
&lt;li&gt;.&lt;a href="https://developer.android.com/reference/kotlin/androidx/browser/customtabs/CustomTabsIntent.Builder#setUrlBarHidingEnabled(boolean)" rel="noopener noreferrer"&gt;&lt;em&gt;setUrlBarHidingEnabled &lt;/em&gt;&lt;/a&gt;— Hide the URL bar on scroll to give the user more space to explore web content.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are just a few basic customizations. There’s much more you can do, like adding custom menu items, or integrating Chrome-specific features etc.&lt;/p&gt;

&lt;p&gt;For a comprehensive guide, check out the official documentation here. &lt;a href="https://developer.chrome.com/docs/android/custom-tabs/guide-interactivity" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Conclusion
&lt;/h4&gt;

&lt;p&gt;In this article, we explored how the androidx.browser library and Android Custom Tabs provide a modern, secure, and user-friendly alternative to WebView for displaying web content within Android applications. With features like seamless integration with the user's default browser, enhanced security, and extensive customization options, Custom Tabs offer an efficient way to enrich your app's functionality while ensuring a smooth user experience.&lt;/p&gt;

&lt;p&gt;For real world demonstration of this custom tabs don’t forgot to checkout my WikiNews Github project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/MubarakNative/WikiNewsFeed" rel="noopener noreferrer"&gt;GitHub - MubarakNative/WikiNewsFeed: WikiNewsApp: A modern Android client for fetching and displaying global news from the open-source WikiNews platform https://www.wikinews.org/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>webview</category>
      <category>chromecustomtabs</category>
      <category>androiddev</category>
    </item>
    <item>
      <title>Get your app for larger screens using window-size classes</title>
      <dc:creator>Mubarak Basha</dc:creator>
      <pubDate>Sat, 29 Jun 2024 16:10:48 +0000</pubDate>
      <link>https://dev.to/mubaraknative/get-your-app-for-larger-screens-using-window-size-classes-3dh</link>
      <guid>https://dev.to/mubaraknative/get-your-app-for-larger-screens-using-window-size-classes-3dh</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.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%2Fh5oei9k8zyhc2efxqy0f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fh5oei9k8zyhc2efxqy0f.png" alt="Designing our app for all screen-sizes in android" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In this article, we are going to learn how to optimize our app to look better on every screen-sizes. It includes a phone, tablet and even a desktop (Chrome OS) and also learn why we need to consider optimizing our app for larger screens and more. Let’s begin.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Why do we need to support larger screen-sizes?
&lt;/h4&gt;

&lt;p&gt;Android not only runs on smartphones, it also runs on Tablet, Desktop (Chrome OS), Foldables, Automotive and also on Smart TV’s with over &lt;strong&gt;three billion active devices&lt;/strong&gt;. We are developers we ensure to provide a seamless experience on every platform, foldables are now the current hot topic is that every smartphone brand releases their own version of foldables. They dynamically change their screen sizes from a phone to a tablet-sized display.&lt;/p&gt;

&lt;h4&gt;
  
  
  How to support large screen-sizes?
&lt;/h4&gt;

&lt;p&gt;To support every screen-size, &lt;strong&gt;we need to make our layout adaptive&lt;/strong&gt; , so they adapt its size based on screen size. We achieve this by using &lt;a href="https://developer.android.com/develop/ui/compose/layouts/adaptive/window-size-classes" rel="noopener noreferrer"&gt;&lt;strong&gt;window-size-classes on android&lt;/strong&gt;&lt;/a&gt;. They provide high level abstraction of screen size by providing these simple types: &lt;strong&gt;&lt;em&gt;compact&lt;/em&gt;&lt;/strong&gt; , &lt;strong&gt;&lt;em&gt;medium&lt;/em&gt;&lt;/strong&gt; , and &lt;strong&gt;expanded&lt;/strong&gt; , so we can easily make UI design decisions based on screen sizes. &lt;strong&gt;Ex: in compact we show a navigation bar or model navigation drawer, there are 2 types of window-size-classes&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Height&lt;/li&gt;
&lt;li&gt;Width&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;We usually consider width size class because most of the content in our app scrolls vertically.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F4sinyuf6paq7d4vtqlgk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F4sinyuf6paq7d4vtqlgk.png" alt="Window width size classes" width="800" height="493"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Window-Size-Classes&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To get the current window-size, let’s add one dependency to our &lt;strong&gt;&lt;em&gt;libs.versions.toml&lt;/em&gt;&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;[versions]
material3AdaptiveNavigationSuite = "1.3.0-beta04"

[libraries]
androidx-material3-adaptive-navigation-suite = { module = "androidx.compose.material3:material3-adaptive-navigation-suite", version.ref = "material3AdaptiveNavigationSuite" }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And define it on &lt;strong&gt;build.gradle.kts(module:app)&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;dependencies {

 // NavigationSuiteScaffold
implementation(libs.androidx.material3.adaptive.navigation.suite)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;Note: The material adaptive library is currently in beta. Check out the latest releases &lt;a href="https://developer.android.com/jetpack/androidx/releases/compose-material3-adaptive" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;We have the two following benefits for adding this dependency&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;One is obvious, we can access the window-size class for both height and width by using the &lt;strong&gt;currentWindowAdaptiveInfo&lt;/strong&gt; () function.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass.windowWidthSizeClass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So we can make UI design decisions about something like that.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable
fun App(
    widthSizeClass: WindowWidthSizeClass
) {
    // Perform logic on the size class to decide whether to show navigation rail or not.
    val isExpanded = windowSizeClass == WindowWidthSizeClass.EXPANDED

    Row {
        if (isExpanded) {
            NavigationRail {
                NavigationRailItem(
                    /* ... */
                )
            }
        }
        DefaultNavGraph(/* ... */)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;The second one is that we have access to &lt;strong&gt;NavigationSuiteScaffold &lt;em&gt;which simplifies the navigation UI decision logic for us, based on window-size.&lt;/em&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It shows the &lt;strong&gt;bottom navigation bar&lt;/strong&gt; &lt;strong&gt;if the windowsize is in a compact or in a table-top (horizontal) position&lt;/strong&gt;, &lt;strong&gt;and it shows navigation rail for everything else.&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  For what screen-size, which navigation layout is best ?
&lt;/h4&gt;

&lt;p&gt;As per Material Design guidelines, window size class&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Compact (Width &amp;lt; 600 dp): Use Navigation bar, modal navigation drawer&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Medium (600 dp≤ width &amp;lt; 840 dp): Use Navigation rail, modal navigation drawer&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expanded (840 ≤ width &amp;lt; 1200*): Use Navigation rail, modal or standard navigation drawer (for expanded use 2 pane layout if you use list-detail screen by using&lt;/strong&gt; &lt;a href="https://developer.android.com/develop/ui/compose/layouts/adaptive/list-detail#implement_ui_pattern_with_listdetailpanescaffold" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;em&gt;ListDetailPaneScaffold&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: ListDetailPaneScaffold is from a material-adaptive library which is currently in alpha, and it also is not supporting Navigation compose yet, for view-based app use &lt;a href="https://developer.android.com/develop/ui/views/layout/twopane" rel="noopener noreferrer"&gt;&lt;em&gt;SlidingPaneLayout&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  Let’s see a real world demo
&lt;/h4&gt;

&lt;p&gt;As I already mentioned, by using &lt;strong&gt;NavigationSuiteScaffold&lt;/strong&gt; , it really simplifies our work. &lt;strong&gt;We don’t need to write a logic based on window-size-class ourselves.&lt;/strong&gt; It does for us out of the box. Let’s get into a demo. Next, &lt;strong&gt;we also learn how to manually show navigation layout based on window-size-classes.&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  What do we build??
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Ftvnrjexorg8s9uk5yg2m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Ftvnrjexorg8s9uk5yg2m.png" alt="NavigationSuiteScaffold app demo" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this app we don’t focus on the content of the screen, instead just showing the text that displays, our current destination. Our goal is just displaying a navigation layout based on window-size.&lt;/p&gt;

&lt;p&gt;Let’s implement it:&lt;/p&gt;

&lt;p&gt;As we already added the required dependency, which is navigation-suite from material 3, so let’s focus on code.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For our top level destinations, I added an enum class. For that, here is that code.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;enum class AppDestinations(
    @StringRes val label: Int,
    val icon: ImageVector,
    @StringRes val contentDescription: Int
) {
    HOME(R.string.home, Icons.Default.Home, R.string.home),
    DRAWING(R.string.draw, Icons.Default.Draw, R.string.draw),
    EDIT(R.string.edit, Icons.Default.Edit, R.string.edit),
    SETTINGS(R.string.profile, Icons.Default.Person, R.string.settings),
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And let’s call the &lt;strong&gt;NavigationSuiteScaffold&lt;/strong&gt; and pass the &lt;em&gt;necessary arguments&lt;/em&gt;&lt;/p&gt;


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



&lt;p&gt;As you can see the code how easy it is to implement the navigation layout based on window-size class &lt;strong&gt;when we use NavigationSuiteScaffold, we don’t need to write. Single conditional statement for the window-size class&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you want, we can further customize it. If you want to show other navigation layout based on window-size, you can do so by passing another parameter in NavigationSuiteScaffold named &lt;strong&gt;layoutType&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;val adaptiveInfo = currentWindowAdaptiveInfo()

    /* Optional */
    val customNavSuiteType = with(adaptiveInfo) {
        if (windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.EXPANDED) {
            NavigationSuiteType.NavigationRail
        } else {
            NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo(adaptiveInfo)
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here we customize the navigation layout based on the window class. &lt;strong&gt;If we are currently on the EXPANDED screen, we show the navigation rail instead of the default navigation bar&lt;/strong&gt; , our layout screen is considered as an EXPANDED if the below criteria meet:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Phone in landscape&lt;/li&gt;
&lt;li&gt;Tablet in landscape&lt;/li&gt;
&lt;li&gt;Foldable in landscape (unfolded state)&lt;/li&gt;
&lt;li&gt;Desktop (Chrome OS)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we have learned how to work with NavigationSuiteScaffold. Now let’s move on to more customized option.&lt;/p&gt;
&lt;h3&gt;
  
  
  Handling navigation layout decisions ourselves by using Window-Size-Classes
&lt;/h3&gt;

&lt;p&gt;Now let’s explore how to handle navigation layout based on Window-Size-Class ourselves.&lt;/p&gt;


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



&lt;p&gt;As you can see in the code, &lt;strong&gt;we conditionally show Navigation Rail based on screen-size&lt;/strong&gt; by using&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val isExpanded = widthSizeClass == WindowWidthSizeClass.EXPANDED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s call this function in &lt;strong&gt;MainActivity.kt&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;YourAppTheme{
    val windowWidthSizeClass = currentWindowAdaptiveInfo().windowSizeClass
    OsbApp(windowWidthSizeClass.windowWidthSizeClass) // here we using Width Size class.
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you run the app, it shows an appropriate navigation layout based on widow-size&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fjjs7ptc7lty58oprloip.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fjjs7ptc7lty58oprloip.png" alt="App Demo" width="800" height="500"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Conditionally show a navigation layout based on window-size.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The source code of the &lt;strong&gt;NavigationSuiteScaffold&lt;/strong&gt; demo is available on this repository:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/MubarakNative/Compose-Code-Examples/tree/navigation-suite-scaffold" rel="noopener noreferrer"&gt;GitHub - MubarakNative/Compose-Code-Examples at navigation-suite-scaffold&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For real world application, checkout &lt;a href="https://github.com/MubarakNative/WikiNewsFeed/" rel="noopener noreferrer"&gt;GitHub - MubarakNative/WikiNewsFeed&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this article, we learned &lt;em&gt;how to provide the best user-experience on larger screen sizes and also learned its use cases.&lt;/em&gt; I hope you will like this article. If so, please like this story and share it with your friends and family. And i will see you in the next upcoming article with an interesting topic.&lt;/p&gt;

&lt;p&gt;Signing off, &lt;a href="https://mubaraknative.github.io/" rel="noopener noreferrer"&gt;Mubarak Basha&lt;/a&gt;&lt;/p&gt;

</description>
      <category>jetpackcompose</category>
      <category>androiddev</category>
      <category>largescreen</category>
      <category>kotlin</category>
    </item>
  </channel>
</rss>
