<?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: Rajen Trivedi</title>
    <description>The latest articles on DEV Community by Rajen Trivedi (@rajen_trivedi).</description>
    <link>https://dev.to/rajen_trivedi</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3766954%2Fe8a60617-44bb-4ced-840f-6a2350835073.png</url>
      <title>DEV Community: Rajen Trivedi</title>
      <link>https://dev.to/rajen_trivedi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rajen_trivedi"/>
    <language>en</language>
    <item>
      <title>jsoup 1.23.1 is out: here's what actually changed</title>
      <dc:creator>Rajen Trivedi</dc:creator>
      <pubDate>Thu, 06 Aug 2026 18:25:55 +0000</pubDate>
      <link>https://dev.to/rajen_trivedi/jsoup-1231-is-out-heres-what-actually-changed-4d5i</link>
      <guid>https://dev.to/rajen_trivedi/jsoup-1231-is-out-heres-what-actually-changed-4d5i</guid>
      <description>&lt;p&gt;jsoup 1.23.1 just dropped and this one is worth paying attention to. Not just a patch release. There are real parser speed gains, meaningful memory improvements, and a security fix that Android and server-side Java devs should know about.&lt;/p&gt;

&lt;p&gt;Here's what changed and why it matters.&lt;/p&gt;




&lt;h2&gt;
  
  
  Add the dependency
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Gradle (Groovy):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'org.jsoup:jsoup:1.23.1'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Gradle (Kotlin DSL):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"org.jsoup:jsoup:1.23.1"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Maven:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.jsoup&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;jsoup&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.23.1&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;This was clearly the main focus of the release. Numbers are from OpenJDK 21 benchmarks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;String parsing is 18% faster on average.&lt;/strong&gt;&lt;br&gt;
The most common use case just got noticeably quicker.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Document&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Jsoup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;htmlString&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;InputStream parsing is 11% faster.&lt;/strong&gt;&lt;br&gt;
Good news if you're parsing HTTP responses or file streams directly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Document&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Jsoup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputStream&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;baseUri&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Source position tracking is 70% faster.&lt;/strong&gt;&lt;br&gt;
If you use &lt;code&gt;Parser.htmlParser().setTrackPosition(true)&lt;/code&gt;, this is a big one. It was the slowest mode before. Not anymore.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Parser&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;htmlParser&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;setTrackPosition&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;Document&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Jsoup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;htmlString&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;baseUri&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Source-tracked DOMs use 58 to 65% less memory on medium to large documents.&lt;/strong&gt;&lt;br&gt;
And the gains hold under concurrent parsing without introducing new contention. If you parse in parallel, you get the memory savings without thread safety trade-offs.&lt;/p&gt;


&lt;h2&gt;
  
  
  Security fix
&lt;/h2&gt;

&lt;p&gt;The Cleaner had an issue where malformed HTML could sneak markup through when cleaned with a custom &lt;code&gt;Safelist&lt;/code&gt; that allowed certain raw-text elements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Custom Safelists with raw-text elements were affected&lt;/span&gt;
&lt;span class="nc"&gt;Safelist&lt;/span&gt; &lt;span class="n"&gt;safelist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Safelist&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;relaxed&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;addTags&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"script"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;cleaned&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Jsoup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;malformedHtml&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;safelist&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// In previous versions, some markup could survive this incorrectly&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Built-in Safelists like &lt;code&gt;Safelist.basic()&lt;/code&gt; and &lt;code&gt;Safelist.relaxed()&lt;/code&gt; are not affected. But if you built a custom Safelist with unusual raw-text tag permissions, update now.&lt;/p&gt;




