<?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: Yusuff Jokanola O.</title>
    <description>The latest articles on DEV Community by Yusuff Jokanola O. (@jocanola).</description>
    <link>https://dev.to/jocanola</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%2F415451%2Fe9c10a4c-a90d-4cf9-b0ba-686f758ee917.jpeg</url>
      <title>DEV Community: Yusuff Jokanola O.</title>
      <link>https://dev.to/jocanola</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jocanola"/>
    <language>en</language>
    <item>
      <title>Understanding OWASP M1 (2024): Improper Credential Usage in React Native/Expo and How to Mitigate It</title>
      <dc:creator>Yusuff Jokanola O.</dc:creator>
      <pubDate>Fri, 31 Oct 2025 19:49:52 +0000</pubDate>
      <link>https://dev.to/jocanola/understanding-owasp-m1-2024-improper-credential-usage-in-react-nativeexpo-and-how-to-mitigate-it-2657</link>
      <guid>https://dev.to/jocanola/understanding-owasp-m1-2024-improper-credential-usage-in-react-nativeexpo-and-how-to-mitigate-it-2657</guid>
      <description>&lt;p&gt;&lt;strong&gt;Improper Credential Usage (M1)&lt;/strong&gt; tops the OWASP Mobile Top 10 (2024) because it hits the core of mobile security: &lt;em&gt;protecting secrets and sensitive data&lt;/em&gt;. This vulnerability occurs when apps mishandle credentials — whether hardcoded API keys, tokens, or user authentication data — within insecure client environments.&lt;/p&gt;

&lt;p&gt;For React Native and Expo developers, this issue is particularly severe. Since the JavaScript bundle ships with the app, anyone with basic reverse-engineering tools can easily peek into the source, exposing credentials you thought were “hidden.”&lt;/p&gt;

&lt;p&gt;Let’s break down what this means for you — and how to fix it properly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding M1: The Risk of Client-Side Credential Exposure
&lt;/h2&gt;

&lt;p&gt;Improper Credential Usage arises when developers treat the mobile client like a private backend. The problem? &lt;strong&gt;Your app code runs entirely on the user’s device&lt;/strong&gt;, meaning anything embedded in it — even environment variables — can be extracted from the &lt;code&gt;.apk&lt;/code&gt; or &lt;code&gt;.ipa&lt;/code&gt; file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Common M1 Scenarios
&lt;/h3&gt;

&lt;h4&gt;
  
  
  A. Hardcoded Application Secrets
&lt;/h4&gt;

&lt;p&gt;These are &lt;em&gt;non-user&lt;/em&gt; credentials that give wide access to your system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Firebase Admin keys&lt;/li&gt;
&lt;li&gt;Stripe secret keys&lt;/li&gt;
&lt;li&gt;Private API keys&lt;/li&gt;
&lt;li&gt;Database credentials&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many developers think &lt;code&gt;.env&lt;/code&gt; files or libraries like &lt;code&gt;react-native-dotenv&lt;/code&gt; keep secrets safe. They don’t. These variables are bundled into the final JS code — anyone with reverse-engineering tools can extract them in plain text.&lt;/p&gt;

&lt;h4&gt;
  
  
  B. Insecure Storage of User Credentials
&lt;/h4&gt;

&lt;p&gt;On the other hand, storing sensitive user data (access tokens, refresh tokens, biometric keys, etc) in insecure storage like &lt;code&gt;AsyncStorage&lt;/code&gt; makes it easily retrievable — especially on rooted or jailbroken devices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mitigation I: Protecting Application Secrets (Backend-for-Frontend Pattern)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Golden rule:&lt;/strong&gt; Never embed app-level secrets in your mobile code.&lt;/p&gt;

&lt;p&gt;The best solution is to isolate secrets using a &lt;strong&gt;Backend-for-Frontend (BFF)&lt;/strong&gt; proxy or &lt;strong&gt;serverless orchestration layer&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Principle&lt;/th&gt;
&lt;th&gt;Recommended Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Architectural Isolation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Build a secure backend endpoint that your mobile app talks to. The backend makes the actual third-party API calls using stored credentials.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Serverless Ready&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Use serverless functions (AWS Lambda, Google Cloud Functions, or Cloudflare Workers) for lightweight, scalable orchestration.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Secrets Management&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Store sensitive keys in &lt;code&gt;AWS Secrets Manager&lt;/code&gt;, &lt;code&gt;Google Secret Manager&lt;/code&gt;, or encrypted environment variables — never in the app.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Client Update&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Change your React Native code to call your secure proxy instead of external APIs directly.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This ensures your app remains a “dumb client,” relying on your backend for anything that needs secret keys.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mitigation II: Protecting User Credentials (Expo SecureStore)
&lt;/h2&gt;

&lt;p&gt;When user credentials &lt;em&gt;must&lt;/em&gt; live on the device (like tokens for login sessions), they should be stored using &lt;strong&gt;hardware-backed secure storage&lt;/strong&gt;, not in plain JS-accessible stores like &lt;code&gt;AsyncStorage&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Recommended Tool: &lt;code&gt;expo-secure-store&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Expo SecureStore is a unified interface over native OS storage systems — &lt;strong&gt;Keychain Services&lt;/strong&gt; (iOS) and &lt;strong&gt;Android Keystore&lt;/strong&gt;. These systems are designed by Apple and Google to safely store small bits of sensitive data like passwords, tokens, and encryption keys.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Underlying System&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;iOS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Keychain Services&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Data is stored in the device’s Secure Enclave — a hardware chip isolated from the OS. It requires user authentication (Face ID, Touch ID, or passcode) before access.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Android&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Android Keystore System&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Credentials are stored in an isolated keystore. Private keys never leave this secure hardware zone; even the app can’t read them directly. Data is encrypted with AES before being persisted.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  📱 Example Implementation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;SecureStore&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;expo-secure-store&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Save user token securely&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;saveUserToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;SecureStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItemAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;userToken&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Retrieve stored token&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getUserToken&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;SecureStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItemAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;userToken&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures your sensitive data lives in encrypted, OS-managed storage — not in plain JS memory or AsyncStorage. &lt;a href="https://docs.expo.dev/versions/latest/sdk/securestore/" rel="noopener noreferrer"&gt;Learn more for detailed implementation&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How Expo SecureStore Works with Keychain &amp;amp; Keystore
&lt;/h2&gt;

&lt;p&gt;Behind the scenes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On &lt;strong&gt;iOS&lt;/strong&gt;, &lt;code&gt;expo-secure-store&lt;/code&gt; communicates with the &lt;strong&gt;Keychain API&lt;/strong&gt;, which stores your key-value pair inside the &lt;strong&gt;Secure Enclave&lt;/strong&gt; chip. The OS encrypts it with a device-specific key, ensuring only your app (or authenticated user) can access it.&lt;/li&gt;
&lt;li&gt;On &lt;strong&gt;Android&lt;/strong&gt;, it interacts with the &lt;strong&gt;Keystore System&lt;/strong&gt;, where a master key is generated inside the &lt;strong&gt;Trusted Execution Environment (TEE)&lt;/strong&gt;. This master key encrypts your stored values. Even if the device is compromised, attackers cannot export these keys.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This native integration means data is not only encrypted but &lt;em&gt;hardware-isolated&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Improper Credential Usage (M1) isn’t just about bad code — it’s about architectural decisions. Every time a secret key or token sits in your mobile code, you’re one decompilation away from a breach.&lt;/p&gt;

