<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Syed Zubyl N | Software Developer - Android</title>
    <subtitle>Syed Zubyl N — Software Developer focused on Java, Spring Boot, backend development, REST APIs, databases, Flutter and production-oriented applications.</subtitle>
    <link rel="self" type="application/atom+xml" href="https://syedzubyl.space/tags/android/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://syedzubyl.space"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-08-05T00:00:00+00:00</updated>
    <id>https://syedzubyl.space/tags/android/atom.xml</id>
    <entry xml:lang="en">
        <title>From an Old Android Release to a Modern Play Store Release</title>
        <published>2026-08-05T00:00:00+00:00</published>
        <updated>2026-08-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Syed Zubyl N
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://syedzubyl.space/blog/old-android-release-to-modern/"/>
        <id>https://syedzubyl.space/blog/old-android-release-to-modern/</id>
        
        <content type="html" xml:base="https://syedzubyl.space/blog/old-android-release-to-modern/">&lt;h3 id=&quot;the-problem&quot;&gt;The Problem&lt;&#x2F;h3&gt;
&lt;p&gt;A few years ago, I built and published an Android application to the Google Play Store. Fast forward to 2026, and Google Play policies had evolved significantly. The original application was targeting an older Android version (around API 33). Google now required updates to target modern specifications (API 36). To make matters worse, the original development environment, including the local source code and the original signing keystore, had been lost on a dead hard drive.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;context&quot;&gt;Context&lt;&#x2F;h3&gt;
&lt;p&gt;Updating an app on the Google Play Store is not just about uploading an APK. The new release must:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Retain the exact same Application ID (package name).&lt;&#x2F;li&gt;
&lt;li&gt;Be signed with the exact same cryptographic key (or use Play App Signing).&lt;&#x2F;li&gt;
&lt;li&gt;Meet the latest &lt;code&gt;targetSdkVersion&lt;&#x2F;code&gt; requirements.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;what-i-tried&quot;&gt;What I Tried&lt;&#x2F;h3&gt;
&lt;p&gt;I initially tried to create a brand new application with a slightly different package name (&lt;code&gt;com.myapp.v2&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-failed&quot;&gt;What Failed&lt;&#x2F;h3&gt;
&lt;p&gt;Creating a new application means starting from scratch. All previous reviews, download history, and existing users are lost. Existing users will not receive the update automatically; they would have to find the new app manually. This was unacceptable.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-worked-technical-explanation&quot;&gt;What Worked &amp;amp; Technical Explanation&lt;&#x2F;h3&gt;
&lt;p&gt;I had to recover the original identity and modernize the codebase.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;1. Source Recovery and Preservation&lt;&#x2F;strong&gt;
Fortunately, I was able to recover a backup of the source code. The very first step was initializing a Git repository and pushing it to GitHub. Once the source was recovered, the code was preserved in GitHub so that the project would no longer depend on a single local copy.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;2. Modernizing the API Level&lt;&#x2F;strong&gt;
I updated the &lt;code&gt;build.gradle&lt;&#x2F;code&gt; file to reflect modern requirements:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Updated &lt;code&gt;compileSdkVersion&lt;&#x2F;code&gt; and &lt;code&gt;targetSdkVersion&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Upgraded deprecated dependencies that were incompatible with newer Android versions.&lt;&#x2F;li&gt;
&lt;li&gt;Tested the application on Android 14+ emulators to ensure permissions and UI rendering remained functional.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;3. The Keystore Crisis&lt;&#x2F;strong&gt;
The Android signing key is critical. Without it, Google Play rejects the update because it cannot cryptographically prove the update came from the original author. Luckily, I had enrolled the app in &lt;strong&gt;Play App Signing&lt;&#x2F;strong&gt; during the original upload.&lt;&#x2F;p&gt;
&lt;p&gt;This meant the actual production signing key was securely stored by Google. I only needed an “Upload Key.” Because I had lost the original upload key, I contacted Google Play Developer Support to reset it. I generated a new secure keystore, provided Google with the new &lt;code&gt;.pem&lt;&#x2F;code&gt; certificate, and they linked it to my app.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;4. Production Release (Version 4)&lt;&#x2F;strong&gt;
With the code modernized and the new signing configuration securely backed up (with passwords stored in a password manager, NOT in the Git repo), I built the release bundle. I uploaded Version 4 to the Play Console, filled out the new Data Safety declarations, and successfully rolled it out to production.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;lessons-learned&quot;&gt;Lessons Learned&lt;&#x2F;h3&gt;
&lt;p&gt;Losing the original development environment does not necessarily mean the application itself is lost, but package identity, signing credentials, source code, and release history must be treated as critical assets.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-i-would-do-differently&quot;&gt;What I Would Do Differently&lt;&#x2F;h3&gt;
&lt;p&gt;I will never rely on a local machine for code storage again. Every project, no matter how small, gets pushed to a remote version control system immediately. Furthermore, keystore files and their credentials must be treated as high-priority secrets and stored in redundant, encrypted cloud backups.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Flutter Splash Screens vs Native Android Startup Screens</title>
        <published>2026-01-25T00:00:00+00:00</published>
        <updated>2026-01-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Syed Zubyl N
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://syedzubyl.space/blog/flutter-splash-screens/"/>
        <id>https://syedzubyl.space/blog/flutter-splash-screens/</id>
        
        <content type="html" xml:base="https://syedzubyl.space/blog/flutter-splash-screens/">&lt;h3 id=&quot;the-problem&quot;&gt;The Problem&lt;&#x2F;h3&gt;
&lt;p&gt;A client wanted a highly customized, complex, animated Flutter-style splash screen to play the moment the user tapped the app icon. They wanted their branding to animate immediately, replacing the “boring” default app launch experience.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;context&quot;&gt;Context&lt;&#x2F;h3&gt;
&lt;p&gt;When an Android application launches, there is an unavoidable window of time where the OS loads the app process into memory. During this time, Android displays a system-controlled launch screen. With the introduction of Android 12, Google enforced the &lt;code&gt;SplashScreen&lt;&#x2F;code&gt; API, standardizing this experience to show the app icon and a background color.&lt;&#x2F;p&gt;
&lt;p&gt;Flutter operates inside an Android Activity. The Flutter engine must initialize, load the Dart isolate, and render the first frame. This takes time.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-i-tried&quot;&gt;What I Tried&lt;&#x2F;h3&gt;
&lt;p&gt;The client wanted the animation to start instantly. I initially tried putting the animation directly into the first Flutter widget loaded by &lt;code&gt;runApp()&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-failed&quot;&gt;What Failed&lt;&#x2F;h3&gt;
&lt;p&gt;This resulted in a jarring experience:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;User taps app.&lt;&#x2F;li&gt;
&lt;li&gt;System shows Android 12 static splash screen (icon + background).&lt;&#x2F;li&gt;
&lt;li&gt;System splash disappears.&lt;&#x2F;li&gt;
&lt;li&gt;White flash (briefly, as Flutter attaches).&lt;&#x2F;li&gt;
&lt;li&gt;Flutter animated splash screen begins.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;It looked like two separate splash screens playing back-to-back.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-worked-technical-explanation&quot;&gt;What Worked &amp;amp; Technical Explanation&lt;&#x2F;h3&gt;
&lt;p&gt;The actual limitation is that the system-controlled Android launch splash occurs &lt;em&gt;before&lt;&#x2F;em&gt; the Flutter UI is ready, especially under Android 12+ splash-screen rules. A Flutter animation can begin after the Flutter engine&#x2F;UI becomes available, but it does not replace the system launch sequence in the same way.&lt;&#x2F;p&gt;
&lt;p&gt;The correct approach was a hybrid hand-off:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Configure the native Android 12 &lt;code&gt;SplashScreen&lt;&#x2F;code&gt; via &lt;code&gt;styles.xml&lt;&#x2F;code&gt; to match the exact background color and static logo of the first frame of the Flutter animation.&lt;&#x2F;li&gt;
&lt;li&gt;Use the &lt;code&gt;flutter_native_splash&lt;&#x2F;code&gt; package to hold the native splash screen up until Flutter is fully rendered.&lt;&#x2F;li&gt;
&lt;li&gt;Once Flutter renders its first frame, immediately begin the complex Flutter animation from the exact state the native splash left off.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;lt;!-- android&#x2F;app&#x2F;src&#x2F;main&#x2F;res&#x2F;values-v31&#x2F;styles.xml --&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;style&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;LaunchTheme&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; parent&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Theme.SplashScreen&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;item&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;windowSplashScreenBackground&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;@color&#x2F;brand_background&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;item&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;item&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;windowSplashScreenAnimatedIcon&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;@drawable&#x2F;launch_icon&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;item&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;item&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;postSplashScreenTheme&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;@style&#x2F;NormalTheme&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;item&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;style&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;lessons-learned&quot;&gt;Lessons Learned&lt;&#x2F;h3&gt;
&lt;p&gt;You cannot fight the OS. The Android lifecycle dictates what happens before your application code runs. Understanding the boundaries between native Android processes and the Flutter engine is critical for smooth UX.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-i-would-do-differently&quot;&gt;What I Would Do Differently&lt;&#x2F;h3&gt;
&lt;p&gt;I will clarify the distinction between “OS Launch Screen” and “App Onboarding Animation” to clients early on. Managing expectations around what happens in the first 500ms of an app’s lifecycle prevents impossible requests later.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Android App Bar Compatibility: When Client Requirements Meet Platform Defaults</title>
        <published>2026-01-10T00:00:00+00:00</published>
        <updated>2026-01-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Syed Zubyl N
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://syedzubyl.space/blog/android-app-bar-compatibility/"/>
        <id>https://syedzubyl.space/blog/android-app-bar-compatibility/</id>
        
        <content type="html" xml:base="https://syedzubyl.space/blog/android-app-bar-compatibility/">&lt;h3 id=&quot;the-problem&quot;&gt;The Problem&lt;&#x2F;h3&gt;
&lt;p&gt;During a recent project, a client expected a highly specific app-bar appearance. The request was straightforward on paper: make the Flutter application look exactly like an Android-native&#x2F;default implementation, matching a specific older Android version’s aesthetic they were used to.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;context&quot;&gt;Context&lt;&#x2F;h3&gt;
&lt;p&gt;When building cross-platform applications with Flutter, the framework paints every pixel on the screen using its own rendering engine (Skia&#x2F;Impeller). It does not use OEM native widgets. While Flutter’s Material widgets do an incredible job of mimicking native Android components, they default to the current Material Design guidelines (Material 3). The client, however, wanted an exact replica of an older Android native app bar behavior and shadowing.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-i-tried&quot;&gt;What I Tried&lt;&#x2F;h3&gt;
&lt;p&gt;I initially tried overriding the &lt;code&gt;AppBar&lt;&#x2F;code&gt; theme properties:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;dart&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;AppBar&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  elevation&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 4.0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  shadowColor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; Colors&lt;&#x2F;span&gt;&lt;span&gt;.black.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;withOpacity&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;0.5&lt;&#x2F;span&gt;&lt;span&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  backgroundColor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; Theme&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;of&lt;&#x2F;span&gt;&lt;span&gt;(context).primaryColor,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  title&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;: const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; Text&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;Dashboard&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This got us close, but the exact gradient of the shadow and the specific typographic alignment didn’t perfectly match the legacy Android native view the client had side-by-side on their device.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-failed&quot;&gt;What Failed&lt;&#x2F;h3&gt;
&lt;p&gt;Attempting to perfectly mimic a deprecated OEM native view using a modern cross-platform framework’s rendering engine became a game of diminishing returns. I tried building a completely custom &lt;code&gt;PreferredSizeWidget&lt;&#x2F;code&gt; with complex box shadows, but it felt brittle.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-worked-technical-explanation&quot;&gt;What Worked &amp;amp; Technical Explanation&lt;&#x2F;h3&gt;
&lt;p&gt;The solution was a conversation rather than a code hack. The requested result could not be reproduced exactly with the existing implementation constraints without completely changing the approach or hardcoding fragile design values.&lt;&#x2F;p&gt;
&lt;p&gt;I explained to the client the difference between native Android UI conventions (which vary wildly between Android 10, 12, and 14) and Flutter’s unified rendering model. I demonstrated how adhering to Flutter’s Material 3 defaults actually provided &lt;em&gt;better&lt;&#x2F;em&gt; compatibility and visual consistency across all modern Android devices, rather than forcing an older, device-specific look.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;lessons-learned&quot;&gt;Lessons Learned&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Client expectations vs. platform realities:&lt;&#x2F;strong&gt; Clients often don’t know the difference between a “native default” and a “custom design.” To them, what they see on their personal phone is the “default.”&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Push back with technical reasoning:&lt;&#x2F;strong&gt; Instead of spending hours tweaking pixel-perfect shadows to match an outdated OS, it’s better to explain the benefits of modern platform defaults.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;what-i-would-do-differently&quot;&gt;What I Would Do Differently&lt;&#x2F;h3&gt;
&lt;p&gt;Next time, I will establish the baseline UI components using Flutter’s default Material 3 implementation during the very first design review, ensuring the client signs off on the framework’s native look before development begins.&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