&lt;h2&gt;
  
  
  What else changed
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Better HTML spec alignment.&lt;/strong&gt;&lt;br&gt;
Parsing of &lt;code&gt;noscript&lt;/code&gt;, CDATA, SVG, and MathML now aligns more closely with the HTML living standard. If your parser results on edge-case documents ever felt slightly off, this release tightens that up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spec-correct HTTP redirects.&lt;/strong&gt;&lt;br&gt;
Redirect handling is now safer and follows the HTTP spec more accurately. Fewer surprises when dealing with servers that do non-standard redirect chains.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fast immutable &lt;code&gt;Element#classList()&lt;/code&gt;.&lt;/strong&gt;&lt;br&gt;
Returns an immutable view of the element's class list. Faster to call, safer to use since you can't accidentally mutate it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Element&lt;/span&gt; &lt;span class="n"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;selectFirst&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"div.card"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;el&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;classList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// immutable, no defensive copy needed&lt;/span&gt;
&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// [card, featured, active]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Direct outer-HTML output to an &lt;code&gt;Appendable&lt;/code&gt;.&lt;/strong&gt;&lt;br&gt;
You can now write an element's outer HTML directly to a &lt;code&gt;StringBuilder&lt;/code&gt;, &lt;code&gt;Writer&lt;/code&gt;, or any &lt;code&gt;Appendable&lt;/code&gt; without going through a &lt;code&gt;String&lt;/code&gt; allocation first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;StringBuilder&lt;/span&gt; &lt;span class="n"&gt;sb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StringBuilder&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;outerHtml&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// no intermediate String created&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Bug fixes across the board:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RCDATA parsing corrections&lt;/li&gt;
&lt;li&gt;XML conversion edge cases&lt;/li&gt;
&lt;li&gt;Tag-name handling&lt;/li&gt;
&lt;li&gt;Cleaner link detection&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Should you update?
&lt;/h2&gt;

&lt;p&gt;Yes, especially if you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;setTrackPosition(true)&lt;/code&gt;: the 70% speed gain alone is worth it&lt;/li&gt;
&lt;li&gt;Parse large documents concurrently: the memory savings are real&lt;/li&gt;
&lt;li&gt;Built a custom &lt;code&gt;Safelist&lt;/code&gt; with raw-text elements: the security fix applies to you&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For everyone else it's still an easy drop-in upgrade with no API changes.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Reference:&lt;/strong&gt; &lt;a href="https://github.com/jhy/jsoup/releases" rel="noopener noreferrer"&gt;jsoup releases on GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>kotlin</category>
      <category>android</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Server Commands I Actually Use, Part 2: Finding What's Actually Deployed</title>
      <dc:creator>Rajen Trivedi</dc:creator>
      <pubDate>Thu, 06 Aug 2026 18:15:32 +0000</pubDate>
      <link>https://dev.to/rajen_trivedi/server-commands-i-actually-use-part-2-finding-whats-actually-deployed-37dk</link>
      <guid>https://dev.to/rajen_trivedi/server-commands-i-actually-use-part-2-finding-whats-actually-deployed-37dk</guid>
      <description>&lt;p&gt;Hey Dev.to 👋&lt;/p&gt;

&lt;p&gt;If you came from Medium, welcome back. Part 1 of this series (Nginx commands for managing a Linux server) got a good response over there, so I decided to keep the series going but bring Part 2 here to Dev.to for a change of scenery.&lt;/p&gt;

&lt;p&gt;If you haven't read Part 1 yet, it covers the core Nginx workflow: checking if Nginx is running, testing configs before reloading, enabling and disabling sites, reading logs, and testing URLs. You can find it here:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Part 1 on Medium:&lt;/strong&gt; &lt;a href="https://medium.com/@rajen-trivedi/nginx-commands-i-actually-use-a-running-guide-for-managing-a-linux-server-60ed78d03186?sharedUserId=rajen-trivedi" rel="noopener noreferrer"&gt;Nginx Commands I Actually Use: A Running Guide for Managing a Linux Server&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This part is different. It's not about Nginx specifically. It's about a problem that shows up after you've been deploying things for a while.&lt;/p&gt;

&lt;p&gt;You've got a frontend here, a backend there, some Nginx config you wrote three weeks ago, maybe a Docker container you spun up to test something and then... left running. And then one day something breaks and you're sitting there thinking: okay, what even &lt;em&gt;is&lt;/em&gt; on this server right now?&lt;/p&gt;

&lt;p&gt;That's what this part is about.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvrtw0pul3f29zi12dmmt.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvrtw0pul3f29zi12dmmt.png" alt=" " width="800" height="1200"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Quick note on setup:&lt;/strong&gt; I work from a Windows laptop, connecting over SSH via PowerShell. All the commands below run on the server after you SSH in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="o"&gt;{&lt;/span&gt;deploy-user&lt;span class="o"&gt;}&lt;/span&gt;@&lt;span class="o"&gt;{&lt;/span&gt;your-server-ip&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Anything in &lt;code&gt;{curly braces}&lt;/code&gt; is a placeholder. Swap in your own values before running.&lt;/p&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;List All Files (Structure Only)&lt;/li&gt;
&lt;li&gt;Tree View with Sizes&lt;/li&gt;
&lt;li&gt;Full Deployment Snapshot in One Command&lt;/li&gt;
&lt;li&gt;Find What's Eating Your Disk Space&lt;/li&gt;
&lt;li&gt;Quick Reference&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  1. List All Files (Structure Only)
&lt;/h2&gt;