&lt;h3&gt;
  
  
  TL;DR for React Native/Expo developers:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;❌ Never hardcode secrets or rely on &lt;code&gt;.env&lt;/code&gt; in the app.&lt;/li&gt;
&lt;li&gt;✅ Route API calls through a secure backend proxy.&lt;/li&gt;
&lt;li&gt;❌ Don’t use &lt;code&gt;AsyncStorage&lt;/code&gt; for tokens.&lt;/li&gt;
&lt;li&gt;✅ Use &lt;code&gt;expo-secure-store&lt;/code&gt; or &lt;code&gt;react-native-keychain&lt;/code&gt; to leverage native OS secure storage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Securing credentials isn’t just a best practice — it’s what separates a secure app from a data breach headline.&lt;/p&gt;

</description>
      <category>mobile</category>
      <category>reactnative</category>
      <category>security</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Zero-Downtime Deployment: Master Over-the-Air (OTA) Updates in Expo React Native</title>
      <dc:creator>Yusuff Jokanola O.</dc:creator>
      <pubDate>Fri, 24 Oct 2025 13:41:27 +0000</pubDate>
      <link>https://dev.to/jocanola/zero-downtime-deployment-master-over-the-air-ota-updates-in-expo-react-native-4p8a</link>
      <guid>https://dev.to/jocanola/zero-downtime-deployment-master-over-the-air-ota-updates-in-expo-react-native-4p8a</guid>
      <description>&lt;p&gt;Have you ever wondered why web developers can push code changes and users see them instantly—yet in mobile apps, even a tiny text fix can take days waiting for Apple or Google’s approval? Every React Native developer has faced that frustration, especially when production bugs sneak in right after release.&lt;/p&gt;

&lt;p&gt;That’s where Over-the-Air (OTA) updates come in. In simple terms, OTA updates let you deliver new JavaScript code, images, and other assets directly to users’ devices—without going through the app store review process. It’s like refreshing a web page, but for your mobile app. With Expo’s EAS Updates, this process becomes seamless, secure, and fully integrated into your deployment workflow.&lt;/p&gt;