&lt;p&gt;The bluntest possible tool. Shows every file under the directories you care about, sorted, no frills.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find /var/www/ /home/&lt;span class="o"&gt;{&lt;/span&gt;deploy-user&lt;span class="o"&gt;}&lt;/span&gt;/ &lt;span class="nt"&gt;-type&lt;/span&gt; f 2&amp;gt;/dev/null | &lt;span class="nb"&gt;sort&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&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;/home/deploy/api/build.gradle.kts
/home/deploy/api/src/main/Application.kt
/var/www/{site-1}/index.html
/var/www/{site-1}/robots.txt
/var/www/{site-2}/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Good for a quick "what's actually in here" check. Pipe it through &lt;code&gt;grep&lt;/code&gt; if you're looking for something specific, like a file you vaguely remember deploying but can't place.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find /var/www/ /home/&lt;span class="o"&gt;{&lt;/span&gt;deploy-user&lt;span class="o"&gt;}&lt;/span&gt;/ &lt;span class="nt"&gt;-type&lt;/span&gt; f 2&amp;gt;/dev/null | &lt;span class="nb"&gt;sort&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"robots"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&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;/var/www/{site-1}/robots.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. Tree View with Sizes
&lt;/h2&gt;

&lt;p&gt;Same idea but actually readable. Shows the folder structure visually with file sizes alongside.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Only needed once if tree isn't installed&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; tree

tree &lt;span class="nt"&gt;-h&lt;/span&gt; /var/www/ /home/&lt;span class="o"&gt;{&lt;/span&gt;deploy-user&lt;span class="o"&gt;}&lt;/span&gt;/ &lt;span class="nt"&gt;-I&lt;/span&gt; &lt;span class="s1"&gt;'node_modules|.git'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&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;/var/www/
├── [4.0K]  {site-1}
│   ├── [ 612]  index.html
│   └── [ 128]  robots.txt
└── [4.0K]  {site-2}
    └── [ 890]  index.html

/home/deploy/
└── [4.0K]  api
    ├── [1.2K]  build.gradle.kts
    └── [4.0K]  src
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-I 'node_modules|.git'&lt;/code&gt; flag skips folders that have thousands of files and none of them are yours. Add more patterns as needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tree &lt;span class="nt"&gt;-h&lt;/span&gt; /var/www/ /home/&lt;span class="o"&gt;{&lt;/span&gt;deploy-user&lt;span class="o"&gt;}&lt;/span&gt;/ &lt;span class="nt"&gt;-I&lt;/span&gt; &lt;span class="s1"&gt;'node_modules|.git|build|.gradle'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I reach for this one more than the flat list. The tree shape makes it much easier to see what belongs where at a glance.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Full Deployment Snapshot in One Command
&lt;/h2&gt;

&lt;p&gt;This is the one I actually use when I need to remember what I've built.&lt;/p&gt;