&lt;p&gt;In this guide, you’ll learn how to set up and use EAS Updates for your Expo React Native project, following a clear, step-by-step approach. By the end, you’ll be able to ship updates instantly, fix issues in minutes, and make deployment virtually painless.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before diving in, make sure you have the following essentials ready:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;An Existing Expo Project:&lt;/strong&gt; Your project must be configured to use &lt;strong&gt;EAS (Expo Application Services)&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;EAS CLI Installed:&lt;/strong&gt; You need the EAS command-line tool.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; eas-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;An Initial Native Build:&lt;/strong&gt; A crucial point—OTA updates can only be pushed to an app that was &lt;strong&gt;originally built&lt;/strong&gt; using &lt;code&gt;eas build&lt;/code&gt;. You must have a native binary (&lt;code&gt;.ipa&lt;/code&gt; or &lt;code&gt;.apk&lt;/code&gt;) installed on your test devices or available to your users.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Expo Account:&lt;/strong&gt; Logged in via the CLI (&lt;code&gt;eas login&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 1: Configure Your Project for Updates
&lt;/h2&gt;

&lt;p&gt;EAS takes care of much of the heavy lifting, but we need to ensure the configuration is explicit, especially regarding &lt;strong&gt;channels&lt;/strong&gt;. Channels are how you target updates to different environments (e.g., &lt;code&gt;preview&lt;/code&gt;, &lt;code&gt;development&lt;/code&gt;, &lt;code&gt;production&lt;/code&gt;). &lt;br&gt;
To initialize EAS Update configuration run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;eas update:configure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will update your &lt;code&gt;app.config.js&lt;/code&gt; (or &lt;code&gt;app.json&lt;/code&gt;) file with the runtimeVersion and updates.url properties.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.1 Configure the update channel
&lt;/h3&gt;

&lt;p&gt;The channel property on a build allows you to point updates at specific types of builds. For example, it allows you to publish updates to a preview build without impacting your production deployment.&lt;/p&gt;

&lt;p&gt;If you are using EAS Build, eas update:configure will set the update channel property on the preview and production profiles in eas.json. Set them manually if you use different profile names.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// eas.json&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;build&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;development&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;developmentClient&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;distribution&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;internal&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;environment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;development&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;channel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;development&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;preview&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;distribution&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;internal&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;environment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;preview&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;channel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;preview&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;environment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;channel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Integrate &lt;code&gt;expo-updates&lt;/code&gt; (Optional but Recommended)
&lt;/h2&gt;

&lt;p&gt;While Expo handles automatic updates in the background, you might want to add a user interface (UI) to check for and apply updates immediately. This is particularly useful in development or for critical fixes.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.1 Install the Module
&lt;/h3&gt;

&lt;p&gt;If it's not already installed, add the official updates module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx expo &lt;span class="nb"&gt;install &lt;/span&gt;expo-updates
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2.2 Manually Check for Updates (Optional)
&lt;/h3&gt;

&lt;p&gt;You can create a custom hook or function to check for updates when the app starts. This example shows how to use the &lt;code&gt;useUpdates()&lt;/code&gt; hook in a functional component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StatusBar&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;expo-status-bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Updates&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;expo-updates&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UpdatesDemo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;currentlyRunning&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;isUpdateAvailable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;isUpdatePending&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Updates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useUpdates&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isUpdatePending&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Update has successfully downloaded; apply it now&lt;/span&gt;
      &lt;span class="nx"&gt;Updates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reloadAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isUpdatePending&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="c1"&gt;// If true, we show the button to download and run the update&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;showDownloadButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isUpdateAvailable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Show whether or not we are running embedded code or an update&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;runTypeMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;currentlyRunning&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isEmbeddedLaunch&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;This app is running from built-in code&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;This app is running an update&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headerText&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Updates&lt;/span&gt; &lt;span class="nx"&gt;Demo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Text&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;runTypeMessage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Text&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="nx"&gt;onPress&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Updates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;checkForUpdateAsync&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Check manually for updates&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;showDownloadButton&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="nx"&gt;onPress&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Updates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchUpdateAsync&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Download and run update&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;StatusBar&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/View&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 3: Build and Distribute the Native Container
&lt;/h2&gt;

&lt;p&gt;Remember, OTA updates only change JavaScript and assets. If you change native code (e.g., add a new library or modify &lt;code&gt;Podfile&lt;/code&gt;), you &lt;strong&gt;must&lt;/strong&gt; create a new native build (&lt;code&gt;.apk&lt;/code&gt; or &lt;code&gt;.ipa&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Use the &lt;code&gt;eas build&lt;/code&gt; command to create the initial app binary that contains the necessary update configuration.&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;# Build a preview binary for iOS&lt;/span&gt;
eas build &lt;span class="nt"&gt;--profile&lt;/span&gt; preview &lt;span class="nt"&gt;--platform&lt;/span&gt; ios
&lt;span class="c"&gt;# Build a preview binary for Android&lt;/span&gt;
eas build &lt;span class="nt"&gt;--profile&lt;/span&gt; preview &lt;span class="nt"&gt;--platform&lt;/span&gt; android
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once this build is installed on the device, you are ready for the magic of instant updates.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4: Publishing Your First OTA Update
&lt;/h2&gt;

&lt;p&gt;Now for the moment of truth. You've fixed a typo, adjusted a style, or added a new feature that doesn't involve native module changes.&lt;/p&gt;

&lt;p&gt;Instead of running a full, time-consuming native build, you run a single command: &lt;code&gt;eas update&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.1 The Command
&lt;/h3&gt;

&lt;p&gt;Use the &lt;code&gt;--channel&lt;/code&gt; flag to target the specific channel defined in your &lt;code&gt;eas.json&lt;/code&gt; (e.g., &lt;code&gt;preview&lt;/code&gt;). remember will build for preview that is the reason where pushing to OTA to preview if you're pushing for production you will use &lt;code&gt;production&lt;/code&gt;&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;# Deploy a new update to all users with the preview binary installed on android&lt;/span&gt;
eas update &lt;span class="nt"&gt;--channel&lt;/span&gt; preview &lt;span class="nt"&gt;--platform&lt;/span&gt; android &lt;span class="nt"&gt;--message&lt;/span&gt; &lt;span class="s2"&gt;"Fixing that embarrassing typo on the homepage. 😅"&lt;/span&gt;

&lt;span class="c"&gt;# Deploy a new update to all users with the production binary installed on ios&lt;/span&gt;
eas update &lt;span class="nt"&gt;--channel&lt;/span&gt; production &lt;span class="nt"&gt;--platform&lt;/span&gt; ios &lt;span class="nt"&gt;--message&lt;/span&gt; &lt;span class="s2"&gt;"Fixing that embarrassing typo on the homepage. 😅"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.2 What Happens Next?
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Bundling:&lt;/strong&gt; EAS bundles your latest JavaScript and static assets.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Upload:&lt;/strong&gt; The bundle is uploaded to the Expo CDN (Content Delivery Network).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Assignment:&lt;/strong&gt; The update is assigned to the specified &lt;strong&gt;branch&lt;/strong&gt; (&lt;code&gt;preview&lt;/code&gt; or &lt;code&gt;production&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Deployment:&lt;/strong&gt; When a user opens their existing app, it checks the EAS Update server, downloads the new JavaScript bundle in the background, and applies it upon the next app restart or manually via your &lt;code&gt;expo-updates&lt;/code&gt; implementation.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Step 5: Testing the Deployed Update
&lt;/h2&gt;

&lt;p&gt;To confirm your update works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Make a Visible Change:&lt;/strong&gt; Change a simple &lt;code&gt;Text&lt;/code&gt; component in your app (e.g., change "Welcome" to "Welcome Back!").&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Publish the Update:&lt;/strong&gt; Run the &lt;code&gt;eas update&lt;/code&gt; command from Step 4.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Test:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Open your app on the device that has the native build from Step 3.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Crucial:&lt;/strong&gt; Close the app completely (kill it from the task switcher) and re-open it.&lt;/li&gt;
&lt;li&gt;You should see your new change instantly, without downloading anything from the App Store or installing !&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Adopting &lt;strong&gt;EAS Updates&lt;/strong&gt; transforms your deployment workflow. No longer are you beholden to slow review processes for minor fixes. You gain speed, agility, and a much better user experience by instantly delivering improvements.&lt;/p&gt;

&lt;p&gt;While the freedom is great, remember: &lt;strong&gt;any change to native code still requires a full &lt;code&gt;eas build&lt;/code&gt; and an App Store submission.&lt;/strong&gt; For everything else—JS, assets, business logic—&lt;strong&gt;&lt;code&gt;eas update&lt;/code&gt;&lt;/strong&gt; is your new best friend! Happy instant deploying! 🎉&lt;/p&gt;

</description>
      <category>android</category>
      <category>react</category>
      <category>reactnative</category>
      <category>security</category>
    </item>
    <item>
      <title>Improving Binary Security in Mobile Application: A Deep Dive into Obfuscation</title>
      <dc:creator>Yusuff Jokanola O.</dc:creator>
      <pubDate>Fri, 17 Oct 2025 21:13:23 +0000</pubDate>
      <link>https://dev.to/jocanola/improving-binary-security-in-mobile-application-a-deep-dive-into-obfuscation-58n2</link>
      <guid>https://dev.to/jocanola/improving-binary-security-in-mobile-application-a-deep-dive-into-obfuscation-58n2</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Mobile applications increasingly serve as the gateway to critical business operations, making them high-value targets for reverse engineering and code tampering. This threat is formally recognized in the &lt;strong&gt;&lt;a href="https://owasp.org/www-project-mobile-top-10/" rel="noopener noreferrer"&gt;OWASP Mobile Top 10 (2024) risks&lt;/a&gt;&lt;/strong&gt;. This category highlights &lt;strong&gt;&lt;a href="https://owasp.org/www-project-mobile-top-10/2023-risks/m7-insufficient-binary-protection.html" rel="noopener noreferrer"&gt;M7: Insufficient Binary Protection&lt;/a&gt;&lt;/strong&gt; enable attackers to extract secrets, reverse engineer proprietary logic, and repackage apps for malicious use.&lt;/p&gt;

&lt;p&gt;In the context of React Native, this threat is especially relevant because the application’s core logic is bundled in JavaScript and then compiled into Hermes bytecode for performance optimization. While the use of Hermes offers a foundational layer of obfuscation through bytecode compilation, it is not a foolproof defense. Its output can still be decompiled or analyzed by determined adversaries (though advanced analysis techniques are beyond the scope of this article). Crucially, React Native apps also include several native files (Java/Kotlin on Android) and metadata that can reveal insights about the app’s internal structure, such as all the third-party packages in use. This information, when combined with the decompiled Hermes bytecode, can help attackers better understand the app’s architecture, identify potential weaknesses, and target specific vulnerabilities.&lt;/p&gt;

&lt;p&gt;In this article, we’ll explore how Android reverse engineering affects React Native applications, why it remains a top-tier security concern, and outline key mitigation strategies—with a focus on implementing code obfuscation as an essential defense layer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites for Analysis
&lt;/h3&gt;

&lt;p&gt;To practically understand and test the security posture of your application against reverse engineering, you must have the production-ready Android Package Kit (APK) file.&lt;/p&gt;

&lt;h3&gt;
  
  
  For React Native (Bare Workflow)
&lt;/h3&gt;

&lt;p&gt;You will typically generate the APK directly using Android Studio or the command line.&lt;/p&gt;

&lt;h3&gt;
  
  
  For Expo (Managed Workflow)
&lt;/h3&gt;

&lt;p&gt;The .apk file is produced after a release build (eas build --platform android). If you receive an Android App Bundle (.aab) file from your build service or Google Play Console, you must use the Google-provided bundletool to extract a Universal or device-specific .apk for analysis.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;bundletool can be used to Converts .aab to .apk files for testing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  How Attackers/CyberSecurity Analyst Decompile Your App
&lt;/h3&gt;

&lt;p&gt;Disclaimer: This section is for educational purposes only, intended to help developers understand and mitigate attack vectors. The techniques described are mimic standard practices used by security analysts and penetration testers to assess application security.&lt;/p&gt;

&lt;p&gt;The standard process for reverse engineering an Android application involves several key steps, primarily centered around a tool called Apktool.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Decompilation Process
&lt;/h3&gt;

&lt;p&gt;Apktool is the go-to utility for unpacking and repacking Android APKs. It extracts the resources and decompiles the compiled code into a more readable format called Smali.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;APK Acquisition&lt;/strong&gt;: The attacker obtains the APK from an app store or directly from a compromised device.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decompilation Command&lt;/strong&gt;: After installing apktool run below command in your preferred terminal&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apktool.org/docs/install/" rel="noopener noreferrer"&gt;Apktool Installation&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;apktool d app-release.apk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a new directory containing the decompiled files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code Inspection&lt;/strong&gt;: The attacker then navigates and analyzes the resulting files, which include the app's native code and resource structure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Anatomy of a Decompiled App (Before Obfuscation)
&lt;/h2&gt;

&lt;p&gt;In an unprotected (or minimally protected) React Native or Expo application, the directory structure and file contents offer clear signposts to an attacker.&lt;/p&gt;

&lt;p&gt;Example Decompiled app directory&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%2F97voiv3bv2zimat5a9ji.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%2F97voiv3bv2zimat5a9ji.png" alt="Decompiled App with Minimal Obfuscation" width="555" height="837"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;smali/ directory Contains .smali files, which are a human-readable assembly-like language derived from the app's native Java/Kotlin bytecode.   Proprietary Logic: Function names, variable names, class structures, and API endpoint references are often intact and descriptive as shown in the image above.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Improve Obfuscation in Expo Apps
&lt;/h2&gt;

&lt;p&gt;For React Native apps, particularly those built with the Expo Managed Workflow, you can leverage the powerful built-in tooling for advanced binary protection. The key is to enable and fine-tune ProGuard (or R8, the modern equivalent) through the expo-build-properties plugin in your app.json or app.config.js.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration Steps
&lt;/h2&gt;

&lt;p&gt;By default, Expo enables basic resource shrinking. For stronger protection, you must explicitly enable code obfuscation and resource compression for release builds, you can customize your app.config.js or app.json, by add expo-build-properties in your plugins&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[
  "expo-build-properties",
  {
    "android": {
      // 1. **Crucial:** Enables R8/ProGuard for code obfuscation and shrinking.
      "enableProguardInReleaseBuilds": true,

      // 2. Optimizes the size of the final APK by compressing bundled assets.
      "enableBundleCompression": true, 

      // 3. Removes unused resources (like images or unused strings) to shrink size.
      "enableShrinkResourcesInReleaseBuilds": true,

      // 4. Advanced: Allows custom ProGuard rules for fine-tuning obfuscation.
      "extraProguardRules": "-dontwarn com.squareup.okhttp3.**\n-keep class com.myapp.secure.** { *; }"
    }
  }
],
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Implementing extraProguardRules&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;The extraProguardRules&lt;/strong&gt; property is powerful for fine-tuning the &lt;br&gt;
protection: You can write specific rules to further obfuscate proprietary code or to prevent obfuscation on specific native modules that rely on introspection (reflection) to function correctly.&lt;/p&gt;

&lt;p&gt;Best Practice: Always use a -keep rule for classes that are accessed dynamically (e.g., via reflection, JNI, or third-party SDKs) to prevent R8/ProGuard from renaming or stripping them, which would cause runtime crashes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Anatomy of a Decompiled App (After Obfuscation)
&lt;/h2&gt;

&lt;p&gt;After implementing robust obfuscation, the same directories and files become significantly less useful to the attacker, drastically increasing the time and effort required for reverse engineering.&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%2Fheyzq6i3fhsfqc1w3058.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%2Fheyzq6i3fhsfqc1w3058.png" alt="Decompiled App with Custom Obfuscation" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After implementing robust obfuscation, the same directories and files become significantly less useful to the attacker, drastically increasing the time and effort required for reverse engineering.&lt;/p&gt;

&lt;p&gt;Directory/File  Post-Obfuscation State  Impact on Attacker&lt;br&gt;
smali/ directory File and function names are replaced with meaningless, single-letter or short, randomized strings (e.g., a1.smali, b.smali). &lt;br&gt;
Deterrence: The attacker loses context. A file named a.smali provides no clues about its function, forcing manual, tedious analysis of the bytecode's flow and content.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NB&lt;/strong&gt;&lt;br&gt;
⚠️ &lt;strong&gt;Warning and Testing&lt;/strong&gt;: You must thoroughly test your application after enabling or tightening obfuscation. Since some native packages (especially those using reflection) may be affected by renamed classes, rigorous regression testing across all functionalities is non-negotiable before deploying the secure build.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;While basic, default obfuscation provides a minimal barrier, it may not deter a determined attacker targeting a high-value application. As the threat landscape evolves, and with attackers increasingly leveraging &lt;strong&gt;Large Language Models (LLMs)&lt;/strong&gt; to accelerate the decoding of default binary encoding provided by frameworks, developers must respond with sufficient binary protection.&lt;/p&gt;

&lt;p&gt;Obfuscation is a layer of defense, not a complete solution. When combined with other critical controls—such as &lt;strong&gt;Root/Jailbreak Detection, Runtime Application Self-Protection (RASP), Certificate Pinning, and proper Secret Management&lt;/strong&gt;—a comprehensive strategy will significantly increase the cost and effort required for a successful reverse engineering attack, stretching the attacker's resources to their limit. For serious, commercially-sensitive projects, insufficient binary protection is a risk you simply cannot afford.&lt;/p&gt;

</description>
      <category>android</category>
      <category>react</category>
      <category>reactnative</category>
      <category>security</category>
    </item>
    <item>
      <title>How to Prioritize Product Development: A Practical Guide for Startups and Beyond</title>
      <dc:creator>Yusuff Jokanola O.</dc:creator>
      <pubDate>Mon, 22 Sep 2025 22:24:20 +0000</pubDate>
      <link>https://dev.to/jocanola/how-to-prioritize-product-development-a-practical-guide-for-startups-and-beyond-no7</link>
      <guid>https://dev.to/jocanola/how-to-prioritize-product-development-a-practical-guide-for-startups-and-beyond-no7</guid>
      <description>&lt;p&gt;When it comes to product development, many teams—whether product managers, engineers, or even stakeholders—tend to get caught up in the excitement of new features. A feature may sound fantastic on paper, or research may suggest it could be a game-changer. Teams often rally behind these ideas with great enthusiasm. But here’s the critical question:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Is that exciting feature really worth prioritizing over everything else?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is where many organizations stumble. Bugs pile up, timelines stretch thin, and the “next big thing” in the backlog steals attention from what truly matters. In large corporations with deep pockets, chasing the wrong features might not be fatal. But in the startup world, burning cash on low-impact features is one of the fastest ways to fail.&lt;/p&gt;

&lt;p&gt;So, how do effective leaders consistently make the right calls when it comes to prioritization?&lt;/p&gt;




&lt;h2&gt;
  
  
  The Myth: Customers Always Know What They Want
&lt;/h2&gt;

&lt;p&gt;A common argument is to simply “listen to the customer.” And yes, customers are central—you’re building for them. But here’s the nuance: customers often don’t fully know what they want.&lt;/p&gt;

&lt;p&gt;Imagine this scenario:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One customer requests five features.&lt;/li&gt;
&lt;li&gt;With 100 customers, you might find only a 40% overlap.&lt;/li&gt;
&lt;li&gt;That leaves you with &lt;strong&gt;300 unique feature requests&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not only is it impossible to build all of them, but many of these features will be used sparingly—maybe once every three months. Should you really burn resources on that?&lt;/p&gt;

&lt;p&gt;The answer lies in a more systematic approach.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Value-Cost Sieve: A Smarter Way to Prioritize
&lt;/h2&gt;

&lt;p&gt;One powerful framework is the &lt;strong&gt;Value-Cost Sieve&lt;/strong&gt;. Instead of chasing every shiny new feature, you categorize work into four buckets:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;High-Value, Low-Cost&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;These are quick wins. They provide significant impact with minimal effort.&lt;/li&gt;
&lt;li&gt;Example: Improving onboarding flow to reduce drop-offs.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;High-Value, High-Cost&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Strategic investments. They’re resource-heavy but deliver long-term gains.&lt;/li&gt;
&lt;li&gt;Example: Building a recommendation engine that significantly boosts engagement.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Low-Value, Low-Cost&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Consider only if resources allow. These may enhance UX or delight niche users but won’t move the needle.&lt;/li&gt;
&lt;li&gt;Example: Adding cosmetic theme options.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Low-Value, High-Cost&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Avoid at all costs. These are distractions disguised as opportunities.&lt;/li&gt;
&lt;li&gt;Example: Building complex integrations that serve only a handful of customers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By running every idea through this sieve, leaders can quickly filter noise and focus on features that align with both &lt;strong&gt;customer needs&lt;/strong&gt; and &lt;strong&gt;business goals&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Matters More in Startups
&lt;/h2&gt;

&lt;p&gt;For established corporations, experimenting with features—even ones with low impact—rarely threatens survival. They have the budgets and buffers.&lt;/p&gt;

&lt;p&gt;Startups, however, operate under tight constraints. Every sprint, every dollar, and every engineer’s hour needs to be maximized. Misplaced priorities can mean the difference between survival and shutdown.&lt;/p&gt;

&lt;p&gt;Effective leaders know this instinctively. They ruthlessly eliminate distractions and guide their teams toward what creates &lt;strong&gt;real, compounding value&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Takeaway
&lt;/h2&gt;

&lt;p&gt;Prioritization is not about rejecting ideas—it’s about &lt;strong&gt;systematically filtering them&lt;/strong&gt;. By applying frameworks like the &lt;strong&gt;Value-Cost Sieve&lt;/strong&gt;, you’ll:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deliver what truly matters to customers.&lt;/li&gt;
&lt;li&gt;Save time and money.&lt;/li&gt;
&lt;li&gt;Keep your product roadmap focused and impactful.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The best leaders aren’t the ones who say “yes” to every exciting idea. They’re the ones who know &lt;strong&gt;what to say “no” to&lt;/strong&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>React Native CLI vs Expo CLI: Clearing Up Misconceptions</title>
      <dc:creator>Yusuff Jokanola O.</dc:creator>
      <pubDate>Thu, 18 Sep 2025 11:04:16 +0000</pubDate>
      <link>https://dev.to/jocanola/react-native-cli-vs-expo-cli-clearing-up-misconceptions-2fl4</link>
      <guid>https://dev.to/jocanola/react-native-cli-vs-expo-cli-clearing-up-misconceptions-2fl4</guid>
      <description>&lt;p&gt;When building mobile apps with React Native, one of the earliest choices developers face is &lt;strong&gt;whether to use Expo CLI or the bare React Native CLI workflow&lt;/strong&gt;. For years, Expo carried the reputation of being a tool only good for prototypes, MVPs, or simple apps—while React Native CLI was considered the “serious” option for production.&lt;/p&gt;

&lt;p&gt;That landscape has changed. Today, Expo has evolved into the recommended default for production apps, and many of the previous limitations no longer apply. But we still see people writing about this limitation till today, and even if you ask LLM like ChatGPT with &lt;strong&gt;React Native CLI vs Expo CLI&lt;/strong&gt; it will still bring the same old limitation, which is why most people still include it in their article because the most likely generated part of their articles without their own personal experience input.&lt;/p&gt;

&lt;p&gt;Let’s look at the current reality of the ecosystem.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Expo CLI: Then vs Now
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Old perception:&lt;/strong&gt; Expo was limited—you could only use what the Expo SDK provided, and if you needed custom native code, your only path forward was “ejecting” into a bare React Native workflow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Now:&lt;/strong&gt; The &lt;strong&gt;eject option has been deprecated&lt;/strong&gt; and replaced with &lt;strong&gt;&lt;code&gt;expo prebuild&lt;/code&gt;&lt;/strong&gt;, which generates the same native projects (Xcode/Android Studio) you’d get with React Native CLI. From there, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add &lt;strong&gt;custom native modules&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Modify iOS and Android projects directly.&lt;/li&gt;
&lt;li&gt;Still use Expo’s managed features like OTA updates, EAS builds, and the Expo SDK.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means Expo offers up to &lt;strong&gt;95% of the flexibility of bare React Native&lt;/strong&gt;, with additional tooling that makes development and maintenance easier.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Bare React Native CLI: Where It Stands
&lt;/h2&gt;

&lt;p&gt;Using React Native CLI directly gives you full control from day one:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You configure Gradle and CocoaPods manually.&lt;/li&gt;
&lt;li&gt;You install and link all libraries yourself.&lt;/li&gt;
&lt;li&gt;You manage upgrades manually (which can be painful for large projects).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While this offers maximum freedom, it also introduces overhead. You become responsible for &lt;strong&gt;CI/CD pipelines, OTA update solutions, and navigating complex upgrades&lt;/strong&gt;. For apps with extremely specialized native requirements, this control is valuable—but for most teams, the tradeoff is high.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Advantages of Expo Beyond Development Speed
&lt;/h2&gt;

&lt;p&gt;Expo isn’t just about fast prototyping anymore. It also brings &lt;strong&gt;post-development benefits&lt;/strong&gt; that make it a strong choice for production apps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Smoother upgrades:&lt;/strong&gt; Expo maintains compatibility across the ecosystem, so upgrading React Native versions is often significantly easier than in bare projects.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;EAS (Expo Application Services):&lt;/strong&gt; Provides managed CI/CD pipelines, cloud builds, and app store submission without manual configuration.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;OTA (Over-the-Air) updates:&lt;/strong&gt; Ship instant fixes and feature updates without going through the app store review process. (While CodePush offered similar benefits, it has been deprecated, leaving Expo’s OTA as the modern solution.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Rich SDK:&lt;/strong&gt; Camera, notifications, sensors, biometrics, and more—all maintained and tested to work with React Native’s latest versions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. Official Recommendation
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;React Native documentation&lt;/strong&gt; itself now recommends starting with &lt;strong&gt;Expo&lt;/strong&gt; for new projects:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Yes. You can use React Native without a Framework. However, if you’re building a new app with React Native, we recommend using a Framework.&lt;/p&gt;

&lt;p&gt;In short, you’ll be able to spend time writing your app instead of writing an entire Framework yourself in addition to your app.”&lt;br&gt;
— &lt;a href="https://reactnative.dev/docs/environment-setup" rel="noopener noreferrer"&gt;React Native Docs: Environment Setup&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The only time you should reach for bare React Native CLI from the start is if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You already know Expo’s tooling won’t fit your project needs.&lt;/li&gt;
&lt;li&gt;You have a strong team with the expertise and resources to maintain a fully custom setup.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For most developers and teams, Expo should be the default choice.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Expo is no longer just for prototypes&lt;/strong&gt;—it’s fully production-ready.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ejecting is gone&lt;/strong&gt;; replaced by &lt;code&gt;expo prebuild&lt;/code&gt;, which provides nearly the same flexibility as bare React Native.&lt;/li&gt;
&lt;li&gt;Expo offers significant &lt;strong&gt;long-term benefits&lt;/strong&gt; like easier upgrades, EAS, and OTA updates.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;React Native team recommends Expo&lt;/strong&gt; as the default starting point for production apps.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unless Expo’s solutions don’t meet your needs—and you’re ready to take on the complexity of maintaining everything yourself—you should &lt;strong&gt;start with Expo&lt;/strong&gt;.&lt;/p&gt;




&lt;p&gt;✅ &lt;strong&gt;Final Thoughts&lt;/strong&gt; &lt;br&gt;
The old “Expo vs React Native CLI” debate is outdated. Today, Expo is the recommended production pathway, and the limitations that once justified avoiding it are mostly gone.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>reactnative</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Automating Expo Android Submission to Play Store Console with EAS Using GitHub Actions: A Step-by-Step Guide.</title>
      <dc:creator>Yusuff Jokanola O.</dc:creator>
      <pubDate>Sun, 16 Feb 2025 11:22:34 +0000</pubDate>
      <link>https://dev.to/jocanola/automating-expo-android-submission-with-eas-using-github-actions-a-step-by-step-guide-36b3</link>
      <guid>https://dev.to/jocanola/automating-expo-android-submission-with-eas-using-github-actions-a-step-by-step-guide-36b3</guid>
      <description>&lt;p&gt;Building and deploying an Android app can often be a repetitive and time-consuming task. Automating the submission process using GitHub Actions streamlines development workflows, reduces manual errors, and ensures consistent app releases. If you’re using Expo to develop your Android app, you’re in luck – Expo provides tools that integrate seamlessly with CI/CD pipelines.&lt;/p&gt;

&lt;p&gt;In this guide, we’ll walk through setting up a GitHub Actions workflow to automate the submission of your Expo Android app.&lt;/p&gt;

&lt;p&gt;To make sense of the post you may need to read my previous post &lt;a href="https://dev.to/jocanola/automate-your-expo-builds-with-eas-using-github-actions-a-step-by-step-guide-bik"&gt;Automate Your Expo Builds with EAS Using GitHub Actions: A Step-by-Step Guide (Android)&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;React Native project &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Must have created your first build &lt;a href="https://docs.expo.dev/build/setup/" rel="noopener noreferrer"&gt;How to create your first build&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Must have submitted your android app first time &lt;a href="https://docs.expo.dev/deploy/submit-to-app-stores/" rel="noopener noreferrer"&gt;How to submit expo app to stores&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Define Your GitHub Actions Workflow to build the app&lt;/strong&gt;&lt;br&gt;
Create a GitHub Actions workflow file in your repository at .github/workflows/android-submission.yml and paste the code below. If you’ve read the previous post, your workflow file should look similar to this. This code builds the .aab file for submission.&lt;br&gt;
&lt;/p&gt;

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

on:
  push:
    branches:
      - staging
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Setup repo
        uses: actions/checkout@v4

      - name: Setup node
        uses: actions/setup-node@v3
        with:
          node-version: 20.x
          cache: "npm"

      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: "17"
          distribution: "temurin"

      - name: Setup Android SDK
        uses: android-actions/setup-android@v3

      - name: Setup Expo
        uses: expo/expo-github-action@v8
        with:
          expo-version: latest
          eas-version: latest
          token: ${{ secrets.EXPO_TOKEN }}

      - name: Install dependencies
        run: yarn install --frozen-lockfile

      - name: Build Android app
        run: eas build --platform android --profile production --local --output ${{ github.workspace }}/app-release.aab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;NB&lt;/strong&gt;:&lt;br&gt;
If you notice, the key change from the previous article is the replacement of &lt;code&gt;preview&lt;/code&gt; with &lt;code&gt;production&lt;/code&gt; in the --profile setting. This means we’re now building for production instead of testing. For more details on configuring profiles &lt;a href="https://docs.expo.dev/build/eas-json/" rel="noopener noreferrer"&gt;Configure EAS Build with eas.json&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Submitting the app&lt;/strong&gt;&lt;br&gt;
The command below should look familiar if you’ve submitted an Android app with Expo via the terminal. It takes the app you previously built and submits it directly to the store.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; - name: Submit to Google Play
        run: |
          eas submit -p android --profile production --path ${{ github.workspace }}/app-release.aab --non-interactive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Test the Workflow&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Push your changes to the &lt;strong&gt;staging&lt;/strong&gt; (or specific branch you put in workflow) branch to trigger the workflow. Monitor the Actions tab in your GitHub repository to ensure the steps execute successfully. If the submission succeeds, your app will be uploaded to the Google Play Console and you should see it in your internal test.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tips and Best Practices&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Versioning: Ensure your version and versionCode in app.json or app.config.js are updated automatically using scripts or manual steps &lt;a href="https://docs.expo.dev/build-reference/app-versions/" rel="noopener noreferrer"&gt;learn more&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Testing: Run unit, integration tests or e2e test before submitting  ensure app stability &lt;a href="https://reactnative.dev/docs/testing-overview" rel="noopener noreferrer"&gt;learn more&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading till the end.&lt;/p&gt;

&lt;p&gt;Next time, I'll cover automating build and submission of iOS app to the Apple store respectively. Stay tuned!!!.&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>mobile</category>
      <category>android</category>
      <category>githubactions</category>
    </item>
    <item>
      <title>Automate Your Expo Builds with EAS Using GitHub Actions: A Step-by-Step Guide (Android)</title>
      <dc:creator>Yusuff Jokanola O.</dc:creator>
      <pubDate>Sun, 07 Jul 2024 20:55:40 +0000</pubDate>
      <link>https://dev.to/jocanola/automate-your-expo-builds-with-eas-using-github-actions-a-step-by-step-guide-bik</link>
      <guid>https://dev.to/jocanola/automate-your-expo-builds-with-eas-using-github-actions-a-step-by-step-guide-bik</guid>
      <description>&lt;p&gt;Developers get 30 free builds each month (up to 15 iOS builds) with EAS Build. While this seems much at first glance, it can be quickly exhausted in a serious hobby project, let alone a professional environment.&lt;/p&gt;

&lt;p&gt;Additionally, the queue for builds can be very long, sometimes taking up to 90 minutes or more before starting. &lt;/p&gt;

&lt;p&gt;This wait can be problematic if you need to fix high-severity or security issues urgently. Local builds (--local) are an alternative, but the process is repetitive and unavailable to Windows users.&lt;/p&gt;

&lt;p&gt;In this article, we will cover how to avoid these issues efficiently using GitHub Actions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;React Native project &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Must have created your first build &lt;a href="https://docs.expo.dev/build/setup/" rel="noopener noreferrer"&gt;Create your first build&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An Expo user account &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Setup your project&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ensure you have your Expo project set up and configured for EAS Build. If not, you can check expo docs &lt;a href="https://docs.expo.dev/build/setup/" rel="noopener noreferrer"&gt;On creating your first build&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Get your Expo access token&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can generate expo tokens that will allow github action to access your account on your behalf. &lt;a href="https://docs.expo.dev/accounts/programmatic-access/" rel="noopener noreferrer"&gt;learn more&lt;/a&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%2Fzkzsd9twal1034s9wydv.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%2Fzkzsd9twal1034s9wydv.png" alt="Getting Expo access token" width="800" height="501"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Save this token to GitHub Secrets&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In your GitHub repository, navigate to Settings &amp;gt; Secrets and variables &amp;gt; Actions and add the following secrets:&lt;/p&gt;

&lt;p&gt;EXPO_TOKEN:  your expo access token generated in step 2&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Create a New Workflow File&lt;/strong&gt;&lt;br&gt;
In your GitHub repository or locally, create a new directory .github/workflows  and add a file named build-apk.yml (you can name this file whatever you want and in my case I created the file inside &lt;strong&gt;staging&lt;/strong&gt; branch).&lt;/p&gt;

&lt;p&gt;Enter your workflow name and trigger&lt;br&gt;
&lt;/p&gt;

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

on:
  push:
    branches:
      - staging
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;NB&lt;/strong&gt;:&lt;br&gt;
You may not understand the above code but what you need to understand is the workflow runs when code is pushed to the branch name &lt;strong&gt;staging&lt;/strong&gt;, you can replace it with a different branch.&lt;br&gt;
&lt;a href="https://docs.github.com/en/actions/using-workflows" rel="noopener noreferrer"&gt;Learn more about workflows&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Jobs and Steps&lt;/strong&gt;&lt;br&gt;
 Below code specifies the type of virtual machine to run the job: which is ubuntu-latest. you can specify &lt;strong&gt;macos-latest&lt;/strong&gt; when building for iOS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jobs:
  build:
    runs-on: ubuntu-latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Steps Within the Job&lt;/strong&gt;&lt;br&gt;
This code is essential to get the code into the virtual machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;steps:
      - name: Setup repo
        uses: actions/checkout@v4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Setup node&lt;/strong&gt;&lt;br&gt;
Uses a pre-built action to set up a Node.js environment&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      - name: Setup node
        uses: actions/setup-node@v3
        with:
          node-version: 20.x
          cache: "npm"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Set up JDK 17&lt;/strong&gt;&lt;br&gt;
Uses a pre-built action to set up a Java environment&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: "17"
          distribution: "temurin"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Setup Android SDK&lt;/strong&gt;&lt;br&gt;
Uses a pre-built action to install and set Android SDK&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  - name: Setup Android SDK
        uses: android-actions/setup-android@v3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Setup Expo&lt;/strong&gt;&lt;br&gt;
Uses a pre-built action to set up Expo&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; - name: Setup Expo
        uses: expo/expo-github-action@v8
        with:
          expo-version: latest
          eas-version: latest
          token: ${{ secrets.EXPO_TOKEN }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NB: You must save EXPO_TOKEN to Github secret you can go back to step 2 &amp;amp; 3 if you have not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Install project depencies&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; - name: Install dependencies
        run: yarn install --frozen-lockfile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Build Android 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;  - name: Build Android app
        run: eas build --platform android --profile preview --local --output ${{ github.workspace }}/app-release.apk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Upload Build Artifact&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      - name: Upload Build Artifact
        uses: actions/upload-artifact@v2
        with:
          name: app-release
          path: ${{ github.workspace }}/app-release.apk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your build-apk.yml should have below content by now, make changes to your code and push to github.&lt;br&gt;
&lt;/p&gt;

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

on:
  push:
    branches:
      - new-features
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Setup repo
        uses: actions/checkout@v4

      - name: Setup node
        uses: actions/setup-node@v3
        with:
          node-version: 20.x
          cache: "npm"

      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: "17"
          distribution: "temurin"

      - name: Setup Android SDK
        uses: android-actions/setup-android@v3

      - name: Setup Expo
        uses: expo/expo-github-action@v8
        with:
          expo-version: latest
          eas-version: latest
          token: ${{ secrets.EXPO_TOKEN }}

      - name: Install dependencies
        run: yarn install --frozen-lockfile

      - name: Build Android app
        run: eas build --platform android --profile preview --local --output ${{ github.workspace }}/app-release.apk
      - name: Upload APK artifact
        uses: actions/upload-artifact@v2
        with:
          name: app-release
          path: ${{ github.workspace }}/app-release.apk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can download the Artifact (build file apk or aab) in the job detail's page.&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%2Fqdq2wbiipr6n5d6ufonp.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%2Fqdq2wbiipr6n5d6ufonp.png" alt="Where you can download the Artifact" width="800" height="477"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;NB: For medium or large-sized companies, it is advisable to use the Production or Enterprise subscription, as it includes many additional features that cater to their needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final Thoughts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Employing GitHub Actions for building my projects has saved me a lot of time. Previously, I could only create 2-3 builds per day. Now, I can generate unlimited builds, eliminating repetitive and boring tasks from my workflow. This allows me to focus on what truly matters: building my project.&lt;/p&gt;

&lt;p&gt;Thanks for reading till the end.&lt;/p&gt;

&lt;p&gt;Next time, I'll cover automating builds and submission of  android and iOS to the Play Store and Apple store respectively. Stay tuned!!!&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>expo</category>
      <category>frontend</category>
      <category>mobile</category>
    </item>
    <item>
      <title>How to convert existing nodejs/expressjs app from javascript to typescript, the painless way</title>
      <dc:creator>Yusuff Jokanola O.</dc:creator>
      <pubDate>Sun, 10 Mar 2024 19:28:20 +0000</pubDate>
      <link>https://dev.to/jocanola/how-to-convert-exist-nodejsexpressjs-app-from-javascript-to-typescript-the-painless-way-3g51</link>
      <guid>https://dev.to/jocanola/how-to-convert-exist-nodejsexpressjs-app-from-javascript-to-typescript-the-painless-way-3g51</guid>
      <description>&lt;p&gt;Converting a large &lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;Express.js&lt;/a&gt; application from JavaScript to TypeScript can be a challenging task. For many applications, this represents a significant portion of their &lt;a href="https://www.productplan.com/glossary/technical-debt/" rel="noopener noreferrer"&gt;technical debt&lt;/a&gt;, as the process may span many days, if not months, and new changes are typically not allowed during the conversion. &lt;/p&gt;

&lt;p&gt;Imagine having to implement new features or hotfixes in such an application; it can be exceedingly difficult to keep up with ongoing changes during the conversion. &lt;/p&gt;

&lt;p&gt;This is one of the primary reasons developers often hesitate to convert an extensive Express.js application from JavaScript to TypeScript.&lt;/p&gt;

&lt;p&gt;In this article, we will explore the fastest and least disruptive way to convert a mid to large Express.js application from JavaScript to TypeScript. &lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Nodejs ≥ v16.4.0 installed on your machine&lt;/li&gt;
&lt;li&gt;Basic Understanding of javascript, typescript, nodejs/expressjs&lt;/li&gt;
&lt;li&gt;Having expressjs application writing in javascript&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setup your expressjs application
&lt;/h2&gt;

&lt;p&gt;clone the application and navigate to the root directory&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/codateam/your-repo-name.git
cd your-repo-name
&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%2Fqk0f4mc48tdqxxhbzx46.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%2Fqk0f4mc48tdqxxhbzx46.png" alt="Files before convertion" width="606" height="1222"&gt;&lt;/a&gt;&lt;br&gt;
Javascript files before converted to typescript&lt;/p&gt;
&lt;h2&gt;
  
  
  Create bash script to automate file convertion from .js to .ts
&lt;/h2&gt;

&lt;p&gt;Rename javascript to typescript file one by one main be boring and time consuming, especially in medium or large application with tons of files, automating the process will save a lot of time.&lt;/p&gt;

&lt;p&gt;Create a bash script file &lt;strong&gt;convert-js-to-ts.sh&lt;/strong&gt; in the root of your application and update with below code, you can read about &lt;a href="https://devdocs.io/bash/" rel="noopener noreferrer"&gt;bashs script&lt;/a&gt; if you aren't familiar or read about about &lt;a href="https://stackoverflow.com/questions/35723985/bash-automatically-rename-file-as-its-folder" rel="noopener noreferrer"&gt;BASH - Automatically rename file as its folder&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;#!/bin/bash

# Function to rename JavaScript files to TypeScript
rename_js_to_ts() {
  for file in "$1"/*.js; do
    if [ -e "$file" ]; then
      new_file="${file%.js}.ts"
      mv "$file" "$new_file"
      echo "Renamed $file to $new_file"
    fi
  done

  # Recursively process subdirectories, excluding node_modules
  for dir in "$1"/*; do
    if [ -d "$dir" ] &amp;amp;&amp;amp; [ "${dir##*/}" != "node_modules" ]; then
      rename_js_to_ts "$dir"
    fi
  done
}

# Check if a directory is provided as an argument
if [ -z "$1" ]; then
  echo "Usage: $0 &amp;lt;directory&amp;gt;"
  exit 1
fi

# Check if the provided path is a directory
if [ ! -d "$1" ]; then
  echo "Error: '$1' is not a directory."
  exit 1
fi

# Call the function to rename files
rename_js_to_ts "$1"

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

&lt;/div&gt;



&lt;p&gt;Remember to make this script executable by executing the below command in your terminal.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;chmod +x convert-js-to-ts.sh&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Execute the script in your commandline
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./convert-js-to-ts.sh .
&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%2Fwbzg5t1ck6ael5yjfs3p.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%2Fwbzg5t1ck6ael5yjfs3p.png" alt="Files after convertion" width="600" height="1374"&gt;&lt;/a&gt;&lt;br&gt;
Typescript files after convertion&lt;/p&gt;
&lt;h2&gt;
  
  
  Installing required typescript dependencies
&lt;/h2&gt;

&lt;p&gt;Below are the typescript required for my project (yours maybe different).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add -D typescript ts-node @types/node @types/express @types/mongoose @types/multer @types/passport @types/passport-jwt @types/passport-local @types/passport-local-mongoose @types/socket.io @types/winston

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Generating tsconfig.json by enter below command in your terminal
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx tsc --init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Modify your tsconfig.json file
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; {
  "compilerOptions": {
    ...
    "outDir": "./dist"
    ...
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;remove .js from all your import code search &lt;strong&gt;.js"&lt;/strong&gt; and click on replace &lt;strong&gt;"&lt;/strong&gt; in vscode or your preferred editor&lt;/p&gt;

&lt;h2&gt;
  
  
  Running TypeScript in Node with ts-node
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx ts-node src/index.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;if you're unable to get it work with ts-node you can using concurrently, &lt;/p&gt;

&lt;p&gt;package.json&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
 "scripts": {
   "start": "node dist/server",
   "dev": "concurrently \"npx tsc --watch\" \"nodemon -q dist/server.js\""
  },
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Start your application
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn run dev
&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%2Fmfcz06vcqqu6tibt4cp6.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%2Fmfcz06vcqqu6tibt4cp6.png" alt=" " width="800" height="311"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;NB: The project can be deployed when you're still fixing types errors and new features can be implemented in typescript&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Converting a large Express.js application to TypeScript is a significant undertaking, but with proper planning and automation, you can streamline the process. &lt;/p&gt;

&lt;p&gt;Keep in mind that each project is unique, so adapt the steps and script to fit your specific requirements. &lt;/p&gt;

&lt;p&gt;Thanks for reading.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>node</category>
    </item>
  </channel>
</rss>