&lt;p&gt;I kept running &lt;code&gt;ls&lt;/code&gt; on different directories separately, then forgetting what I'd already checked. So I started keeping one long command that dumps everything relevant in one go: frontend folders, backend apps, Nginx configs, Docker containers, top to bottom.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"=== FRONTEND: {site-1} ==="&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
find /var/www/&lt;span class="o"&gt;{&lt;/span&gt;site-1&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-maxdepth&lt;/span&gt; 1 &lt;span class="nt"&gt;-type&lt;/span&gt; f | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"=== FRONTEND: {site-2} ==="&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
find /var/www/&lt;span class="o"&gt;{&lt;/span&gt;site-2&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-maxdepth&lt;/span&gt; 1 &lt;span class="nt"&gt;-type&lt;/span&gt; f | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"=== BACKEND APPS ==="&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
find /home/&lt;span class="o"&gt;{&lt;/span&gt;deploy-user&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-maxdepth&lt;/span&gt; 2 &lt;span class="nt"&gt;-type&lt;/span&gt; f 2&amp;gt;/dev/null | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;".git"&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"=== NGINX CONFIGS ==="&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; /etc/nginx/sites-available/ &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"=== DOCKER CONTAINERS ==="&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
docker ps &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="nt"&gt;--format&lt;/span&gt; &lt;span class="s2"&gt;"table {{.Names}}&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s2"&gt;{{.Image}}&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s2"&gt;{{.Status}}&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s2"&gt;{{.Ports}}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output (what it actually looks like):&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;=== FRONTEND: {site-1} ===
/var/www/{site-1}/index.html
/var/www/{site-1}/robots.txt

=== FRONTEND: {site-2} ===
/var/www/{site-2}/index.html

=== BACKEND APPS ===
/home/deploy/api/build.gradle.kts
/home/deploy/api/Dockerfile

=== NGINX CONFIGS ===
-rw-r--r-- 1 root root 1.1K Jul 20 {site-1}
-rw-r--r-- 1 root root  980 Jul 31 {site-2}

=== DOCKER CONTAINERS ===
NAMES        IMAGE          STATUS         PORTS
{app-name}   {image-name}   Up 3 days      0.0.0.0:{port}-&amp;gt;{port}/tcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command looks long but it's not complicated. It's literally just the same few commands chained together with &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; and &lt;code&gt;echo&lt;/code&gt; separators. Adapt the folder paths and site names to match your setup, then save it somewhere because you will want it again.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Find What's Eating Your Disk Space
&lt;/h2&gt;

&lt;p&gt;I added this one after noticing the server getting slower and realizing I had months of old build artifacts sitting in &lt;code&gt;/home/deploy/api/build&lt;/code&gt; that nobody had cleaned up. This command would have caught it immediately.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;du&lt;/span&gt; &lt;span class="nt"&gt;-ah&lt;/span&gt; /var/www/ /home/&lt;span class="o"&gt;{&lt;/span&gt;deploy-user&lt;span class="o"&gt;}&lt;/span&gt;/ 2&amp;gt;/dev/null | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-rh&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-50&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&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;1.2G  /home/deploy/api/build
340M  /home/deploy/api/build/libs/app.jar
88M   /var/www/{site-1}/assets
12M   /var/www/{site-2}
4.0K  /var/www/{site-2}/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Biggest to smallest, top 50 results. If your disk is filling up and you don't know why, this usually tells you in about three seconds.&lt;/p&gt;

&lt;p&gt;Drop &lt;code&gt;head -50&lt;/code&gt; if you want the full unfiltered list.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Reference
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Flat file list:&lt;/strong&gt; &lt;code&gt;find /var/www/ /home/{deploy-user}/ -type f 2&amp;gt;/dev/null | sort&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tree with sizes:&lt;/strong&gt; &lt;code&gt;tree -h /var/www/ /home/{deploy-user}/ -I 'node_modules|.git'&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full snapshot:&lt;/strong&gt; the long one in section 3 (copy, adapt, save it)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Disk usage:&lt;/strong&gt; &lt;code&gt;du -ah /var/www/ /home/{deploy-user}/ 2&amp;gt;/dev/null | sort -rh | head -50&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;That's Part 2. Short and focused on one problem: knowing what's actually on your server.&lt;/p&gt;

&lt;p&gt;Stay tuned for Part 3.&lt;/p&gt;

&lt;p&gt;If Part 1 on Medium was useful too, drop it a like there. Helps more people find it.&lt;/p&gt;

</description>
      <category>nginx</category>
      <category>linux</category>
      <category>devops</category>
      <category>webdev</category>
    </item>
    <item>
      <title>What's new in our latest Android dependency bumps — ConstraintLayout, Firebase, Intercom, Auth0</title>
      <dc:creator>Rajen Trivedi</dc:creator>
      <pubDate>Sat, 01 Aug 2026 18:51:37 +0000</pubDate>
      <link>https://dev.to/rajen_trivedi/whats-new-in-our-latest-android-dependency-bumps-constraintlayout-firebase-intercom-auth0-3e2e</link>
      <guid>https://dev.to/rajen_trivedi/whats-new-in-our-latest-android-dependency-bumps-constraintlayout-firebase-intercom-auth0-3e2e</guid>
      <description>&lt;p&gt;We just bumped four dependencies in the app. Here's what each one brings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'androidx.constraintlayout:constraintlayout:2.2.2'&lt;/span&gt;
&lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="nf"&gt;platform&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'com.google.firebase:firebase-bom:34.17.0'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'io.intercom.android:intercom-sdk:18.6.0'&lt;/span&gt;
&lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'com.auth0.android:auth0:4.0.1'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ConstraintLayout 2.2.2
&lt;/h2&gt;

&lt;p&gt;The library's in maintenance mode now — Google's steering everyone toward Compose for new UI — so releases here are small, focused patches. This one carries forward a binary compatibility fix in &lt;code&gt;constraintlayout-core&lt;/code&gt; that landed in the 2.2.x line.&lt;/p&gt;

&lt;h2&gt;
  
  
  Firebase BoM 34.17.0
&lt;/h2&gt;

&lt;p&gt;The BoM pins compatible versions across every Firebase library you pull in. This release lands close behind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Firebase AI Logic (17.14.0)&lt;/strong&gt; — new factory methods exposing &lt;code&gt;thoughtSignature&lt;/code&gt;/&lt;code&gt;isThought&lt;/code&gt; on response parts, plus automatic function calling for &lt;code&gt;LiveGenerativeModel&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authentication (24.2.0)&lt;/strong&gt; — fixed an auth timeout on dual-stack Wi-Fi, where long IPv6 timeouts were blocking IPv4 fallback&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud Firestore (26.4.1)&lt;/strong&gt; — now caches documents over 1MB by chunk-reading from local SQLite; fixed a debug-logging OOM caused by large payloads&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud Messaging (25.1.1)&lt;/strong&gt; — fixed a re-registration bug tied to Firebase installation ID changes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Crashlytics (20.1.0)&lt;/strong&gt; — on API 37+, fatal event reports now carry OOM/anomaly context from the ProfilingManager API&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Firebase Installations (19.1.2)&lt;/strong&gt; — internal storage moved from SharedPreferences to DataStore&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance Monitoring (22.0.6)&lt;/strong&gt; — fixed &lt;code&gt;_app_start&lt;/code&gt; traces getting incorrectly suppressed on API 34+&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SQL Connect (17.3.2)&lt;/strong&gt; — several fixes to realtime query subscriptions around auth-token refresh and expiry&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Intercom Android SDK 18.6.0
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Pinch-to-zoom, double-tap-to-zoom, and pan on full-screen image attachments&lt;/li&gt;
&lt;li&gt;Fixed an ANR during &lt;code&gt;Intercom.initialize()&lt;/code&gt; caused by Keystore and persisted-identity reads blocking the calling thread&lt;/li&gt;
&lt;li&gt;Fixed the keyboard covering form fields in Canvas Kit sheets — IME insets are now handled correctly&lt;/li&gt;
&lt;li&gt;Fixed a crash from a null &lt;code&gt;trustedFileExtensions&lt;/code&gt; value in persisted attachment settings&lt;/li&gt;
&lt;li&gt;Fixed empty list items rendering a dangling bullet in message and survey text&lt;/li&gt;
&lt;li&gt;Intercom's flagged that the next major version moves to Kotlin 2.3 and will require a minimum Kotlin version of 2.0, for binary compatibility&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Auth0.Android 4.0.1
&lt;/h2&gt;

&lt;p&gt;4.0.1 sits on top of the 4.0.0 major release, which is where the breaking changes live:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;useDPoP&lt;/code&gt; moved off &lt;code&gt;WebAuthProvider&lt;/code&gt; and onto the login builder&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PasskeyProvider&lt;/code&gt; and &lt;code&gt;PasskeyManager&lt;/code&gt; have been removed, with no direct replacement in this version&lt;/li&gt;
&lt;li&gt;The redundant &lt;code&gt;SecureCredentialsManager&lt;/code&gt; constructors are gone, down to a single constructor&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;minSdkVersion&lt;/code&gt; is now 31+&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;New in exchange: &lt;code&gt;SSOCredentialsDeserializer&lt;/code&gt; for SSO credential deserialization, &lt;code&gt;Storage.removeAll()&lt;/code&gt; with a default 60s minimum TTL, ephemeral session support for Chrome Custom Tabs login, and &lt;code&gt;DefaultClient&lt;/code&gt; rebuilt around a Builder pattern for configurable HTTP client options.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:constraintlayout/" rel="noopener noreferrer"&gt;ConstraintLayout source&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://firebase.google.com/support/release-notes/android" rel="noopener noreferrer"&gt;Firebase Android release notes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/intercom/intercom-android/releases" rel="noopener noreferrer"&gt;Intercom Android SDK releases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/auth0/Auth0.Android/releases" rel="noopener noreferrer"&gt;Auth0.Android releases&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>firebase</category>
      <category>androiddev</category>
    </item>
    <item>
      <title>How to Generate APK from AAB File Using Bundletool (Super Simple Guide)</title>
      <dc:creator>Rajen Trivedi</dc:creator>
      <pubDate>Thu, 09 Apr 2026 16:19:33 +0000</pubDate>
      <link>https://dev.to/rajen_trivedi/how-to-generate-apk-from-aab-file-using-bundletool-super-simple-guide-48ne</link>
      <guid>https://dev.to/rajen_trivedi/how-to-generate-apk-from-aab-file-using-bundletool-super-simple-guide-48ne</guid>
      <description>&lt;p&gt;Hey devs! 👋&lt;/p&gt;

&lt;p&gt;We all know Google Play now prefers &lt;strong&gt;Android App Bundles (AAB)&lt;/strong&gt; for publishing because they generate optimized APKs for each device.&lt;/p&gt;

&lt;p&gt;But in real-world development, we often need a single &lt;strong&gt;APK&lt;/strong&gt; for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Testing on physical devices&lt;/li&gt;
&lt;li&gt;Sharing with QA teams&lt;/li&gt;
&lt;li&gt;Quick installs without Play Store&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is the &lt;strong&gt;easiest and official way&lt;/strong&gt; to convert your &lt;code&gt;.aab&lt;/code&gt; file into an &lt;code&gt;.apk&lt;/code&gt; using &lt;strong&gt;Google’s Bundletool&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Step 1: Download Bundletool
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Go to the official GitHub releases:&lt;br&gt;
👉 &lt;a href="https://github.com/google/bundletool/releases/latest" rel="noopener noreferrer"&gt;https://github.com/google/bundletool/releases/latest&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Download the latest file:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   bundletool-all-x.x.x.jar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Place the &lt;code&gt;.jar&lt;/code&gt; file:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;In the same folder as your &lt;code&gt;.aab&lt;/code&gt; file
 &lt;strong&gt;OR&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Remember its full path&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 2: Generate &lt;code&gt;.apks&lt;/code&gt; File (Universal Mode)
&lt;/h2&gt;

&lt;p&gt;Open &lt;strong&gt;Command Prompt (Windows)&lt;/strong&gt; or &lt;strong&gt;Terminal (Mac/Linux)&lt;/strong&gt; and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;java &lt;span class="nt"&gt;-jar&lt;/span&gt; bundletool-all-1.18.3.jar build-apks &lt;span class="nt"&gt;--bundle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;app-release.aab &lt;span class="nt"&gt;--output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;myapp.apks &lt;span class="nt"&gt;--mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;universal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🔁 Replace:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bundletool-all-1.18.3.jar&lt;/code&gt; → your actual jar filename&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;app-release.aab&lt;/code&gt; → your AAB file path/name&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;📦 Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;myapp.apks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;By default, this is signed with a debug keystore.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  📦 Step 3: Extract the APK
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Rename the file:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   ren myapp.apks myapp.zip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Extract it using:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;WinRAR&lt;/li&gt;
&lt;li&gt;7-Zip&lt;/li&gt;
&lt;li&gt;Default OS extractor&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Inside, you’ll find:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   universal.apk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🎉 That’s your final APK!&lt;/p&gt;

&lt;p&gt;You can rename it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app-release.apk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔐 Generate Signed APK (Recommended for QA)
&lt;/h2&gt;

&lt;p&gt;If you want a &lt;strong&gt;release-signed APK&lt;/strong&gt;, use your keystore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;java &lt;span class="nt"&gt;-jar&lt;/span&gt; bundletool-all-1.18.3.jar build-apks &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--bundle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;app-release.aab &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;myapp.apks &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;universal &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--ks&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-keystore.jks &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--ks-key-alias&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_alias &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--ks-pass&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;pass:your_keystore_password &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--key-pass&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;pass:your_key_password
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧠 Common Tips &amp;amp; Troubleshooting
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✅ Check Java installation:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  java &lt;span class="nt"&gt;-version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;📁 Keep files in the same folder to avoid path issues&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;📦 Universal APK is larger (contains all device configs)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;🚫 Not for Play Store — upload AAB only&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;❌ Error: &lt;code&gt;Unable to access jarfile&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check filename and path carefully&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  🏁 Conclusion
&lt;/h2&gt;

&lt;p&gt;That’s it! 🎯&lt;/p&gt;

&lt;p&gt;In less than &lt;strong&gt;2 minutes&lt;/strong&gt;, you can convert any &lt;code&gt;.aab&lt;/code&gt; into an &lt;code&gt;.apk&lt;/code&gt; using Bundletool — no GUI tools needed.&lt;/p&gt;

&lt;p&gt;If you run into any issues, drop the error in the comments — happy to help! 😊&lt;/p&gt;




</description>
      <category>android</category>
      <category>apk</category>
      <category>aab</category>
      <category>bundletool</category>
    </item>
  </channel>
</rss>
