<?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: Dainy Jose</title>
    <description>The latest articles on DEV Community by Dainy Jose (@dainyjose).</description>
    <link>https://dev.to/dainyjose</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%2F2361642%2F2d2d706c-5407-43f9-a162-574bce781b78.png</url>
      <title>DEV Community: Dainy Jose</title>
      <link>https://dev.to/dainyjose</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dainyjose"/>
    <language>en</language>
    <item>
      <title>Understanding OWASP Mobile Top 10 (2025): A Guide for Android &amp; iOS Developers</title>
      <dc:creator>Dainy Jose</dc:creator>
      <pubDate>Sun, 28 Jun 2026 16:32:01 +0000</pubDate>
      <link>https://dev.to/dainyjose/understanding-owasp-mobile-top-10-2025-a-guide-for-android-ios-developers-371p</link>
      <guid>https://dev.to/dainyjose/understanding-owasp-mobile-top-10-2025-a-guide-for-android-ios-developers-371p</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Disclaimer: This article summarizes the concepts I learned while studying the OWASP Mobile Top 10 (2025) and includes additional references from official OWASP documentation to help fellow developers get started.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Mobile applications have become an essential part of our daily lives, handling everything from banking and healthcare to shopping and communication. As mobile apps process increasingly sensitive data, security must be considered throughout the development lifecycle—not as an afterthought.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;OWASP Mobile Top 10 (2025)&lt;/strong&gt; is a community-driven list of the most critical security risks affecting Android and iOS applications. It helps developers, security engineers, and organizations understand common vulnerabilities and implement best practices to build more secure mobile apps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why OWASP Mobile Top 10 Matters
&lt;/h2&gt;

&lt;p&gt;Many security incidents occur because of simple mistakes such as storing sensitive data insecurely, trusting client-side validation, or using outdated cryptographic algorithms.&lt;/p&gt;

&lt;p&gt;By understanding these risks early, developers can design applications that are more resilient against attacks like reverse engineering, credential theft, data leakage, and unauthorized access.&lt;/p&gt;




&lt;h1&gt;
  
  
  The OWASP Mobile Top 10 (2025)
&lt;/h1&gt;

&lt;h2&gt;
  
  
  M1: Improper Credential Usage
&lt;/h2&gt;

&lt;p&gt;Applications should never hardcode API keys, passwords, or authentication tokens. Credentials stored insecurely can be extracted through reverse engineering and used to access backend services.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Use OAuth 2.0/OpenID Connect&lt;/li&gt;
&lt;li&gt;Store secrets in Android Keystore or iOS Keychain&lt;/li&gt;
&lt;li&gt;Use short-lived access tokens and refresh token rotation&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  M2: Inadequate Supply Chain Security
&lt;/h2&gt;

&lt;p&gt;Modern apps depend heavily on third-party SDKs and open-source libraries. Outdated or untrusted dependencies can introduce vulnerabilities or malicious code.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Vet third-party vendors&lt;/li&gt;
&lt;li&gt;Maintain an SBOM (Software Bill of Materials)&lt;/li&gt;
&lt;li&gt;Automate dependency scanning&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  M3: Insecure Authentication &amp;amp; Authorization
&lt;/h2&gt;

&lt;p&gt;Weak passwords, missing MFA, or poor server-side authorization can allow attackers to gain unauthorized access.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Strong password policies&lt;/li&gt;
&lt;li&gt;Platform-native biometrics&lt;/li&gt;
&lt;li&gt;Server-side authorization checks&lt;/li&gt;
&lt;li&gt;Role-Based Access Control (RBAC)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  M4: Insufficient Input &amp;amp; Output Validation
&lt;/h2&gt;

&lt;p&gt;Failing to validate user input can lead to injection attacks, data corruption, or unexpected application behavior.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Validate all client and server inputs&lt;/li&gt;
&lt;li&gt;Sanitize outputs&lt;/li&gt;
&lt;li&gt;Use parameterized queries&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  M5: Insecure Communication
&lt;/h2&gt;

&lt;p&gt;Sensitive information should always be protected while traveling across networks.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;TLS 1.2 or TLS 1.3&lt;/li&gt;
&lt;li&gt;Certificate validation&lt;/li&gt;
&lt;li&gt;Certificate pinning&lt;/li&gt;
&lt;li&gt;Disable insecure protocols&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  M6: Inadequate Privacy Controls
&lt;/h2&gt;

&lt;p&gt;Collecting excessive user data or sharing personal information without consent can violate user trust and regulations such as GDPR and CCPA.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Data minimization&lt;/li&gt;
&lt;li&gt;Explicit user consent&lt;/li&gt;
&lt;li&gt;Encrypt sensitive data&lt;/li&gt;
&lt;li&gt;Transparent privacy policies&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  M7: Insufficient Binary Protection
&lt;/h2&gt;

&lt;p&gt;Mobile apps can be reverse engineered, modified, or repackaged if they lack binary protection.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Code obfuscation (R8/ProGuard)&lt;/li&gt;
&lt;li&gt;Runtime integrity verification&lt;/li&gt;
&lt;li&gt;Signature validation&lt;/li&gt;
&lt;li&gt;Frida/Xposed detection&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  M8: Security Misconfiguration
&lt;/h2&gt;

&lt;p&gt;Debug logging, insecure build configurations, and exposed endpoints often leak valuable information to attackers.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Disable debug logs in production&lt;/li&gt;
&lt;li&gt;Secure release builds&lt;/li&gt;
&lt;li&gt;Regular configuration reviews&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  M9: Insecure Data Storage
&lt;/h2&gt;

&lt;p&gt;Sensitive information stored on the device should always be encrypted and protected.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Android Keystore&lt;/li&gt;
&lt;li&gt;iOS Keychain/Secure Enclave&lt;/li&gt;
&lt;li&gt;Encrypted SharedPreferences&lt;/li&gt;
&lt;li&gt;Avoid storing sensitive data unnecessarily&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  M10: Insufficient Cryptography
&lt;/h2&gt;

&lt;p&gt;Using outdated algorithms such as MD5 or weak random number generators can compromise data confidentiality.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Argon2 or bcrypt for password hashing&lt;/li&gt;
&lt;li&gt;AES-GCM for encryption&lt;/li&gt;
&lt;li&gt;SecureRandom for cryptographic randomness&lt;/li&gt;
&lt;li&gt;Regular cryptographic reviews&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Security Is More Than Writing Secure Code
&lt;/h1&gt;

&lt;p&gt;Building secure mobile applications requires a layered approach that includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Secure architecture&lt;/li&gt;
&lt;li&gt;Secure coding practices&lt;/li&gt;
&lt;li&gt;Dependency management&lt;/li&gt;
&lt;li&gt;Continuous security testing&lt;/li&gt;
&lt;li&gt;Runtime protection&lt;/li&gt;
&lt;li&gt;Monitoring and incident response&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Frameworks like &lt;strong&gt;OWASP MASVS (Mobile Application Security Verification Standard)&lt;/strong&gt; and &lt;strong&gt;OWASP MSTG (Mobile Security Testing Guide)&lt;/strong&gt; provide practical guidance for implementing and verifying these security controls.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recommended Security Tools
&lt;/h2&gt;

&lt;p&gt;Some useful tools for securing mobile applications include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MobSF&lt;/strong&gt; – Mobile application security testing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OWASP ZAP&lt;/strong&gt; – API and dynamic security testing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SonarQube&lt;/strong&gt; &amp;amp; &lt;strong&gt;Semgrep&lt;/strong&gt; – Static code analysis&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gitleaks&lt;/strong&gt; – Secret detection&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OWASP Dependency-Check&lt;/strong&gt; – Dependency vulnerability scanning&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CycloneDX / SPDX&lt;/strong&gt; – Software Bill of Materials (SBOM)&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The OWASP Mobile Top 10 (2025) is not just a list of vulnerabilities—it's a roadmap for building secure Android and iOS applications. Whether you're a mobile developer, security engineer, or architect, understanding these risks helps you create applications that protect user data, resist modern attack techniques, and meet industry security standards.&lt;/p&gt;

&lt;p&gt;Security is an ongoing process. Integrating secure design, continuous testing, and regular updates into the development lifecycle is the key to building trustworthy mobile applications.&lt;/p&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;If you're interested in learning more about mobile application security, I highly recommend this course:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OWASP Mobile Top 10 2025: Android &amp;amp; iOS App Security&lt;/strong&gt; by Dr. Amar Massoud&lt;/li&gt;
&lt;li&gt;🎓 &lt;strong&gt;My Certificate of Completion:&lt;/strong&gt; &lt;a href="https://ude.my/UC-492454b2-dbfa-4753-a9e8-35d6722b91c1" rel="noopener noreferrer"&gt;https://ude.my/UC-492454b2-dbfa-4753-a9e8-35d6722b91c1&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also explore these official OWASP resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OWASP Mobile Application Security: &lt;a href="https://owasp.org/www-project-mobile-top-10/" rel="noopener noreferrer"&gt;https://owasp.org/www-project-mobile-top-10/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;OWASP MASVS: &lt;a href="https://mas.owasp.org/MASVS/" rel="noopener noreferrer"&gt;https://mas.owasp.org/MASVS/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;OWASP MSTG: &lt;a href="https://mas.owasp.org/MSTG/" rel="noopener noreferrer"&gt;https://mas.owasp.org/MSTG/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Thank you for reading! If you found this article useful, feel free to ❤️ like it, leave a comment, or share your experience with mobile application security.&lt;/p&gt;




&lt;p&gt;✍️ Written by &lt;a href="https://www.linkedin.com/in/dainyjose" rel="noopener noreferrer"&gt;&lt;strong&gt;Dainy Jose&lt;/strong&gt;&lt;/a&gt; — React Native Mobile Application Developer with 3+ years of experience building cross-platform mobile apps using &lt;strong&gt;React Native (Expo, TypeScript, Redux)&lt;/strong&gt;. &lt;br&gt;
Currently expanding backend knowledge through the &lt;strong&gt;MERN Stack (MongoDB, Express.js, React.js, Node.js)&lt;/strong&gt; to create more efficient, full-stack mobile experiences.&lt;/p&gt;

&lt;p&gt;💼 &lt;strong&gt;Tech Stack:&lt;/strong&gt; React Native · TypeScript · Redux · Expo · Firebase · Node.js · Express.js · MongoDB · REST API · JWT · Jest · Google Maps · Razorpay · PayU · Agile · SDLC · Git · Bitbucket · Jira &lt;/p&gt;

&lt;p&gt;📬 &lt;strong&gt;Connect with me&lt;/strong&gt;:&lt;br&gt;
🌐 &lt;a href="https://dainyjose.github.io/my-portfolio/" rel="noopener noreferrer"&gt;Portfolio&lt;/a&gt;&lt;br&gt;
🔗 &lt;a href="https://www.linkedin.com/in/dainyjose" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;br&gt;
💻 &lt;a href="https://github.com/dainyjose" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>owasp</category>
      <category>mobile</category>
      <category>developer</category>
    </item>
    <item>
      <title>Building Picture-in-Picture (PiP) Mode in React Native with Expo and TypeScript</title>
      <dc:creator>Dainy Jose</dc:creator>
      <pubDate>Mon, 01 Jun 2026 17:06:29 +0000</pubDate>
      <link>https://dev.to/dainyjose/building-picture-in-picture-pip-mode-in-react-native-with-expo-and-typescript-af6</link>
      <guid>https://dev.to/dainyjose/building-picture-in-picture-pip-mode-in-react-native-with-expo-and-typescript-af6</guid>
      <description>&lt;p&gt;Picture-in-Picture (PiP) mode is one of the most useful features for media-based mobile applications. It allows users to continue watching video content while navigating outside the app.&lt;/p&gt;

&lt;p&gt;In this article, we will build a modern React Native PiP Mode Proof of Concept using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React Native&lt;/li&gt;
&lt;li&gt;Expo&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;react-native-video&lt;/li&gt;
&lt;li&gt;Native Android PiP APIs&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  What is Picture-in-Picture (PiP)?
&lt;/h3&gt;

&lt;p&gt;Picture-in-Picture mode allows a video player to continue playing inside a small floating window while users interact with other applications.&lt;/p&gt;

&lt;p&gt;Popular apps using PiP:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;YouTube&lt;/li&gt;
&lt;li&gt;Google Meet&lt;/li&gt;
&lt;li&gt;Netflix&lt;/li&gt;
&lt;li&gt;WhatsApp Video Calls&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  Final Result
&lt;/h4&gt;

&lt;p&gt;Features implemented:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Floating mini-player&lt;/li&gt;
&lt;li&gt;Background playback&lt;/li&gt;
&lt;li&gt;Auto-enter PiP mode&lt;/li&gt;
&lt;li&gt;Manual PiP trigger&lt;/li&gt;
&lt;li&gt;Modern UI&lt;/li&gt;
&lt;li&gt;Reusable custom hook&lt;/li&gt;
&lt;li&gt;Native Android integration&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Source Code&lt;/p&gt;

&lt;p&gt;The complete source code for this project is available on GitHub:&lt;/p&gt;

&lt;p&gt;🔗 GitHub Repository: &lt;a href="https://github.com/dainyjose/pip-video-player-mobile" rel="noopener noreferrer"&gt;https://github.com/dainyjose/pip-video-player-mobile&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Create Project
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Expo Project Setup
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-expo-app react-native-pip-poc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Move into the project:&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;cd &lt;/span&gt;react-native-pip-poc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Install Dependencies
&lt;/h3&gt;

&lt;p&gt;Install video package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;react-native-video
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Project Structure
&lt;/h3&gt;

&lt;p&gt;Instead of putting everything inside &lt;code&gt;App.tsx&lt;/code&gt;, use a scalable architecture.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
 ├── components/
 │    ├── MiniPlayer.tsx
 │    ├── PipButton.tsx
 │    ├── PipStatus.tsx
 │    └── VideoPlayer.tsx
 │
 ├── hooks/
 │    └── usePictureInPicture.ts
 │
 ├── constants/
 │    └── video.ts
 │
 ├── screens/
 │    └── PlayerScreen.tsx
 │
 └── types/
      └── video.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This keeps the code reusable and production-ready.&lt;/p&gt;




&lt;h3&gt;
  
  
  Android PiP Configuration
&lt;/h3&gt;

&lt;h4&gt;
  
  
  AndroidManifest.xml
&lt;/h4&gt;

&lt;p&gt;Open:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;android/app/src/main/AndroidManifest.xml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add:&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;activity&lt;/span&gt;
  &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;".MainActivity"&lt;/span&gt;
  &lt;span class="na"&gt;android:supportsPictureInPicture=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
  &lt;span class="na"&gt;android:configChanges=&lt;/span&gt;&lt;span class="s"&gt;"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"&lt;/span&gt;
  &lt;span class="na"&gt;android:launchMode=&lt;/span&gt;&lt;span class="s"&gt;"singleTask"&lt;/span&gt;
  &lt;span class="na"&gt;android:windowSoftInputMode=&lt;/span&gt;&lt;span class="s"&gt;"adjustResize"&lt;/span&gt;
  &lt;span class="na"&gt;android:exported=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This enables native Android PiP support.&lt;/p&gt;




&lt;h3&gt;
  
  
  Configure MainActivity.kt
&lt;/h3&gt;

&lt;p&gt;Open:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;android/app/src/main/java/.../MainActivity.kt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add:&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="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onUserLeaveHint&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onUserLeaveHint&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="nc"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;VERSION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SDK_INT&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nc"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;VERSION_CODES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;O&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;params&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
            &lt;span class="nc"&gt;PictureInPictureParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAspectRatio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Rational&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="nf"&gt;enterPictureInPictureMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&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;p&gt;This automatically enters PiP mode when the app moves to the background.&lt;/p&gt;




&lt;h3&gt;
  
  
  Create Reusable PiP Hook
&lt;/h3&gt;

&lt;h3&gt;
  
  
  usePictureInPicture.ts
&lt;/h3&gt;

&lt;p&gt;Instead of writing all logic directly inside the screen, create a reusable hook.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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;useCallback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&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="s2"&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;Platform&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="s2"&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;VideoRef&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="s2"&gt;react-native-video&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;usePictureInPicture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;videoRef&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RefObject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;VideoRef&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;loadedRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pendingPipRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&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;pipActive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPipActive&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&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;paused&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPaused&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;enterPip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;delays&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="nx"&gt;Platform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OS&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ios&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="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;700&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1200&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="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="nx"&gt;delays&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;delay&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="nf"&gt;setTimeout&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="nx"&gt;videoRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;enterPictureInPicture&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;delay&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;activateFloatingPlayer&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="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;pendingPipRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;setPaused&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&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;loadedRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;enterPip&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;paused&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;setPaused&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;pipActive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;setPipActive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;loadedRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;activateFloatingPlayer&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;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reusable logic&lt;/li&gt;
&lt;li&gt;cleaner screens&lt;/li&gt;
&lt;li&gt;easier maintenance&lt;/li&gt;
&lt;li&gt;scalable architecture&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Build Video Player Component
&lt;/h3&gt;

&lt;h4&gt;
  
  
  VideoPlayer.tsx
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Video&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-native-video&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Video&lt;/span&gt;
  &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;videoRef&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;VIDEO_SOURCE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;video&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;resizeMode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"contain"&lt;/span&gt;
  &lt;span class="na"&gt;paused&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;paused&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;controls&lt;/span&gt;
  &lt;span class="na"&gt;playInBackground&lt;/span&gt;
  &lt;span class="na"&gt;playWhenInactive&lt;/span&gt;
  &lt;span class="na"&gt;enterPictureInPictureOnLeave&lt;/span&gt;
  &lt;span class="na"&gt;ignoreSilentSwitch&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"ignore"&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Important PiP props:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Prop&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;playInBackground&lt;/td&gt;
&lt;td&gt;Continue playback in background&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;playWhenInactive&lt;/td&gt;
&lt;td&gt;Allow inactive playback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;enterPictureInPictureOnLeave&lt;/td&gt;
&lt;td&gt;Auto-enter PiP&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  Auto PiP on Background
&lt;/h3&gt;

&lt;p&gt;Inside the screen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;AppState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;change&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="nx"&gt;state&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;state&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;background&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="nf"&gt;activateFloatingPlayer&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="k"&gt;return &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;sub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&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;p&gt;This creates a YouTube-like experience.&lt;/p&gt;




&lt;h3&gt;
  
  
  Modern UI Layout
&lt;/h3&gt;

&lt;p&gt;Instead of basic buttons, create:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Player card&lt;/li&gt;
&lt;li&gt;Floating mini-player&lt;/li&gt;
&lt;li&gt;Status cards&lt;/li&gt;
&lt;li&gt;Dark streaming UI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;playerCard&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;VideoPlayer&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PipButton&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PipStatus&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Running the Project
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Android
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx expo run:android
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Important Notes
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Expo Go Limitation
&lt;/h4&gt;

&lt;p&gt;Expo Go may not fully support native PiP functionality.&lt;/p&gt;

&lt;p&gt;Use native builds instead.&lt;/p&gt;




&lt;h3&gt;
  
  
  Common Issues
&lt;/h3&gt;

&lt;h4&gt;
  
  
  PiP Not Starting
&lt;/h4&gt;

&lt;p&gt;Check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Android version &amp;gt;= 8&lt;/li&gt;
&lt;li&gt;Manifest configuration&lt;/li&gt;
&lt;li&gt;Native build usage&lt;/li&gt;
&lt;li&gt;Video loaded state&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  App Crashes
&lt;/h4&gt;

&lt;p&gt;Verify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;correct MainActivity.kt imports&lt;/li&gt;
&lt;li&gt;react-native-video installation&lt;/li&gt;
&lt;li&gt;Android SDK compatibility&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Future Improvements
&lt;/h3&gt;

&lt;p&gt;This PoC can be extended with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Custom PiP controls&lt;/li&gt;
&lt;li&gt;Live streaming&lt;/li&gt;
&lt;li&gt;Video call PiP&lt;/li&gt;
&lt;li&gt;Draggable mini-player&lt;/li&gt;
&lt;li&gt;Media session controls&lt;/li&gt;
&lt;li&gt;Netflix-style player UI&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;Picture-in-Picture mode significantly improves user experience for media applications.&lt;/p&gt;

&lt;p&gt;With React Native, Expo, and native Android APIs, we can build scalable and modern PiP experiences similar to YouTube and Netflix.&lt;/p&gt;

&lt;p&gt;This project demonstrates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;native Android PiP integration&lt;/li&gt;
&lt;li&gt;modular React Native architecture&lt;/li&gt;
&lt;li&gt;reusable hooks&lt;/li&gt;
&lt;li&gt;background playback handling&lt;/li&gt;
&lt;li&gt;scalable UI structure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can now extend this implementation into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OTT applications&lt;/li&gt;
&lt;li&gt;Video conferencing apps&lt;/li&gt;
&lt;li&gt;Live class platforms&lt;/li&gt;
&lt;li&gt;Social media video apps&lt;/li&gt;
&lt;li&gt;Streaming platforms&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;✍️ Written by &lt;a href="https://www.linkedin.com/in/dainyjose" rel="noopener noreferrer"&gt;&lt;strong&gt;Dainy Jose&lt;/strong&gt;&lt;/a&gt; — React Native Mobile Application Developer with 3+ years of experience building cross-platform mobile apps using &lt;strong&gt;React Native (Expo, TypeScript, Redux)&lt;/strong&gt;. &lt;br&gt;
Currently expanding backend knowledge through the &lt;strong&gt;MERN Stack (MongoDB, Express.js, React.js, Node.js)&lt;/strong&gt; to create more efficient, full-stack mobile experiences.&lt;/p&gt;

&lt;p&gt;💼 &lt;strong&gt;Tech Stack:&lt;/strong&gt; React Native · TypeScript · Redux · Expo · Firebase · Node.js · Express.js · MongoDB · REST API · JWT · Jest · Google Maps · Razorpay · PayU · Agile · SDLC · Git · Bitbucket · Jira &lt;/p&gt;

&lt;p&gt;📬 &lt;strong&gt;Connect with me&lt;/strong&gt;:&lt;br&gt;
🌐 &lt;a href="https://dainyjose.github.io/my-portfolio/" rel="noopener noreferrer"&gt;Portfolio&lt;/a&gt;&lt;br&gt;
🔗 &lt;a href="https://www.linkedin.com/in/dainyjose" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;br&gt;
💻 &lt;a href="https://github.com/dainyjose" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>android</category>
      <category>ios</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Complete CI/CD Guide for React Native Apps Using GitHub Actions</title>
      <dc:creator>Dainy Jose</dc:creator>
      <pubDate>Mon, 11 May 2026 08:43:26 +0000</pubDate>
      <link>https://dev.to/dainyjose/complete-cicd-guide-for-react-native-apps-using-github-actions-4hh1</link>
      <guid>https://dev.to/dainyjose/complete-cicd-guide-for-react-native-apps-using-github-actions-4hh1</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Automating builds, testing, and deployments can save hours of manual work in React Native projects. This article explains how to set up a practical CI/CD pipeline for Android and iOS apps using GitHub Actions.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;As React Native projects grow, manual release processes become difficult.&lt;/p&gt;

&lt;p&gt;Developers often spend time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;generating APKs manually&lt;/li&gt;
&lt;li&gt;updating versions&lt;/li&gt;
&lt;li&gt;testing release builds&lt;/li&gt;
&lt;li&gt;uploading builds to stores&lt;/li&gt;
&lt;li&gt;fixing environment issues&lt;/li&gt;
&lt;li&gt;handling signing configurations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This process becomes repetitive and error-prone.&lt;/p&gt;

&lt;p&gt;That’s where CI/CD helps.&lt;/p&gt;

&lt;p&gt;A proper CI/CD pipeline can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;automate builds&lt;/li&gt;
&lt;li&gt;reduce human errors&lt;/li&gt;
&lt;li&gt;improve release consistency&lt;/li&gt;
&lt;li&gt;speed up deployments&lt;/li&gt;
&lt;li&gt;help teams collaborate efficiently&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this article, I’ll explain how I set up CI/CD for React Native apps using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub Actions&lt;/li&gt;
&lt;li&gt;Fastlane&lt;/li&gt;
&lt;li&gt;Android &amp;amp; iOS workflows&lt;/li&gt;
&lt;li&gt;environment configurations&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  What is CI/CD?
&lt;/h1&gt;

&lt;p&gt;CI/CD stands for:&lt;/p&gt;

&lt;h2&gt;
  
  
  Continuous Integration (CI)
&lt;/h2&gt;

&lt;p&gt;Automatically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;validating code&lt;/li&gt;
&lt;li&gt;running tests&lt;/li&gt;
&lt;li&gt;checking builds&lt;/li&gt;
&lt;li&gt;detecting issues early&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;whenever code is pushed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Continuous Deployment/Delivery (CD)
&lt;/h2&gt;

&lt;p&gt;Automatically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;generating release builds&lt;/li&gt;
&lt;li&gt;distributing apps&lt;/li&gt;
&lt;li&gt;deploying to stores&lt;/li&gt;
&lt;li&gt;handling release workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This reduces manual release effort.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why CI/CD Matters in React Native
&lt;/h1&gt;

&lt;p&gt;React Native projects involve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JavaScript&lt;/li&gt;
&lt;li&gt;Android native code&lt;/li&gt;
&lt;li&gt;iOS native code&lt;/li&gt;
&lt;li&gt;multiple environments&lt;/li&gt;
&lt;li&gt;third-party SDKs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without automation, release management becomes difficult.&lt;/p&gt;




&lt;h1&gt;
  
  
  Tools You Can Use
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. GitHub Actions
&lt;/h2&gt;

&lt;p&gt;Used for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;workflow automation&lt;/li&gt;
&lt;li&gt;build pipelines&lt;/li&gt;
&lt;li&gt;running scripts&lt;/li&gt;
&lt;li&gt;deployment triggers&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Fastlane
&lt;/h2&gt;

&lt;p&gt;Used for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Android Play Store uploads&lt;/li&gt;
&lt;li&gt;TestFlight uploads&lt;/li&gt;
&lt;li&gt;signing management&lt;/li&gt;
&lt;li&gt;screenshots and metadata&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Firebase Crashlytics
&lt;/h2&gt;

&lt;p&gt;Used for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;crash monitoring&lt;/li&gt;
&lt;li&gt;release issue tracking&lt;/li&gt;
&lt;li&gt;production debugging&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Recommended Project Setup
&lt;/h1&gt;

&lt;p&gt;Before setting up CI/CD, ensure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- separate environments
- proper signing setup
- release build testing
- version management
- secure secret storage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prevents many pipeline issues later.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 1: Create GitHub Actions Workflow
&lt;/h1&gt;

&lt;p&gt;Inside your project:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Create:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;android-build.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Android Build&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout Code&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Node&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build Android APK&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;cd android&lt;/span&gt;
          &lt;span class="s"&gt;./gradlew assembleRelease&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This automatically generates Android release builds.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 2: Configure Secrets Securely
&lt;/h1&gt;

&lt;p&gt;Never store:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API keys&lt;/li&gt;
&lt;li&gt;keystore passwords&lt;/li&gt;
&lt;li&gt;certificates&lt;/li&gt;
&lt;li&gt;signing configs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;inside the repository.&lt;/p&gt;

&lt;p&gt;Use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GitHub Repository Secrets
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;signing passwords&lt;/li&gt;
&lt;li&gt;Firebase configs&lt;/li&gt;
&lt;li&gt;Play Store credentials&lt;/li&gt;
&lt;li&gt;App Store credentials&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Step 3: Android Signing Setup
&lt;/h1&gt;

&lt;p&gt;For Android release builds:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Configure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gradle"&gt;&lt;code&gt;&lt;span class="n"&gt;signingConfigs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;inside:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;android/app/build.gradle
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gradle"&gt;&lt;code&gt;&lt;span class="n"&gt;release&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;storeFile&lt;/span&gt; &lt;span class="nf"&gt;file&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MYAPP_UPLOAD_STORE_FILE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;storePassword&lt;/span&gt; &lt;span class="n"&gt;MYAPP_UPLOAD_STORE_PASSWORD&lt;/span&gt;
   &lt;span class="n"&gt;keyAlias&lt;/span&gt; &lt;span class="n"&gt;MYAPP_UPLOAD_KEY_ALIAS&lt;/span&gt;
   &lt;span class="n"&gt;keyPassword&lt;/span&gt; &lt;span class="n"&gt;MYAPP_UPLOAD_KEY_PASSWORD&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Step 4: iOS CI/CD Setup
&lt;/h1&gt;

&lt;p&gt;iOS setup is slightly more complex because of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;certificates&lt;/li&gt;
&lt;li&gt;provisioning profiles&lt;/li&gt;
&lt;li&gt;code signing&lt;/li&gt;
&lt;li&gt;macOS runners&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;GitHub Actions requires:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;macos-latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;for iOS builds.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 5: Fastlane Integration
&lt;/h1&gt;

&lt;p&gt;Fastlane simplifies deployments.&lt;/p&gt;

&lt;p&gt;Install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bundle &lt;span class="nb"&gt;exec &lt;/span&gt;fastlane init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Android Deployment Example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;lane&lt;/span&gt; &lt;span class="ss"&gt;:android_release&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;gradle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;task: &lt;/span&gt;&lt;span class="s2"&gt;"assembleRelease"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  iOS Deployment Example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;lane&lt;/span&gt; &lt;span class="ss"&gt;:ios_release&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;build_app&lt;/span&gt;
  &lt;span class="n"&gt;upload_to_testflight&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This automates deployment significantly.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 6: Automate Version Management
&lt;/h1&gt;

&lt;p&gt;One common problem in mobile releases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;incorrect build numbers&lt;/li&gt;
&lt;li&gt;duplicate version codes&lt;/li&gt;
&lt;li&gt;store upload failures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Automate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Android versionCode&lt;/li&gt;
&lt;li&gt;iOS build number&lt;/li&gt;
&lt;li&gt;semantic versions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;inside CI/CD pipelines.&lt;/p&gt;

&lt;p&gt;This reduces release mistakes.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 7: Run Quality Checks Before Builds
&lt;/h1&gt;

&lt;p&gt;Before generating release builds, I recommend running:&lt;/p&gt;

&lt;h2&gt;
  
  
  Lint
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run lint
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  TypeScript Check
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx tsc &lt;span class="nt"&gt;--noEmit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Tests
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prevents broken builds from reaching production.&lt;/p&gt;




&lt;h1&gt;
  
  
  Handling Multiple Environments
&lt;/h1&gt;

&lt;p&gt;In production apps, we usually have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- development
- staging
- production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I manage environments using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.env.development
.env.production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;with separate workflows.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github.ref == 'refs/heads/main'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;for production deployments.&lt;/p&gt;




&lt;h1&gt;
  
  
  Common CI/CD Issues I Faced
&lt;/h1&gt;

&lt;h1&gt;
  
  
  1. Android Build Works Locally but Fails in CI
&lt;/h1&gt;

&lt;p&gt;Usually caused by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;missing SDK versions&lt;/li&gt;
&lt;li&gt;Gradle mismatch&lt;/li&gt;
&lt;li&gt;Java version issues&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  2. iOS Signing Failures
&lt;/h1&gt;

&lt;p&gt;Most common problem in iOS pipelines.&lt;/p&gt;

&lt;p&gt;Usually related to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;certificates&lt;/li&gt;
&lt;li&gt;provisioning profiles&lt;/li&gt;
&lt;li&gt;Apple Developer configuration&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  3. Environment Variables Missing
&lt;/h1&gt;

&lt;p&gt;Sometimes release builds fail because CI environments do not load &lt;code&gt;.env&lt;/code&gt; correctly.&lt;/p&gt;

&lt;p&gt;Always validate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;workflow variables&lt;/li&gt;
&lt;li&gt;secret mappings&lt;/li&gt;
&lt;li&gt;build configurations&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  4. Slow Build Times
&lt;/h1&gt;

&lt;p&gt;Large React Native projects can become slow in CI.&lt;/p&gt;

&lt;p&gt;Build times can be improved using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;dependency caching&lt;/li&gt;
&lt;li&gt;Gradle caching&lt;/li&gt;
&lt;li&gt;npm caching&lt;/li&gt;
&lt;li&gt;selective workflows&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  My Recommended CI/CD Practices
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. Always Test Release Builds
&lt;/h2&gt;

&lt;p&gt;Debug builds are not enough.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Keep Secrets Secure
&lt;/h2&gt;

&lt;p&gt;Never commit sensitive credentials.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Automate Repetitive Tasks
&lt;/h2&gt;

&lt;p&gt;Anything repeated manually should probably be automated.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Separate Development &amp;amp; Production Pipelines
&lt;/h2&gt;

&lt;p&gt;This prevents accidental releases.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Monitor Releases Properly
&lt;/h2&gt;

&lt;p&gt;Use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Crashlytics&lt;/li&gt;
&lt;li&gt;logs&lt;/li&gt;
&lt;li&gt;analytics&lt;/li&gt;
&lt;li&gt;release monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;for production stability.&lt;/p&gt;




&lt;h1&gt;
  
  
  Benefits of Implementing CI/CD
&lt;/h1&gt;

&lt;p&gt;After setting up CI/CD:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;releases became faster&lt;/li&gt;
&lt;li&gt;fewer manual mistakes happened&lt;/li&gt;
&lt;li&gt;deployments became more consistent&lt;/li&gt;
&lt;li&gt;onboarding developers became easier&lt;/li&gt;
&lt;li&gt;debugging release issues improved&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most importantly, the release process became predictable.&lt;/p&gt;




&lt;h1&gt;
  
  
  Final Thoughts
&lt;/h1&gt;

&lt;p&gt;CI/CD may initially feel complicated in React Native projects.&lt;/p&gt;

&lt;p&gt;Especially because mobile apps involve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Android builds&lt;/li&gt;
&lt;li&gt;iOS signing&lt;/li&gt;
&lt;li&gt;native dependencies&lt;/li&gt;
&lt;li&gt;environment management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But once configured properly, it saves a huge amount of development time.&lt;/p&gt;

&lt;p&gt;Even a basic CI/CD setup can dramatically improve team productivity and release quality.&lt;/p&gt;

&lt;p&gt;Start simple.&lt;br&gt;
Then gradually automate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;testing&lt;/li&gt;
&lt;li&gt;builds&lt;/li&gt;
&lt;li&gt;deployments&lt;/li&gt;
&lt;li&gt;versioning&lt;/li&gt;
&lt;li&gt;monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;over time.&lt;/p&gt;




&lt;h2&gt;
  
  
  How are you managing CI/CD in your React Native projects?
&lt;/h2&gt;

&lt;p&gt;Are you using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub Actions&lt;/li&gt;
&lt;li&gt;Fastlane&lt;/li&gt;
&lt;li&gt;Bitrise&lt;/li&gt;
&lt;li&gt;CircleCI&lt;/li&gt;
&lt;li&gt;Expo EAS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Share your workflow in the comments 👇&lt;/p&gt;




&lt;p&gt;✍️ Written by &lt;a href="https://www.linkedin.com/in/dainyjose" rel="noopener noreferrer"&gt;&lt;strong&gt;Dainy Jose&lt;/strong&gt;&lt;/a&gt; — React Native Mobile Application Developer with 3+ years of experience building cross-platform mobile apps using &lt;strong&gt;React Native (Expo, TypeScript, Redux)&lt;/strong&gt;. &lt;br&gt;
Currently expanding backend knowledge through the &lt;strong&gt;MERN Stack (MongoDB, Express.js, React.js, Node.js)&lt;/strong&gt; to create more efficient, full-stack mobile experiences.&lt;/p&gt;

&lt;p&gt;💼 &lt;strong&gt;Tech Stack:&lt;/strong&gt; React Native · TypeScript · Redux · Expo · Firebase · Node.js · Express.js · MongoDB · REST API · JWT · Jest · Google Maps · Razorpay · PayU · Agile · SDLC · Git · Bitbucket · Jira &lt;/p&gt;

&lt;p&gt;📬 &lt;strong&gt;Connect with me&lt;/strong&gt;:&lt;br&gt;
🌐 &lt;a href="https://dainyjose.github.io/my-portfolio/" rel="noopener noreferrer"&gt;Portfolio&lt;/a&gt;&lt;br&gt;
🔗 &lt;a href="https://www.linkedin.com/in/dainyjose" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;br&gt;
💻 &lt;a href="https://github.com/dainyjose" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>github</category>
      <category>reactnative</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Preparing Your iOS App for the Upcoming SDK Requirements (April 2026)</title>
      <dc:creator>Dainy Jose</dc:creator>
      <pubDate>Thu, 16 Apr 2026 12:10:57 +0000</pubDate>
      <link>https://dev.to/dainyjose/preparing-your-ios-app-for-the-upcoming-sdk-requirements-april-2026-3l7f</link>
      <guid>https://dev.to/dainyjose/preparing-your-ios-app-for-the-upcoming-sdk-requirements-april-2026-3l7f</guid>
      <description>&lt;p&gt;Apple has announced new minimum SDK requirements for App Store submissions starting &lt;strong&gt;April 28, 2026&lt;/strong&gt;. If you're working on an iOS app, it's time to plan your upgrade.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s Changing?
&lt;/h2&gt;

&lt;p&gt;All apps submitted to App Store Connect must be built with the latest SDK versions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;iOS / iPadOS → &lt;strong&gt;SDK 26 or later&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;tvOS → &lt;strong&gt;SDK 26 or later&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;visionOS → &lt;strong&gt;SDK 26 or later&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;watchOS → &lt;strong&gt;SDK 26 or later&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Required Upgrades
&lt;/h2&gt;

&lt;p&gt;To meet these requirements, ensure your development environment is updated:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;macOS → Version 26.4 (Tahoe)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Xcode → Version 26&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Common Issue After Upgrade
&lt;/h2&gt;

&lt;p&gt;After upgrading, you might encounter a build issue related to the &lt;strong&gt;&lt;code&gt;fmt&lt;/code&gt; library (v11.0.2)&lt;/strong&gt; when running the app on a physical device.&lt;/p&gt;

&lt;p&gt;This happens because the newer Apple Clang compiler in Xcode 26 has compatibility issues with &lt;code&gt;consteval&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Workaround Fix (Podfile Patch)
&lt;/h2&gt;

&lt;p&gt;Add the following snippet inside your existing &lt;code&gt;post_install do |installer|&lt;/code&gt; block in your &lt;strong&gt;Podfile&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Workaround for Xcode 26: newer Apple Clang breaks consteval in fmt 11.0.2&lt;/span&gt;
&lt;span class="c1"&gt;# Patch base.h to disable consteval since the header doesn't check for pre-defined FMT_USE_CONSTEVAL.&lt;/span&gt;

&lt;span class="n"&gt;fmt_base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;installer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sandbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'fmt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'include'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'fmt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'base.h'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exist?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmt_base&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmt_base&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Xcode 26 workaround'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;patched&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gsub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="sr"&gt;/^(#elif defined\(__cpp_consteval\)\n#  define FMT_USE_CONSTEVAL) 1/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"// Xcode 26 workaround: disable consteval&lt;/span&gt;&lt;span class="se"&gt;\n\\&lt;/span&gt;&lt;span class="s2"&gt;1 0"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;patched&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;
      &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chmod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mo"&gt;0644&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt_base&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmt_base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;patched&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Final Steps
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Add the snippet to your &lt;code&gt;Podfile&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;   pod install
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Clean and rebuild your project&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Apple Announcement: &lt;a href="https://developer.apple.com/news/?id=ueeok6yw" rel="noopener noreferrer"&gt;https://developer.apple.com/news/?id=ueeok6yw&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Expo Issue Thread: &lt;a href="https://github.com/expo/expo/issues/44229" rel="noopener noreferrer"&gt;https://github.com/expo/expo/issues/44229&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Don’t wait until the deadline. Upgrade early to identify and fix compatibility issues in your dependencies.&lt;/p&gt;




&lt;p&gt;✍️ Written by &lt;a href="https://www.linkedin.com/in/dainyjose" rel="noopener noreferrer"&gt;&lt;strong&gt;Dainy Jose&lt;/strong&gt;&lt;/a&gt; — React Native Mobile Application Developer with 3+ years of experience building cross-platform mobile apps using &lt;strong&gt;React Native (Expo, TypeScript, Redux)&lt;/strong&gt;. &lt;br&gt;
Currently expanding backend knowledge through the &lt;strong&gt;MERN Stack (MongoDB, Express.js, React.js, Node.js)&lt;/strong&gt; to create more efficient, full-stack mobile experiences.&lt;/p&gt;

&lt;p&gt;💼 &lt;strong&gt;Tech Stack:&lt;/strong&gt; React Native · TypeScript · Redux · Expo · Firebase · Node.js · Express.js · MongoDB · REST API · JWT · Jest · Google Maps · Razorpay · PayU · Agile · SDLC · Git · Bitbucket · Jira &lt;/p&gt;

&lt;p&gt;📬 &lt;strong&gt;Connect with me&lt;/strong&gt;:&lt;br&gt;
🌐 &lt;a href="https://dainyjose.github.io/my-portfolio/" rel="noopener noreferrer"&gt;Portfolio&lt;/a&gt;&lt;br&gt;
🔗 &lt;a href="https://www.linkedin.com/in/dainyjose" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;br&gt;
💻 &lt;a href="https://github.com/dainyjose" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>xcode</category>
      <category>expo</category>
      <category>ios</category>
    </item>
    <item>
      <title>Implementing Firebase Crashlytics in React Native</title>
      <dc:creator>Dainy Jose</dc:creator>
      <pubDate>Sun, 15 Mar 2026 08:19:26 +0000</pubDate>
      <link>https://dev.to/dainyjose/implementing-firebase-crashlytics-in-react-native-12i3</link>
      <guid>https://dev.to/dainyjose/implementing-firebase-crashlytics-in-react-native-12i3</guid>
      <description>&lt;p&gt;&lt;strong&gt;Firebase Crashlytics&lt;/strong&gt; is a lightweight, real-time crash reporting tool that helps developers monitor, track, and fix app crashes. Integrating &lt;strong&gt;Crashlytics&lt;/strong&gt; in a React Native app improves app stability and ensures you can react quickly to issues in production.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before implementing Crashlytics, ensure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A React Native project (bare or Expo managed workflow).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Firebase project created in Firebase Console.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;@react-native-firebase/app&lt;/code&gt; and &lt;code&gt;@react-native-firebase/crashlytics&lt;/code&gt; installed (for bare workflow).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Install Dependencies
&lt;/h2&gt;

&lt;p&gt;For React Native bare workflow, install Firebase packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i @react-native-firebase/app @react-native-firebase/crashlytics
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For &lt;strong&gt;Expo managed workflow&lt;/strong&gt;, you can use the bare workflow or &lt;code&gt;expo-firebase-crashlytics&lt;/code&gt; (currently requires ejecting to bare workflow for full support).&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Configure Firebase in Your Project
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;iOS Setup&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Download &lt;code&gt;GoogleService-Info.plist&lt;/code&gt; from Firebase Console.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add it to &lt;code&gt;ios/YourAppName&lt;/code&gt; folder.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In Xcode, select your project → &lt;strong&gt;Build Phases → Copy Bundle Resources&lt;/strong&gt;, and ensure &lt;code&gt;GoogleService-Info.plist&lt;/code&gt; is included.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Android Setup&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Download &lt;code&gt;google-services.json&lt;/code&gt; from Firebase Console.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Place it under &lt;code&gt;android/app/&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Modify &lt;code&gt;android/build.gradle&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;buildscript &lt;span class="o"&gt;{&lt;/span&gt;
    dependencies &lt;span class="o"&gt;{&lt;/span&gt;
        classpath &lt;span class="s1"&gt;'com.google.gms:google-services:4.3.15'&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Modify &lt;code&gt;android/app/build.gradle&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apply plugin: &lt;span class="s1"&gt;'com.google.gms.google-services'&lt;/span&gt;

dependencies &lt;span class="o"&gt;{&lt;/span&gt;
    implementation platform&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'com.google.firebase:firebase-bom:32.1.0'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    implementation &lt;span class="s1"&gt;'com.google.firebase:firebase-crashlytics'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. Initialize Firebase Crashlytics
&lt;/h2&gt;

&lt;p&gt;In your app’s entry file (&lt;code&gt;App.tsx&lt;/code&gt; or &lt;code&gt;index.js&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;import crashlytics from &lt;span class="s1"&gt;'@react-native-firebase/crashlytics'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import React, &lt;span class="o"&gt;{&lt;/span&gt; useEffect &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'react'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import &lt;span class="o"&gt;{&lt;/span&gt; Button, View, Text &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'react-native'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nb"&gt;export &lt;/span&gt;default &lt;span class="k"&gt;function &lt;/span&gt;App&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  useEffect&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    // Enable Crashlytics collection
    crashlytics&lt;span class="o"&gt;()&lt;/span&gt;.setCrashlyticsCollectionEnabled&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    // Log app start
    crashlytics&lt;span class="o"&gt;()&lt;/span&gt;.log&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'App mounted'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;, &lt;span class="o"&gt;[])&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  const testCrash &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    // This will trigger a &lt;span class="nb"&gt;test &lt;/span&gt;crash
    crashlytics&lt;span class="o"&gt;()&lt;/span&gt;.crash&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  const logCustomError &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    crashlytics&lt;span class="o"&gt;()&lt;/span&gt;.recordError&lt;span class="o"&gt;(&lt;/span&gt;new Error&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Custom handled error'&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;
    &amp;lt;View &lt;span class="nv"&gt;style&lt;/span&gt;&lt;span class="o"&gt;={{&lt;/span&gt; flex: 1, justifyContent: &lt;span class="s1"&gt;'center'&lt;/span&gt;, alignItems: &lt;span class="s1"&gt;'center'&lt;/span&gt; &lt;span class="o"&gt;}}&amp;gt;&lt;/span&gt;
      &amp;lt;Text&amp;gt;Firebase Crashlytics Demo&amp;lt;/Text&amp;gt;
      &amp;lt;Button &lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Test Crash"&lt;/span&gt; &lt;span class="nv"&gt;onPress&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;testCrash&lt;span class="o"&gt;}&lt;/span&gt; /&amp;gt;
      &amp;lt;Button &lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Log Custom Error"&lt;/span&gt; &lt;span class="nv"&gt;onPress&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;logCustomError&lt;span class="o"&gt;}&lt;/span&gt; /&amp;gt;
    &amp;lt;/View&amp;gt;
  &lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. Best Practices
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Enable crash reporting in production only&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;__DEV__&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    crashlytics&lt;span class="o"&gt;()&lt;/span&gt;.setCrashlyticsCollectionEnabled&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Log user-specific info&lt;/strong&gt; for better context:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;crashlytics&lt;span class="o"&gt;()&lt;/span&gt;.setUserId&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'USER_12345'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
crashlytics&lt;span class="o"&gt;()&lt;/span&gt;.setAttributes&lt;span class="o"&gt;({&lt;/span&gt; plan: &lt;span class="s1"&gt;'premium'&lt;/span&gt;, region: &lt;span class="s1"&gt;'IN'&lt;/span&gt; &lt;span class="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use &lt;code&gt;recordError&lt;/code&gt; for handled errors&lt;/strong&gt;:&lt;br&gt;
Avoid throwing errors for non-critical events; instead, log them for debugging.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Test integration&lt;/strong&gt; using the &lt;code&gt;crash()&lt;/code&gt; method to ensure crashes are visible in Firebase Console.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  6. Optional: Handling Unhandled JS Exceptions
&lt;/h2&gt;

&lt;p&gt;React Native allows capturing unhandled JS exceptions and forwarding them to Crashlytics:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;import &lt;span class="o"&gt;{&lt;/span&gt; setJSExceptionHandler &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'react-native-exception-handler'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import crashlytics from &lt;span class="s1"&gt;'@react-native-firebase/crashlytics'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

const errorHandler &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;error, isFatal&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  crashlytics&lt;span class="o"&gt;()&lt;/span&gt;.recordError&lt;span class="o"&gt;(&lt;/span&gt;error&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

setJSExceptionHandler&lt;span class="o"&gt;(&lt;/span&gt;errorHandler, &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  7. Monitoring &amp;amp; Analytics
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Go to Firebase Console → Crashlytics.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;View &lt;strong&gt;real-time crash reports&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Identify &lt;strong&gt;affected users&lt;/strong&gt;, &lt;strong&gt;device types&lt;/strong&gt;, &lt;strong&gt;OS versions&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Track errors by &lt;strong&gt;severity and frequency&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  8. Conclusion
&lt;/h2&gt;

&lt;p&gt;Integrating &lt;strong&gt;Firebase Crashlytics&lt;/strong&gt; in React Native is straightforward but highly valuable. It helps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Quickly identify and fix critical bugs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Improve app stability for real users.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Track both fatal crashes and handled exceptions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://rnfirebase.io/crashlytics/usage" rel="noopener noreferrer"&gt;React Native Firebase Crashlytics&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://firebase.google.com/docs/crashlytics" rel="noopener noreferrer"&gt;Firebase Crashlytics Guide&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;✍️ Written by &lt;a href="https://www.linkedin.com/in/dainyjose" rel="noopener noreferrer"&gt;&lt;strong&gt;Dainy Jose&lt;/strong&gt;&lt;/a&gt; — React Native Mobile Application Developer with 3+ years of experience building cross-platform mobile apps using &lt;strong&gt;React Native (Expo, TypeScript, Redux)&lt;/strong&gt;. &lt;br&gt;
Currently expanding backend knowledge through the &lt;strong&gt;MERN Stack (MongoDB, Express.js, React.js, Node.js)&lt;/strong&gt; to create more efficient, full-stack mobile experiences.&lt;/p&gt;

&lt;p&gt;💼 &lt;strong&gt;Tech Stack:&lt;/strong&gt; React Native · TypeScript · Redux · Expo · Firebase · Node.js · Express.js · MongoDB · REST API · JWT · Jest · Google Maps · Razorpay · PayU · Agile · SDLC · Git · Bitbucket · Jira &lt;/p&gt;

&lt;p&gt;📬 &lt;strong&gt;Connect with me&lt;/strong&gt;:&lt;br&gt;
🌐 &lt;a href="https://dainyjose.github.io/my-portfolio/" rel="noopener noreferrer"&gt;Portfolio&lt;/a&gt;&lt;br&gt;
🔗 &lt;a href="https://www.linkedin.com/in/dainyjose" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;br&gt;
💻 &lt;a href="https://github.com/dainyjose" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>firebase</category>
    </item>
    <item>
      <title>Real-Time Location Tracking &amp; Live Route Updates in React Native</title>
      <dc:creator>Dainy Jose</dc:creator>
      <pubDate>Sun, 07 Dec 2025 15:56:04 +0000</pubDate>
      <link>https://dev.to/dainyjose/real-time-location-tracking-live-route-updates-in-react-native-4g15</link>
      <guid>https://dev.to/dainyjose/real-time-location-tracking-live-route-updates-in-react-native-4g15</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://dev.to/dainyjose/showing-nearby-places-routes-in-react-native-maps-34b7"&gt;Part 3&lt;/a&gt; we explored how to show nearby places and draw routes.&lt;br&gt;
Now it’s time to go &lt;strong&gt;real-time&lt;/strong&gt; — tracking a moving user (or driver) on the map and updating the route live.&lt;/p&gt;

&lt;p&gt;We’ll use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;react-native-maps&lt;/strong&gt; → to display the route&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;expo-location&lt;/strong&gt; → to stream position updates&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;socket.io / API polling&lt;/strong&gt; → to broadcast position changes (optional for multi-user scenarios)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Step 1: Basic Setup
&lt;/h2&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;react-native-maps expo-location
npm &lt;span class="nb"&gt;install &lt;/span&gt;socket.io-client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 2: Watch the User’s Location Continuously
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;import React, &lt;span class="o"&gt;{&lt;/span&gt; useEffect, useState &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s2"&gt;"react"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import &lt;span class="o"&gt;{&lt;/span&gt; View, StyleSheet &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s2"&gt;"react-native"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import MapView, &lt;span class="o"&gt;{&lt;/span&gt; Marker, Polyline &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s2"&gt;"react-native-maps"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import &lt;span class="k"&gt;*&lt;/span&gt; as Location from &lt;span class="s2"&gt;"expo-location"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nb"&gt;export &lt;/span&gt;default &lt;span class="k"&gt;function &lt;/span&gt;LiveTrackingScreen&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  const &lt;span class="o"&gt;[&lt;/span&gt;region, setRegion] &lt;span class="o"&gt;=&lt;/span&gt; useState&amp;lt;any&amp;gt;&lt;span class="o"&gt;(&lt;/span&gt;null&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  const &lt;span class="o"&gt;[&lt;/span&gt;routeCoords, setRouteCoords] &lt;span class="o"&gt;=&lt;/span&gt; useState&amp;lt;any[]&amp;gt;&lt;span class="o"&gt;([])&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  useEffect&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;(&lt;/span&gt;async &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      const &lt;span class="o"&gt;{&lt;/span&gt; status &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; await Location.requestForegroundPermissionsAsync&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;status &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="s2"&gt;"granted"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      const loc &lt;span class="o"&gt;=&lt;/span&gt; await Location.getCurrentPositionAsync&lt;span class="o"&gt;({})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      const &lt;span class="o"&gt;{&lt;/span&gt; latitude, longitude &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; loc.coords&lt;span class="p"&gt;;&lt;/span&gt;

      setRegion&lt;span class="o"&gt;({&lt;/span&gt;
        latitude,
        longitude,
        latitudeDelta: 0.01,
        longitudeDelta: 0.01,
      &lt;span class="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      const sub &lt;span class="o"&gt;=&lt;/span&gt; await Location.watchPositionAsync&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;{&lt;/span&gt;
          accuracy: Location.Accuracy.Highest,
          timeInterval: 3000,
          distanceInterval: 5, // update every 5 m
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="o"&gt;(&lt;/span&gt;pos&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
          const &lt;span class="o"&gt;{&lt;/span&gt; latitude, longitude &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; pos.coords&lt;span class="p"&gt;;&lt;/span&gt;
          setRouteCoords&lt;span class="o"&gt;((&lt;/span&gt;prev&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;...prev, &lt;span class="o"&gt;{&lt;/span&gt; latitude, longitude &lt;span class="o"&gt;}])&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          setRegion&lt;span class="o"&gt;((&lt;/span&gt;r&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;({&lt;/span&gt; ...r, latitude, longitude &lt;span class="o"&gt;}))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; sub.remove&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;})()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;, &lt;span class="o"&gt;[])&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;region&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return &lt;/span&gt;null&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;
    &amp;lt;View &lt;span class="nv"&gt;style&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;styles.container&lt;span class="o"&gt;}&amp;gt;&lt;/span&gt;
      &amp;lt;MapView &lt;span class="nv"&gt;style&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;styles.map&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;region&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;region&lt;span class="o"&gt;}&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;{&lt;/span&gt;routeCoords.length &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 0 &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;
          &amp;lt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &amp;lt;Polyline &lt;span class="nv"&gt;coordinates&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;routeCoords&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;strokeWidth&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;4&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;strokeColor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"#007AFF"&lt;/span&gt; /&amp;gt;
            &amp;lt;Marker &lt;span class="nv"&gt;coordinate&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;routeCoords[routeCoords.length - 1]&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"You"&lt;/span&gt; /&amp;gt;
          &amp;lt;/&amp;gt;
        &lt;span class="o"&gt;)}&lt;/span&gt;
      &amp;lt;/MapView&amp;gt;
    &amp;lt;/View&amp;gt;
  &lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

const styles &lt;span class="o"&gt;=&lt;/span&gt; StyleSheet.create&lt;span class="o"&gt;({&lt;/span&gt;
  container: &lt;span class="o"&gt;{&lt;/span&gt; flex: 1 &lt;span class="o"&gt;}&lt;/span&gt;,
  map: &lt;span class="o"&gt;{&lt;/span&gt; flex: 1 &lt;span class="o"&gt;}&lt;/span&gt;,
&lt;span class="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  What this does:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Requests location permission.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Watches position every few seconds/meters.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Draws a live polyline trail of movement.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Step 3: (Optional) Share Location in Real Time
&lt;/h2&gt;

&lt;p&gt;To show another user’s movement (for example, a delivery partner), send location updates through a backend socket:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;import io from &lt;span class="s2"&gt;"socket.io-client"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
const socket &lt;span class="o"&gt;=&lt;/span&gt; io&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"https://your-backend-url.com"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

useEffect&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;routeCoords.length&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  const last &lt;span class="o"&gt;=&lt;/span&gt; routeCoords[routeCoords.length - 1]&lt;span class="p"&gt;;&lt;/span&gt;
  socket.emit&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"location:update"&lt;/span&gt;, last&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;, &lt;span class="o"&gt;[&lt;/span&gt;routeCoords]&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the receiver side:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;socket.on&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"location:update"&lt;/span&gt;, &lt;span class="o"&gt;(&lt;/span&gt;coords&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  setDriverLocation&lt;span class="o"&gt;(&lt;/span&gt;coords&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll then render &lt;code&gt;driverLocation&lt;/code&gt; as a marker that updates instantly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Smooth Marker Animation
&lt;/h2&gt;

&lt;p&gt;For smoother UX, use &lt;strong&gt;react-native-maps-animated-marker&lt;/strong&gt; or Animated API to interpolate coordinates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;// pseudo
Animated.timing&lt;span class="o"&gt;(&lt;/span&gt;markerRef, &lt;span class="o"&gt;{&lt;/span&gt;
  toValue: new AnimatedRegion&lt;span class="o"&gt;({&lt;/span&gt; latitude, longitude &lt;span class="o"&gt;})&lt;/span&gt;,
  useNativeDriver: &lt;span class="nb"&gt;false&lt;/span&gt;,
&lt;span class="o"&gt;})&lt;/span&gt;.start&lt;span class="o"&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 creates a fluid moving-car effect rather than jumpy updates.&lt;/p&gt;

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

&lt;p&gt;And that’s it — you’ve built a real-time location tracker with live route updates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key takeaways:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use &lt;code&gt;watchPositionAsync&lt;/code&gt; for continuous tracking.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Store coordinates to visualize movement with polylines.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Integrate sockets for multi-user real-time sharing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Animate markers for smooth transitions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;✍️ Written by &lt;a href="https://www.linkedin.com/in/dainyjose" rel="noopener noreferrer"&gt;&lt;strong&gt;Dainy Jose&lt;/strong&gt;&lt;/a&gt; — React Native Mobile Application Developer with 3+ years of experience building cross-platform mobile apps using &lt;strong&gt;React Native (Expo, TypeScript, Redux)&lt;/strong&gt;. &lt;br&gt;
Currently expanding backend knowledge through the &lt;strong&gt;MERN Stack (MongoDB, Express.js, React.js, Node.js)&lt;/strong&gt; to create more efficient, full-stack mobile experiences.&lt;/p&gt;

&lt;p&gt;💼 &lt;strong&gt;Tech Stack:&lt;/strong&gt; React Native · TypeScript · Redux · Expo · Firebase · Node.js · Express.js · MongoDB · REST API · JWT · Jest · Google Maps · Razorpay · PayU · Agile · SDLC · Git · Bitbucket · Jira &lt;/p&gt;

&lt;p&gt;📬 &lt;strong&gt;Connect with me&lt;/strong&gt;:&lt;br&gt;
🌐 &lt;a href="https://dainyjose.github.io/my-portfolio/" rel="noopener noreferrer"&gt;Portfolio&lt;/a&gt;&lt;br&gt;
🔗 &lt;a href="https://www.linkedin.com/in/dainyjose" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;br&gt;
💻 &lt;a href="https://github.com/dainyjose" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>mobile</category>
      <category>development</category>
    </item>
    <item>
      <title>Showing Nearby Places &amp; Routes in React Native Maps</title>
      <dc:creator>Dainy Jose</dc:creator>
      <pubDate>Mon, 01 Dec 2025 02:18:54 +0000</pubDate>
      <link>https://dev.to/dainyjose/showing-nearby-places-routes-in-react-native-maps-34b7</link>
      <guid>https://dev.to/dainyjose/showing-nearby-places-routes-in-react-native-maps-34b7</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://dev.to/dainyjose/seamless-map-integration-in-react-native-a-complete-guide-29o7"&gt;Part 1&lt;/a&gt; we integrated maps into React Native, and in &lt;a href="https://dev.to/dainyjose/building-a-location-picker-in-react-native-maps-with-draggable-marker-address-lookup-1d00"&gt;Part 2&lt;/a&gt; we built a location picker.&lt;/p&gt;

&lt;p&gt;Now, let’s make it smarter — by showing &lt;strong&gt;nearby places&lt;/strong&gt; (like restaurants or stores) and drawing &lt;strong&gt;routes&lt;/strong&gt; between two points.&lt;/p&gt;

&lt;p&gt;We’ll use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;react-native-maps&lt;/strong&gt; for rendering&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Google Places API&lt;/strong&gt; for nearby results&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Google Directions API&lt;/strong&gt; for routing&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 1: Enable Required APIs
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Go to your &lt;a href="https://console.cloud.google.com/" rel="noopener noreferrer"&gt;Google Cloud Console&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enable:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Maps SDK for Android / iOS&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Places API&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Directions API&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Create or reuse an API key and restrict it to your app’s bundle ID or SHA-1.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 2: Basic Setup
&lt;/h3&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;react-native-maps expo-location
npm &lt;span class="nb"&gt;install &lt;/span&gt;axios
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Fetch Nearby Places
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;import React, &lt;span class="o"&gt;{&lt;/span&gt; useEffect, useState &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'react'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import &lt;span class="o"&gt;{&lt;/span&gt; View, StyleSheet, Text &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'react-native'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import MapView, &lt;span class="o"&gt;{&lt;/span&gt; Marker, Polyline &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'react-native-maps'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import &lt;span class="k"&gt;*&lt;/span&gt; as Location from &lt;span class="s1"&gt;'expo-location'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import axios from &lt;span class="s1"&gt;'axios'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

const GOOGLE_API_KEY &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'YOUR_GOOGLE_MAPS_API_KEY'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nb"&gt;export &lt;/span&gt;default &lt;span class="k"&gt;function &lt;/span&gt;NearbyMap&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  const &lt;span class="o"&gt;[&lt;/span&gt;region, setRegion] &lt;span class="o"&gt;=&lt;/span&gt; useState&amp;lt;any&amp;gt;&lt;span class="o"&gt;(&lt;/span&gt;null&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  const &lt;span class="o"&gt;[&lt;/span&gt;places, setPlaces] &lt;span class="o"&gt;=&lt;/span&gt; useState&amp;lt;any[]&amp;gt;&lt;span class="o"&gt;([])&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  const &lt;span class="o"&gt;[&lt;/span&gt;routeCoords, setRouteCoords] &lt;span class="o"&gt;=&lt;/span&gt; useState&amp;lt;any[]&amp;gt;&lt;span class="o"&gt;([])&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  useEffect&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;(&lt;/span&gt;async &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      const &lt;span class="o"&gt;{&lt;/span&gt; status &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; await Location.requestForegroundPermissionsAsync&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;status &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="s1"&gt;'granted'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      const pos &lt;span class="o"&gt;=&lt;/span&gt; await Location.getCurrentPositionAsync&lt;span class="o"&gt;({})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      const &lt;span class="o"&gt;{&lt;/span&gt; latitude, longitude &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; pos.coords&lt;span class="p"&gt;;&lt;/span&gt;
      setRegion&lt;span class="o"&gt;({&lt;/span&gt;
        latitude,
        longitude,
        latitudeDelta: 0.01,
        longitudeDelta: 0.01,
      &lt;span class="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      fetchNearby&lt;span class="o"&gt;(&lt;/span&gt;latitude, longitude&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;})()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;, &lt;span class="o"&gt;[])&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  const fetchNearby &lt;span class="o"&gt;=&lt;/span&gt; async &lt;span class="o"&gt;(&lt;/span&gt;lat: number, lng: number&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    const url &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;https://maps.googleapis.com/maps/api/place/nearbysearch/json?location&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;lat&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;,&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;lng&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&amp;amp;radius&lt;span class="o"&gt;=&lt;/span&gt;1000&amp;amp;type&lt;span class="o"&gt;=&lt;/span&gt;restaurant&amp;amp;key&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GOOGLE_API_KEY&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    const &lt;span class="o"&gt;{&lt;/span&gt; data &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; await axios.get&lt;span class="o"&gt;(&lt;/span&gt;url&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    setPlaces&lt;span class="o"&gt;(&lt;/span&gt;data.results&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  const drawRoute &lt;span class="o"&gt;=&lt;/span&gt; async &lt;span class="o"&gt;(&lt;/span&gt;destLat: number, destLng: number&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    const url &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;https://maps.googleapis.com/maps/api/directions/json?origin&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;region&lt;/span&gt;&lt;span class="p"&gt;.latitude&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;,&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;region&lt;/span&gt;&lt;span class="p"&gt;.longitude&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&amp;amp;destination&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;destLat&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;,&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;destLng&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&amp;amp;key&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GOOGLE_API_KEY&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    const &lt;span class="o"&gt;{&lt;/span&gt; data &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; await axios.get&lt;span class="o"&gt;(&lt;/span&gt;url&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    const points &lt;span class="o"&gt;=&lt;/span&gt; decode&lt;span class="o"&gt;(&lt;/span&gt;data.routes[0].overview_polyline.points&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    setRouteCoords&lt;span class="o"&gt;(&lt;/span&gt;points&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  // Polyline decoding helper
  const decode &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;t: string&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;let &lt;/span&gt;points &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;let &lt;/span&gt;step &lt;span class="o"&gt;=&lt;/span&gt; 0, lat &lt;span class="o"&gt;=&lt;/span&gt; 0, lng &lt;span class="o"&gt;=&lt;/span&gt; 0&lt;span class="p"&gt;;&lt;/span&gt; step &amp;lt; t.length&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="nb"&gt;let &lt;/span&gt;b, &lt;span class="nb"&gt;shift&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 0, result &lt;span class="o"&gt;=&lt;/span&gt; 0&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; b &lt;span class="o"&gt;=&lt;/span&gt; t.charCodeAt&lt;span class="o"&gt;(&lt;/span&gt;step++&lt;span class="o"&gt;)&lt;/span&gt; - 63&lt;span class="p"&gt;;&lt;/span&gt; result |&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;b &amp;amp; 31&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;shift&lt;/span&gt;&lt;span class="sh"&gt;; shift += 5; } while (b &amp;gt;= 32);
      lat += (result &amp;amp; 1) ? ~(result &amp;gt;&amp;gt; 1) : (result &amp;gt;&amp;gt; 1);
      shift = result = 0;
      do { b = t.charCodeAt(step++) - 63; result |= (b &amp;amp; 31) &amp;lt;&amp;lt; shift; shift += 5; } while (b &amp;gt;= 32);
      lng += (result &amp;amp; 1) ? ~(result &amp;gt;&amp;gt; 1) : (result &amp;gt;&amp;gt; 1);
      points.push({ latitude: lat / 1e5, longitude: lng / 1e5 });
    }
    return points;
  };

  if (!region) return &amp;lt;Text&amp;gt;Loading map...&amp;lt;/Text&amp;gt;;

  return (
    &amp;lt;View style={styles.container}&amp;gt;
      &amp;lt;MapView style={styles.map} region={region}&amp;gt;
        {places.map((p, i) =&amp;gt; (
          &amp;lt;Marker
            key={i}
            coordinate={{
              latitude: p.geometry.location.lat,
              longitude: p.geometry.location.lng,
            }}
            title={p.name}
            onPress={() =&amp;gt; drawRoute(p.geometry.location.lat, p.geometry.location.lng)}
          /&amp;gt;
        ))}
        {routeCoords.length &amp;gt; 0 &amp;amp;&amp;amp; (
          &amp;lt;Polyline coordinates={routeCoords} strokeWidth={4} strokeColor="#007AFF" /&amp;gt;
        )}
      &amp;lt;/MapView&amp;gt;
    &amp;lt;/View&amp;gt;
  );
}

const styles = StyleSheet.create({
  container: { flex: 1 },
  map: { flex: 1 },
});
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What this does&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Detects your location&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fetches nearby restaurants within 1 km&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Draws a route when you tap a marker&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 4: Optimize UX
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use a bottom sheet to show place details.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add filters for different types (&lt;code&gt;cafe&lt;/code&gt;, &lt;code&gt;hospital&lt;/code&gt;, etc.).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cache responses for smoother panning.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;With just a few APIs, you’ve now added &lt;strong&gt;intelligent location awareness&lt;/strong&gt; to your app — users can view nearby places and get directions instantly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key takeaways&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Always restrict your API key.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Decode Google’s polyline for routes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Combine Places + Directions APIs for real-time navigation features.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What’s Next
&lt;/h3&gt;

&lt;p&gt;Next, I’ll explore “Building Real-Time Location Tracking in React Native” — ideal for delivery or event apps.&lt;/p&gt;




&lt;p&gt;✍️ Written by &lt;a href="https://www.linkedin.com/in/dainyjose" rel="noopener noreferrer"&gt;&lt;strong&gt;Dainy Jose&lt;/strong&gt;&lt;/a&gt; — React Native Mobile Application Developer with 3+ years of experience building cross-platform mobile apps using &lt;strong&gt;React Native (Expo, TypeScript, Redux)&lt;/strong&gt;. &lt;br&gt;
Currently expanding backend knowledge through the &lt;strong&gt;MERN Stack (MongoDB, Express.js, React.js, Node.js)&lt;/strong&gt; to create more efficient, full-stack mobile experiences.&lt;/p&gt;

&lt;p&gt;💼 &lt;strong&gt;Tech Stack:&lt;/strong&gt; React Native · TypeScript · Redux · Expo · Firebase · Node.js · Express.js · MongoDB · REST API · JWT · Jest · Google Maps · Razorpay · PayU · Agile · SDLC · Git · Bitbucket · Jira &lt;/p&gt;

&lt;p&gt;📬 &lt;strong&gt;Connect with me&lt;/strong&gt;:&lt;br&gt;
🌐 &lt;a href="https://dainyjose.github.io/my-portfolio/" rel="noopener noreferrer"&gt;Portfolio&lt;/a&gt;&lt;br&gt;
🔗 &lt;a href="https://www.linkedin.com/in/dainyjose" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;br&gt;
💻 &lt;a href="https://github.com/dainyjose" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>map</category>
      <category>googlemapsapi</category>
    </item>
    <item>
      <title>Building a Location Picker in React Native Maps (with Draggable Marker &amp; Address Lookup)</title>
      <dc:creator>Dainy Jose</dc:creator>
      <pubDate>Sun, 23 Nov 2025 17:59:06 +0000</pubDate>
      <link>https://dev.to/dainyjose/building-a-location-picker-in-react-native-maps-with-draggable-marker-address-lookup-1d00</link>
      <guid>https://dev.to/dainyjose/building-a-location-picker-in-react-native-maps-with-draggable-marker-address-lookup-1d00</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://dev.to/dainyjose/seamless-map-integration-in-react-native-a-complete-guide-29o7"&gt;my previous post&lt;/a&gt;, I covered how to integrate Google Maps and display the user’s live location.&lt;/p&gt;

&lt;p&gt;Now let’s take it one step further — by creating a &lt;strong&gt;location picker&lt;/strong&gt; where users can drag a marker or move the map to select an address. This feature is perfect for checkout pages, delivery address setup, or event creation screens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Setup
&lt;/h2&gt;

&lt;p&gt;We’ll continue using:&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;react-native-maps expo-location
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Optional (for reverse geocoding):&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-location
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Display the Map with a Draggable Marker
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;import React, &lt;span class="o"&gt;{&lt;/span&gt; useState, useEffect &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'react'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import &lt;span class="o"&gt;{&lt;/span&gt; View, Text, StyleSheet &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'react-native'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import MapView, &lt;span class="o"&gt;{&lt;/span&gt; Marker &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'react-native-maps'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import &lt;span class="k"&gt;*&lt;/span&gt; as Location from &lt;span class="s1"&gt;'expo-location'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nb"&gt;export &lt;/span&gt;default &lt;span class="k"&gt;function &lt;/span&gt;LocationPicker&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  const &lt;span class="o"&gt;[&lt;/span&gt;region, setRegion] &lt;span class="o"&gt;=&lt;/span&gt; useState&lt;span class="o"&gt;(&lt;/span&gt;null&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  const &lt;span class="o"&gt;[&lt;/span&gt;address, setAddress] &lt;span class="o"&gt;=&lt;/span&gt; useState&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  useEffect&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;(&lt;/span&gt;async &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      const &lt;span class="o"&gt;{&lt;/span&gt; status &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; await Location.requestForegroundPermissionsAsync&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;status &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="s1"&gt;'granted'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      const current &lt;span class="o"&gt;=&lt;/span&gt; await Location.getCurrentPositionAsync&lt;span class="o"&gt;({})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      const &lt;span class="o"&gt;{&lt;/span&gt; latitude, longitude &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; current.coords&lt;span class="p"&gt;;&lt;/span&gt;
      setRegion&lt;span class="o"&gt;({&lt;/span&gt;
        latitude,
        longitude,
        latitudeDelta: 0.01,
        longitudeDelta: 0.01,
      &lt;span class="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      getAddress&lt;span class="o"&gt;(&lt;/span&gt;latitude, longitude&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;})()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;, &lt;span class="o"&gt;[])&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  const getAddress &lt;span class="o"&gt;=&lt;/span&gt; async &lt;span class="o"&gt;(&lt;/span&gt;lat: number, lng: number&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    const &lt;span class="o"&gt;[&lt;/span&gt;place] &lt;span class="o"&gt;=&lt;/span&gt; await Location.reverseGeocodeAsync&lt;span class="o"&gt;({&lt;/span&gt; latitude: lat, longitude: lng &lt;span class="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;place&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      setAddress&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;place&lt;/span&gt;&lt;span class="p"&gt;.name || &lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;, &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;place&lt;/span&gt;&lt;span class="p"&gt;.city || &lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;, &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;place&lt;/span&gt;&lt;span class="p"&gt;.region || &lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  const onMarkerDragEnd &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;e: any&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    const &lt;span class="o"&gt;{&lt;/span&gt; latitude, longitude &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; e.nativeEvent.coordinate&lt;span class="p"&gt;;&lt;/span&gt;
    setRegion&lt;span class="o"&gt;({&lt;/span&gt; ...region, latitude, longitude &lt;span class="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    getAddress&lt;span class="o"&gt;(&lt;/span&gt;latitude, longitude&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;region&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &amp;lt;Text&amp;gt;Loading map...&amp;lt;/Text&amp;gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;
    &amp;lt;View &lt;span class="nv"&gt;style&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;styles.container&lt;span class="o"&gt;}&amp;gt;&lt;/span&gt;
      &amp;lt;MapView &lt;span class="nv"&gt;style&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;styles.map&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;region&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;region&lt;span class="o"&gt;}&amp;gt;&lt;/span&gt;
        &amp;lt;Marker
          &lt;span class="nv"&gt;coordinate&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;region&lt;span class="o"&gt;}&lt;/span&gt;
          draggable
          &lt;span class="nv"&gt;onDragEnd&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;onMarkerDragEnd&lt;span class="o"&gt;}&lt;/span&gt;
          &lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Selected Location"&lt;/span&gt;
        /&amp;gt;
      &amp;lt;/MapView&amp;gt;
      &amp;lt;View &lt;span class="nv"&gt;style&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;styles.infoBox&lt;span class="o"&gt;}&amp;gt;&lt;/span&gt;
        &amp;lt;Text &lt;span class="nv"&gt;style&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;styles.label&lt;span class="o"&gt;}&amp;gt;&lt;/span&gt;Selected Address:&amp;lt;/Text&amp;gt;
        &amp;lt;Text &lt;span class="nv"&gt;style&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;styles.address&lt;span class="o"&gt;}&amp;gt;{&lt;/span&gt;address &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s1"&gt;'Move marker to select'&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&amp;lt;/Text&amp;gt;
      &amp;lt;/View&amp;gt;
    &amp;lt;/View&amp;gt;
  &lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

const styles &lt;span class="o"&gt;=&lt;/span&gt; StyleSheet.create&lt;span class="o"&gt;({&lt;/span&gt;
  container: &lt;span class="o"&gt;{&lt;/span&gt; flex: 1 &lt;span class="o"&gt;}&lt;/span&gt;,
  map: &lt;span class="o"&gt;{&lt;/span&gt; flex: 1 &lt;span class="o"&gt;}&lt;/span&gt;,
  infoBox: &lt;span class="o"&gt;{&lt;/span&gt;
    position: &lt;span class="s1"&gt;'absolute'&lt;/span&gt;,
    bottom: 40,
    left: 20,
    right: 20,
    backgroundColor: &lt;span class="s1"&gt;'#fff'&lt;/span&gt;,
    borderRadius: 12,
    padding: 10,
    shadowColor: &lt;span class="s1"&gt;'#000'&lt;/span&gt;,
    shadowOpacity: 0.1,
    shadowRadius: 6,
  &lt;span class="o"&gt;}&lt;/span&gt;,
  label: &lt;span class="o"&gt;{&lt;/span&gt; fontWeight: &lt;span class="s1"&gt;'600'&lt;/span&gt;, marginBottom: 4 &lt;span class="o"&gt;}&lt;/span&gt;,
  address: &lt;span class="o"&gt;{&lt;/span&gt; fontSize: 14, color: &lt;span class="s1"&gt;'#333'&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;,
&lt;span class="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What this does:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Displays your current location.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lets you &lt;strong&gt;drag the marker&lt;/strong&gt; to a new position.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Updates the address in real time.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 3: Use Map Pan Instead of Marker Drag
&lt;/h2&gt;

&lt;p&gt;If you prefer to &lt;strong&gt;keep the marker fixed&lt;/strong&gt; and move the map instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&amp;lt;MapView
  &lt;span class="nv"&gt;style&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;styles.map&lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="nv"&gt;region&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;region&lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="nv"&gt;onRegionChangeComplete&lt;/span&gt;&lt;span class="o"&gt;={(&lt;/span&gt;r&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    setRegion&lt;span class="o"&gt;(&lt;/span&gt;r&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    getAddress&lt;span class="o"&gt;(&lt;/span&gt;r.latitude, r.longitude&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}}&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &amp;lt;Marker &lt;span class="nv"&gt;coordinate&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;region&lt;span class="o"&gt;}&lt;/span&gt; /&amp;gt;
&amp;lt;/MapView&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This feels more natural for UX — the marker stays centered while the user pans the map.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Save the Selected Location
&lt;/h2&gt;

&lt;p&gt;Once the user confirms the spot, send it back to your backend or state management:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&amp;lt;Button
  &lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Confirm Location"&lt;/span&gt;
  &lt;span class="nv"&gt;onPress&lt;/span&gt;&lt;span class="o"&gt;={()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; console.log&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Saved location:'&lt;/span&gt;, region, address&lt;span class="o"&gt;)}&lt;/span&gt;
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;And that’s it! You’ve now built a fully functional location picker in React Native using &lt;code&gt;react-native-maps&lt;/code&gt; and Expo Location.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Takeaways:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Always handle permissions before rendering the map.&lt;/p&gt;

&lt;p&gt;Use reverse geocoding to get human-readable addresses.&lt;/p&gt;

&lt;p&gt;For better UX, fix the marker and move the map instead of dragging.&lt;/p&gt;

&lt;p&gt;🔗 Next Up&lt;/p&gt;

&lt;p&gt;In my next post, I’ll explore how to show nearby places and routes using Google Maps APIs in React Native. Stay tuned!&lt;/p&gt;




&lt;p&gt;✍️ Written by &lt;a href="https://www.linkedin.com/in/dainyjose" rel="noopener noreferrer"&gt;&lt;strong&gt;Dainy Jose&lt;/strong&gt;&lt;/a&gt; — React Native Mobile Application Developer with 3+ years of experience building cross-platform mobile apps using &lt;strong&gt;React Native (Expo, TypeScript, Redux)&lt;/strong&gt;. &lt;br&gt;
Currently expanding backend knowledge through the &lt;strong&gt;MERN Stack (MongoDB, Express.js, React.js, Node.js)&lt;/strong&gt; to create more efficient, full-stack mobile experiences.&lt;/p&gt;

&lt;p&gt;💼 &lt;strong&gt;Tech Stack:&lt;/strong&gt; React Native · TypeScript · Redux · Expo · Firebase · Node.js · Express.js · MongoDB · REST API · JWT · Jest · Google Maps · Razorpay · PayU · Agile · SDLC · Git · Bitbucket · Jira &lt;/p&gt;

&lt;p&gt;📬 &lt;strong&gt;Connect with me&lt;/strong&gt;:&lt;br&gt;
🌐 &lt;a href="https://dainyjose.github.io/my-portfolio/" rel="noopener noreferrer"&gt;Portfolio&lt;/a&gt;&lt;br&gt;
🔗 &lt;a href="https://www.linkedin.com/in/dainyjose" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;br&gt;
💻 &lt;a href="https://github.com/dainyjose" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>map</category>
      <category>mobile</category>
      <category>development</category>
    </item>
    <item>
      <title>Seamless Map Integration in React Native: A Complete Guide</title>
      <dc:creator>Dainy Jose</dc:creator>
      <pubDate>Sun, 16 Nov 2025 10:14:36 +0000</pubDate>
      <link>https://dev.to/dainyjose/seamless-map-integration-in-react-native-a-complete-guide-29o7</link>
      <guid>https://dev.to/dainyjose/seamless-map-integration-in-react-native-a-complete-guide-29o7</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Integrating maps into a React Native app sounds simple — until you face platform-specific quirks, location permission issues, and crashes (especially on Android).&lt;/p&gt;

&lt;p&gt;In this post, I’ll walk you through how I integrated &lt;strong&gt;Google Maps&lt;/strong&gt; into my React Native app using the &lt;strong&gt;Expo Bare Workflow&lt;/strong&gt;, including handling permissions, displaying the user’s live location, and fixing common pitfalls like Android crashes when using &lt;code&gt;showsUserLocation&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Setting Up the Map
&lt;/h3&gt;

&lt;p&gt;If you’re using Expo (Bare or Managed), the easiest way to start is with:&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;react-native-maps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, import the component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;import MapView, &lt;span class="o"&gt;{&lt;/span&gt; Marker &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'react-native-maps'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import &lt;span class="o"&gt;{&lt;/span&gt; StyleSheet, View &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'react-native'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


Render a simple map:

&lt;span class="nb"&gt;export &lt;/span&gt;default &lt;span class="k"&gt;function &lt;/span&gt;MapScreen&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;
    &amp;lt;View &lt;span class="nv"&gt;style&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;styles.container&lt;span class="o"&gt;}&amp;gt;&lt;/span&gt;
      &amp;lt;MapView
        &lt;span class="nv"&gt;style&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;styles.map&lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="nv"&gt;initialRegion&lt;/span&gt;&lt;span class="o"&gt;={{&lt;/span&gt;
          latitude: 37.78825,
          longitude: &lt;span class="nt"&gt;-122&lt;/span&gt;.4324,
          latitudeDelta: 0.0922,
          longitudeDelta: 0.0421,
        &lt;span class="o"&gt;}}&lt;/span&gt;
      /&amp;gt;
    &amp;lt;/View&amp;gt;
  &lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

const styles &lt;span class="o"&gt;=&lt;/span&gt; StyleSheet.create&lt;span class="o"&gt;({&lt;/span&gt;
  container: &lt;span class="o"&gt;{&lt;/span&gt; flex: 1 &lt;span class="o"&gt;}&lt;/span&gt;,
  map: &lt;span class="o"&gt;{&lt;/span&gt; width: &lt;span class="s1"&gt;'100%'&lt;/span&gt;, height: &lt;span class="s1"&gt;'100%'&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;,
&lt;span class="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s your base map ready.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Request Location Permissions
&lt;/h3&gt;

&lt;p&gt;To show the user’s live location, install Expo Location:&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-location
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then request permission before displaying the map:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;import &lt;span class="k"&gt;*&lt;/span&gt; as Location from &lt;span class="s1"&gt;'expo-location'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import &lt;span class="o"&gt;{&lt;/span&gt; useEffect, useState &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'react'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

const &lt;span class="o"&gt;[&lt;/span&gt;location, setLocation] &lt;span class="o"&gt;=&lt;/span&gt; useState&lt;span class="o"&gt;(&lt;/span&gt;null&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

useEffect&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;(&lt;/span&gt;async &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;let&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; status &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; await Location.requestForegroundPermissionsAsync&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;status &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="s1"&gt;'granted'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      console.warn&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Permission denied'&lt;/span&gt;&lt;span class="o"&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;}&lt;/span&gt;

    &lt;span class="nb"&gt;let &lt;/span&gt;current &lt;span class="o"&gt;=&lt;/span&gt; await Location.getCurrentPositionAsync&lt;span class="o"&gt;({})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    setLocation&lt;span class="o"&gt;(&lt;/span&gt;current.coords&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;})()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;, &lt;span class="o"&gt;[])&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Display User’s Current Location
&lt;/h3&gt;

&lt;p&gt;Once permission is granted, set your map’s region dynamically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&amp;lt;MapView
  &lt;span class="nv"&gt;style&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;styles.map&lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="nv"&gt;region&lt;/span&gt;&lt;span class="o"&gt;={{&lt;/span&gt;
    latitude: location?.latitude &lt;span class="o"&gt;||&lt;/span&gt; 37.78825,
    longitude: location?.longitude &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nt"&gt;-122&lt;/span&gt;.4324,
    latitudeDelta: 0.01,
    longitudeDelta: 0.01,
  &lt;span class="o"&gt;}}&lt;/span&gt;
  &lt;span class="nv"&gt;showsUserLocation&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="nv"&gt;showsMyLocationButton&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Fix Android Crash with showsUserLocation
&lt;/h3&gt;

&lt;p&gt;If you notice your &lt;strong&gt;app crashes on Android&lt;/strong&gt; when &lt;code&gt;showsUserLocation={true}&lt;/code&gt;, it’s usually because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The location permission isn’t granted before rendering the map, or&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The native module initialization fails due to race conditions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Fix:
&lt;/h3&gt;

&lt;p&gt;Wrap your &lt;code&gt;&amp;lt;MapView /&amp;gt;&lt;/code&gt; inside a condition that ensures &lt;code&gt;location&lt;/code&gt; is loaded first:&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="o"&gt;{&lt;/span&gt;location &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;
  &amp;lt;MapView
    &lt;span class="nv"&gt;style&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;styles.map&lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="nv"&gt;showsUserLocation&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="nv"&gt;region&lt;/span&gt;&lt;span class="o"&gt;={{&lt;/span&gt;
      latitude: location.latitude,
      longitude: location.longitude,
      latitudeDelta: 0.01,
      longitudeDelta: 0.01,
    &lt;span class="o"&gt;}}&lt;/span&gt;
  /&amp;gt;
&lt;span class="o"&gt;)}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This small conditional check prevents the crash on Android and ensures the map renders only after location access.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Adding Markers
&lt;/h3&gt;

&lt;p&gt;You can easily add markers for points of interest:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&amp;lt;Marker
  &lt;span class="nv"&gt;coordinate&lt;/span&gt;&lt;span class="o"&gt;={{&lt;/span&gt;
    latitude: 37.78825,
    longitude: &lt;span class="nt"&gt;-122&lt;/span&gt;.4324,
  &lt;span class="o"&gt;}}&lt;/span&gt;
  &lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"My Favorite Spot"&lt;/span&gt;
  &lt;span class="nv"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"This is where I test map features."&lt;/span&gt;
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can even loop through API data to dynamically render multiple markers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bonus: Custom Map Styling
&lt;/h3&gt;

&lt;p&gt;You can use Google Map styles to match your app’s branding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;const customMapStyle &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
  &lt;span class="o"&gt;{&lt;/span&gt;
    elementType: &lt;span class="s1"&gt;'geometry'&lt;/span&gt;,
    stylers: &lt;span class="o"&gt;[{&lt;/span&gt; color: &lt;span class="s1"&gt;'#212121'&lt;/span&gt; &lt;span class="o"&gt;}]&lt;/span&gt;,
  &lt;span class="o"&gt;}&lt;/span&gt;,
  &lt;span class="o"&gt;{&lt;/span&gt;
    elementType: &lt;span class="s1"&gt;'labels.text.fill'&lt;/span&gt;,
    stylers: &lt;span class="o"&gt;[{&lt;/span&gt; color: &lt;span class="s1"&gt;'#757575'&lt;/span&gt; &lt;span class="o"&gt;}]&lt;/span&gt;,
  &lt;span class="o"&gt;}&lt;/span&gt;,
&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&amp;lt;MapView
  &lt;span class="nv"&gt;customMapStyle&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;customMapStyle&lt;span class="o"&gt;}&lt;/span&gt;
  ...
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Map integration in React Native can be tricky — especially when balancing permission flow and native dependencies — but once set up properly, it unlocks powerful location-based features for your users.&lt;/p&gt;

&lt;p&gt;The key takeaways:&lt;br&gt;
✅ Always request permissions before rendering the map&lt;/p&gt;

&lt;p&gt;✅ Handle &lt;code&gt;showsUserLocation&lt;/code&gt; carefully on Android&lt;/p&gt;

&lt;p&gt;✅ Use dynamic regions for better UX&lt;/p&gt;

&lt;p&gt;✅ Customize your map style to match your app&lt;/p&gt;




&lt;h3&gt;
  
  
  Coming Up Next
&lt;/h3&gt;

&lt;p&gt;In my next post, I’ll cover “Building a Location Picker with React Native Maps” — where users can drag the map to set an address or store location.&lt;/p&gt;




&lt;p&gt;✍️ Written by &lt;a href="https://www.linkedin.com/in/dainyjose" rel="noopener noreferrer"&gt;&lt;strong&gt;Dainy Jose&lt;/strong&gt;&lt;/a&gt; — React Native Mobile Application Developer with 3+ years of experience building cross-platform mobile apps using &lt;strong&gt;React Native (Expo, TypeScript, Redux)&lt;/strong&gt;. &lt;br&gt;
Currently expanding backend knowledge through the &lt;strong&gt;MERN Stack (MongoDB, Express.js, React.js, Node.js)&lt;/strong&gt; to create more efficient, full-stack mobile experiences.&lt;/p&gt;

&lt;p&gt;💼 &lt;strong&gt;Tech Stack:&lt;/strong&gt; React Native · TypeScript · Redux · Expo · Firebase · Node.js · Express.js · MongoDB · REST API · JWT · Jest · Google Maps · Razorpay · PayU · Agile · SDLC · Git · Bitbucket · Jira &lt;/p&gt;

&lt;p&gt;📬 &lt;strong&gt;Connect with me&lt;/strong&gt;:&lt;br&gt;
🌐 &lt;a href="https://dainyjose.github.io/my-portfolio/" rel="noopener noreferrer"&gt;Portfolio&lt;/a&gt;&lt;br&gt;
🔗 &lt;a href="https://www.linkedin.com/in/dainyjose" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;br&gt;
💻 &lt;a href="https://github.com/dainyjose" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>map</category>
      <category>android</category>
      <category>ios</category>
    </item>
    <item>
      <title>Step-by-Step Guide to Upgrading Your React Native Expo Project</title>
      <dc:creator>Dainy Jose</dc:creator>
      <pubDate>Sun, 02 Nov 2025 16:31:06 +0000</pubDate>
      <link>https://dev.to/dainyjose/step-by-step-guide-to-upgrading-your-react-native-expo-project-1fio</link>
      <guid>https://dev.to/dainyjose/step-by-step-guide-to-upgrading-your-react-native-expo-project-1fio</guid>
      <description>&lt;p&gt;Upgrading a React Native Expo project can seem intimidating — especially when juggling native modules, custom configurations, and environment files. But with the right plan, it can be smooth and predictable.&lt;/p&gt;

&lt;p&gt;In this post, I’ll walk you through a practical guide for upgrading an Expo project (bare or managed workflow) while keeping your setup stable and maintainable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Upgrade Regularly?
&lt;/h2&gt;

&lt;p&gt;Regular upgrades ensure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Access to the latest React Native and Expo features&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Improved performance and security&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Compatibility with new OS releases&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Easier future maintenance&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Neglecting upgrades can cause dependency conflicts, native crashes, or build failures during future updates — which are far harder to resolve later.&lt;/p&gt;




&lt;h2&gt;
  
  
  Before You Begin
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Check the Current SDK Version
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;expo &lt;span class="nt"&gt;--version&lt;/span&gt;
expo config &lt;span class="nt"&gt;--json&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;sdkVersion
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Review the Upgrade Guides
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.expo.dev/versions/latest/" rel="noopener noreferrer"&gt;Expo SDK Release Notes&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://react-native-community.github.io/upgrade-helper/" rel="noopener noreferrer"&gt;React Native Upgrade Helper&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Create a Backup
&lt;/h3&gt;

&lt;p&gt;Always create a branch for the upgrade:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; upgrade/sdk-52
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Update Environment Files
&lt;/h3&gt;

&lt;p&gt;Ensure &lt;code&gt;.env.development&lt;/code&gt; and &lt;code&gt;.env.production&lt;/code&gt; are consistent.&lt;br&gt;
Tip: Use a library like &lt;code&gt;react-native-dotenv&lt;/code&gt; for environment management.&lt;/p&gt;


&lt;h2&gt;
  
  
  Step 1: Upgrade Expo SDK
&lt;/h2&gt;

&lt;p&gt;Run the official upgrade command:&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 upgrade
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This automatically updates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Expo SDK version&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Related dependencies (&lt;code&gt;expo-*&lt;/code&gt; packages)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;iOS and Android native projects (if using bare workflow)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re in a bare workflow, run &lt;code&gt;pod install&lt;/code&gt; inside the &lt;code&gt;ios&lt;/code&gt; directory after upgrading.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Update React Native and Dependencies
&lt;/h2&gt;

&lt;p&gt;Check your current versions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm list react react-native
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, align them with the new Expo SDK version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;react@latest react-native@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you’re using TypeScript, also update:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;typescript @types/react @types/react-native &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 3: Clear Cache and Reset Metro Bundler
&lt;/h2&gt;

&lt;p&gt;After upgrading, clear the caches to avoid stale modules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;watchman watch-del-all
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; node_modules
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="nv"&gt;$TMPDIR&lt;/span&gt;/metro-&lt;span class="k"&gt;*&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 4: Verify Native Modules
&lt;/h2&gt;

&lt;p&gt;If you use libraries like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;react-native-vision-camera&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;react-native-share&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;react-native-blob-util&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;notifee/react-native&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ensure they’re compatible with the new SDK:&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 doctor
npx pod-install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For bare workflow users, verify your native modules in &lt;code&gt;MainApplication.kt&lt;/code&gt; / &lt;code&gt;AppDelegate.mm&lt;/code&gt; after upgrading.&lt;/p&gt;




&lt;p&gt;Step 5: Test Build on Both Platforms&lt;/p&gt;

&lt;p&gt;Run the project:&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 run:android
npx expo run:ios
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you face issues, open the build logs and look for deprecated properties or mismatched dependencies.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 6: Validate App Behavior
&lt;/h2&gt;

&lt;p&gt;Check these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Splash screen hides correctly&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Environment variables load properly&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;File sharing, notifications, and camera modules still work&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Production build signs and runs as expected&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also test locally with:&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 start &lt;span class="nt"&gt;--clear&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 7: Commit and Tag the Upgrade
&lt;/h2&gt;

&lt;p&gt;Once stable, commit your changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"chore: upgrade to Expo SDK 52 + RN 0.77"&lt;/span&gt;
git tag v1.2.0-upgrade
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Pro Tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use Dependabot or Renovate&lt;/strong&gt;: Automate version tracking.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Keep a Changelog&lt;/strong&gt;: Helps you and your team track upgrade impacts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Test on Real Devices&lt;/strong&gt;: Emulators don’t always reflect real-world issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Avoid Skipping SDKs&lt;/strong&gt;: Skipping major versions makes future upgrades painful.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;Upgrading your Expo project doesn’t have to break your flow.&lt;br&gt;
With the right steps — backups, incremental updates, and consistent testing — you can keep your project &lt;strong&gt;future-proof, stable, and developer-friendly&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you found this helpful, leave a ❤️ or share how you manage upgrades in your own Expo workflow!&lt;/p&gt;




&lt;p&gt;✍️ Written by &lt;a href="https://www.linkedin.com/in/dainyjose" rel="noopener noreferrer"&gt;&lt;strong&gt;Dainy Jose&lt;/strong&gt;&lt;/a&gt; — React Native Mobile Application Developer with 3+ years of experience building cross-platform mobile apps using &lt;strong&gt;React Native (Expo, TypeScript, Redux)&lt;/strong&gt;. &lt;br&gt;
Currently expanding backend knowledge through the &lt;strong&gt;MERN Stack (MongoDB, Express.js, React.js, Node.js)&lt;/strong&gt; to create more efficient, full-stack mobile experiences.&lt;/p&gt;

&lt;p&gt;💼 &lt;strong&gt;Tech Stack:&lt;/strong&gt; React Native · TypeScript · Redux · Expo · Firebase · Node.js · Express.js · MongoDB · REST API · JWT · Jest · Google Maps · Razorpay · PayU · Agile · SDLC · Git · Bitbucket · Jira &lt;/p&gt;

&lt;p&gt;📬 &lt;strong&gt;Connect with me&lt;/strong&gt;:&lt;br&gt;
🌐 &lt;a href="https://dainyjose.github.io/my-portfolio/" rel="noopener noreferrer"&gt;Portfolio&lt;/a&gt;&lt;br&gt;
🔗 &lt;a href="https://www.linkedin.com/in/dainyjose" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;br&gt;
💻 &lt;a href="https://github.com/dainyjose" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>mobile</category>
      <category>development</category>
      <category>typescript</category>
    </item>
    <item>
      <title>How I Built My Developer Portfolio with Vite, React, and Bun — Fast, Modern &amp; Fully Customizable</title>
      <dc:creator>Dainy Jose</dc:creator>
      <pubDate>Sun, 02 Nov 2025 14:52:41 +0000</pubDate>
      <link>https://dev.to/dainyjose/how-i-built-my-developer-portfolio-with-vite-react-and-bun-fast-modern-fully-customizable-410b</link>
      <guid>https://dev.to/dainyjose/how-i-built-my-developer-portfolio-with-vite-react-and-bun-fast-modern-fully-customizable-410b</guid>
      <description>&lt;p&gt;&lt;em&gt;A lightweight, modular portfolio built with Vite + React + TypeScript + Bun, designed to showcase projects, blogs, and achievements — built from scratch with simplicity and speed in mind.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I Built It
&lt;/h2&gt;

&lt;p&gt;As developers, our portfolios are often the first impression we make — so I wanted mine to be &lt;strong&gt;clean, fast, and easy to maintain&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I experimented with several static site tools before finding the perfect trio: &lt;strong&gt;Vite, React&lt;/strong&gt;, and &lt;strong&gt;Bun&lt;/strong&gt;.&lt;br&gt;
This stack offered everything I wanted — modern development, instant reloads, and a minimal setup that just works.&lt;/p&gt;

&lt;p&gt;👉 Live Demo: &lt;a href="https://dainyjose.github.io/my-portfolio/" rel="noopener noreferrer"&gt;https://dainyjose.github.io/my-portfolio/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👉 Source Code: &lt;a href="https://github.com/dainyjose/my-portfolio" rel="noopener noreferrer"&gt;https://github.com/dainyjose/my-portfolio&lt;/a&gt;&lt;/p&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Vite&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Lightning-fast build tool with instant HMR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;React + TypeScript&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Component-based architecture with type safety&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bun&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fast JavaScript runtime &amp;amp; package manager&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CSS Modules&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Clean and scoped component styling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GitHub Pages&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Simple and free static site hosting&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h2&gt;
  
  
  Setting Up the Project
&lt;/h2&gt;

&lt;p&gt;Vite and Bun make setting up a React + TypeScript project almost instant.&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;# Create a new Vite + React + TypeScript project&lt;/span&gt;
bun create vite my-portfolio &lt;span class="nt"&gt;--template&lt;/span&gt; react-ts

&lt;span class="nb"&gt;cd &lt;/span&gt;my-portfolio

&lt;span class="c"&gt;# Install dependencies (super fast!)&lt;/span&gt;
bun &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# Start the dev server&lt;/span&gt;
bun run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Within seconds, the project is live with hot reload and TypeScript support.&lt;/p&gt;




&lt;h2&gt;
  
  
  Project Structure
&lt;/h2&gt;

&lt;p&gt;Here’s how I organized my portfolio for clarity and scalability:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;my-portfolio/
 ┣ src/
 ┃ ┣ components/
 ┃ ┣ pages/
 ┃ ┣ data/
 ┃ ┣ assets/
 ┃ ┗ App.tsx
 ┣ public/
 ┣ index.html
 ┣ vite.config.ts
 ┗ bun.lockb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Highlights:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;components/&lt;/code&gt; → Reusable UI elements (Header, Footer, ProjectCard, etc.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;pages/&lt;/code&gt; → Sections like Home, About, Projects, and Contact&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;data/&lt;/code&gt; → Static project data and links&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;assets/&lt;/code&gt; → Images and icons&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Designing the UI
&lt;/h2&gt;

&lt;p&gt;I went for a &lt;strong&gt;simple, professional design&lt;/strong&gt; — no UI frameworks or heavy styling libraries, just clean &lt;strong&gt;CSS&lt;/strong&gt; Modules for scoped styles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;// src/components/Header.tsx
import styles from &lt;span class="s2"&gt;"./header.css"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nb"&gt;export &lt;/span&gt;const Header &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;
  &amp;lt;header &lt;span class="nv"&gt;className&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;styles.header&lt;span class="o"&gt;}&amp;gt;&lt;/span&gt;
    &amp;lt;h1 &lt;span class="nv"&gt;className&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;styles.title&lt;span class="o"&gt;}&amp;gt;&lt;/span&gt;Dainy Jose&amp;lt;/h1&amp;gt;
    &amp;lt;nav &lt;span class="nv"&gt;className&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;styles.nav&lt;span class="o"&gt;}&amp;gt;&lt;/span&gt;
      &amp;lt;a &lt;span class="nv"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"#projects"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;Projects&amp;lt;/a&amp;gt;
      &amp;lt;a &lt;span class="nv"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"#contact"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;Contact&amp;lt;/a&amp;gt;
    &amp;lt;/nav&amp;gt;
  &amp;lt;/header&amp;gt;
&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/&lt;span class="k"&gt;*&lt;/span&gt; src/components/header.css &lt;span class="k"&gt;*&lt;/span&gt;/
.header &lt;span class="o"&gt;{&lt;/span&gt;
  display: flex&lt;span class="p"&gt;;&lt;/span&gt;
  justify-content: space-between&lt;span class="p"&gt;;&lt;/span&gt;
  align-items: center&lt;span class="p"&gt;;&lt;/span&gt;
  padding: 1rem 2rem&lt;span class="p"&gt;;&lt;/span&gt;
  background-color: &lt;span class="c"&gt;#ffffff;&lt;/span&gt;
  border-bottom: 1px solid &lt;span class="c"&gt;#eaeaea;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

.title &lt;span class="o"&gt;{&lt;/span&gt;
  font-size: 1.6rem&lt;span class="p"&gt;;&lt;/span&gt;
  font-weight: 600&lt;span class="p"&gt;;&lt;/span&gt;
  color: &lt;span class="c"&gt;#222;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

.nav a &lt;span class="o"&gt;{&lt;/span&gt;
  margin-left: 1rem&lt;span class="p"&gt;;&lt;/span&gt;
  text-decoration: none&lt;span class="p"&gt;;&lt;/span&gt;
  color: &lt;span class="c"&gt;#007bff;&lt;/span&gt;
  transition: color 0.2s&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

.nav a:hover &lt;span class="o"&gt;{&lt;/span&gt;
  color: &lt;span class="c"&gt;#0056b3;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives full control over the look while keeping the CSS lightweight and maintainable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Adding Projects &amp;amp; Blogs
&lt;/h2&gt;

&lt;p&gt;To make it easy to update, I store all portfolio items in a single &lt;code&gt;data/projects.ts&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;// src/data/projects.ts
&lt;span class="nb"&gt;export &lt;/span&gt;const projects &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
  &lt;span class="o"&gt;{&lt;/span&gt;
    name: &lt;span class="s2"&gt;"My Resume App"&lt;/span&gt;,
    description: &lt;span class="s2"&gt;"Created using React + Vite."&lt;/span&gt;,
    &lt;span class="nb"&gt;link&lt;/span&gt;: &lt;span class="s2"&gt;"https://dainyjose.github.io/my-resume/"&lt;/span&gt;,
  &lt;span class="o"&gt;}&lt;/span&gt;,
&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And render them dynamically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;// src/components/Projects.tsx
import &lt;span class="o"&gt;{&lt;/span&gt; projects &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s2"&gt;"../data/projects"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nb"&gt;export &lt;/span&gt;const Projects &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;
  &amp;lt;section &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"projects"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &amp;lt;h2&amp;gt;Projects&amp;lt;/h2&amp;gt;
    &lt;span class="o"&gt;{&lt;/span&gt;projects.map&lt;span class="o"&gt;((&lt;/span&gt;p&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;
      &amp;lt;a &lt;span class="nv"&gt;key&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;p.name&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;href&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;p.link&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"_blank"&lt;/span&gt; &lt;span class="nv"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"noopener noreferrer"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &amp;lt;h3&amp;gt;&lt;span class="o"&gt;{&lt;/span&gt;p.name&lt;span class="o"&gt;}&lt;/span&gt;&amp;lt;/h3&amp;gt;
        &amp;lt;p&amp;gt;&lt;span class="o"&gt;{&lt;/span&gt;p.description&lt;span class="o"&gt;}&lt;/span&gt;&amp;lt;/p&amp;gt;
      &amp;lt;/a&amp;gt;
    &lt;span class="o"&gt;))}&lt;/span&gt;
  &amp;lt;/section&amp;gt;
&lt;span class="o"&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 makes adding new projects as easy as editing one file.&lt;/p&gt;




&lt;h2&gt;
  
  
  Optimizing for Performance
&lt;/h2&gt;

&lt;p&gt;To keep the site fast:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Compressed images manually before adding to &lt;code&gt;assets/&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Leveraged Vite’s built-in minification and bundling&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Bun handled builds incredibly fast&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every rebuild or deploy took only a few seconds.&lt;/p&gt;




&lt;h2&gt;
  
  
  Deployment
&lt;/h2&gt;

&lt;p&gt;I hosted the portfolio on &lt;strong&gt;GitHub Pages&lt;/strong&gt; using a simple build + deploy command:&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="s2"&gt;"scripts"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"dev"&lt;/span&gt;: &lt;span class="s2"&gt;"vite"&lt;/span&gt;,
  &lt;span class="s2"&gt;"build"&lt;/span&gt;: &lt;span class="s2"&gt;"vite build"&lt;/span&gt;,
  &lt;span class="s2"&gt;"preview"&lt;/span&gt;: &lt;span class="s2"&gt;"vite preview"&lt;/span&gt;,
  &lt;span class="s2"&gt;"deploy"&lt;/span&gt;: &lt;span class="s2"&gt;"gh-pages -d dist"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then deployed with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bun run build
bun run deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In just a few seconds, the site was live:&lt;br&gt;
➡️ &lt;a href="https://dainyjose.github.io/my-portfolio" rel="noopener noreferrer"&gt;https://dainyjose.github.io/my-portfolio&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Bun + Vite make development effortless&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The build and dev speed is unbeatable.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;TypeScript ensures long-term scalability&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Strong typing helps maintain clean code.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;CSS Modules keep styling simple and scoped&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easy to maintain and modify as the portfolio grows.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;GitHub Pages = quick deployment&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Perfect for personal projects and static sites.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  What’s Next
&lt;/h2&gt;

&lt;p&gt;I plan to enhance the portfolio with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Dark mode toggle&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;GitHub API integration to auto-fetch repositories&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dev.to API integration for displaying latest blog posts&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;This project reminded me that &lt;strong&gt;simplicity is powerful&lt;/strong&gt;.&lt;br&gt;
You don’t need complex tools or heavy UI frameworks to create something elegant and efficient.&lt;/p&gt;

&lt;p&gt;If you’re building your portfolio, I highly recommend giving &lt;strong&gt;Vite + React + Bun&lt;/strong&gt; a try — you’ll be surprised by how smooth the workflow is.&lt;/p&gt;

&lt;p&gt;🔗 Repo: &lt;a href="https://github.com/dainyjose/my-portfolio" rel="noopener noreferrer"&gt;https://github.com/dainyjose/my-portfolio&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🌐 Live: &lt;a href="https://dainyjose.github.io/my-portfolio/" rel="noopener noreferrer"&gt;https://dainyjose.github.io/my-portfolio/&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;✍️ Written by &lt;a href="https://www.linkedin.com/in/dainyjose" rel="noopener noreferrer"&gt;&lt;strong&gt;Dainy Jose&lt;/strong&gt;&lt;/a&gt; — React Native Mobile Application Developer with 3+ years of experience building cross-platform mobile apps using &lt;strong&gt;React Native (Expo, TypeScript, Redux)&lt;/strong&gt;. &lt;br&gt;
Currently expanding backend knowledge through the &lt;strong&gt;MERN Stack (MongoDB, Express.js, React.js, Node.js)&lt;/strong&gt; to create more efficient, full-stack mobile experiences.&lt;/p&gt;

&lt;p&gt;💼 &lt;strong&gt;Tech Stack:&lt;/strong&gt; React Native · TypeScript · Redux · Expo · Firebase · Node.js · Express.js · MongoDB · REST API · JWT · Jest · Google Maps · Razorpay · PayU · Agile · SDLC · Git · Bitbucket · Jira &lt;/p&gt;

&lt;p&gt;📬 &lt;strong&gt;Connect with me&lt;/strong&gt;:&lt;br&gt;
🌐 &lt;a href="https://dainyjose.github.io/my-portfolio/" rel="noopener noreferrer"&gt;Portfolio&lt;/a&gt;&lt;br&gt;
🔗 &lt;a href="https://www.linkedin.com/in/dainyjose" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;br&gt;
💻 &lt;a href="https://github.com/dainyjose" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>vite</category>
      <category>portfolio</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Advanced Push &amp; Local Notifications in React Native with Firebase and Notifee (Part 2)</title>
      <dc:creator>Dainy Jose</dc:creator>
      <pubDate>Tue, 28 Oct 2025 15:56:27 +0000</pubDate>
      <link>https://dev.to/dainyjose/advanced-push-local-notifications-in-react-native-with-firebase-and-notifee-part-2-2mn6</link>
      <guid>https://dev.to/dainyjose/advanced-push-local-notifications-in-react-native-with-firebase-and-notifee-part-2-2mn6</guid>
      <description>&lt;p&gt;In the &lt;a href="https://dev.to/dainyjose/implementing-push-notifications-in-react-native-using-firebase-and-notifee-ahl"&gt;first part&lt;/a&gt; of this series, we built a complete &lt;strong&gt;Firebase Cloud Messaging (FCM)&lt;/strong&gt; setup for &lt;strong&gt;React Native&lt;/strong&gt; using &lt;strong&gt;Firebase&lt;/strong&gt; and &lt;strong&gt;Notifee&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now, in &lt;strong&gt;Part 2&lt;/strong&gt;, we’ll go deeper and explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📱 Local notifications
&lt;/li&gt;
&lt;li&gt;✨ Custom notification styles
&lt;/li&gt;
&lt;li&gt;⏰ Triggers and scheduling
&lt;/li&gt;
&lt;li&gt;⚡ Action buttons and backend integration
&lt;/li&gt;
&lt;li&gt;🎧 Media and chat-style notifications
&lt;/li&gt;
&lt;li&gt;📊 Event tracking for every app state (Foreground, Background, Killed)
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This part focuses on building a &lt;strong&gt;robust notification system&lt;/strong&gt; that behaves consistently across app states — with fixes to ensure reliable delivery and accurate navigation.&lt;/p&gt;




&lt;h2&gt;
  
  
  📱 1. Local Notifications with Notifee
&lt;/h2&gt;

&lt;p&gt;Local notifications are shown &lt;strong&gt;without FCM&lt;/strong&gt;, usually triggered by in-app events — such as reminders or task completions.&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="nx"&gt;notifee&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AndroidImportance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TriggerType&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;@notifee/react-native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Simple local notification&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;showLocalNotification&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;notifee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;requestPermission&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;channelId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;notifee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createChannel&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;local&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Local Notifications&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;importance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AndroidImportance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HIGH&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;notifee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;displayNotification&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;'NotifyMeApp Reminder',&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Your scheduled task is ready!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;channelId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;smallIcon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ic_launcher&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can call &lt;code&gt;showLocalNotification()&lt;/code&gt; anywhere — even as a response to user actions or events.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⏰ 2. Notification Triggers
&lt;/h2&gt;

&lt;p&gt;Notifee allows &lt;strong&gt;scheduled&lt;/strong&gt; or &lt;strong&gt;event-based&lt;/strong&gt; notifications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example: Trigger after 10 seconds&lt;/strong&gt;&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;trigger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TriggerType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TIMESTAMP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 10 seconds later&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;notifee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTriggerNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;NotifyMeApp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;⏰ Scheduled notification fired!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;channelId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;local&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="nx"&gt;trigger&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;Example: Repeat daily reminder&lt;/strong&gt;&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;trigger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TriggerType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;INTERVAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// every 24 hours&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;notifee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTriggerNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Daily Reminder&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;It’s time to check new updates!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;channelId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;local&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="nx"&gt;trigger&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧱 3. Customizing Notifications
&lt;/h2&gt;

&lt;p&gt;You can completely customize your notification look using Notifee’s Android styles.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Big Picture Style (with Image)&lt;/strong&gt;&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;await&lt;/span&gt; &lt;span class="nx"&gt;notifee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;displayNotification&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;New Offer Available 🎉&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Get 20% off on your next rental!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;channelId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;promo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;notifee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AndroidStyle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BIGPICTURE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;picture&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://example.com/offer-banner.jpg&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;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Messaging Style (for Chat)&lt;/strong&gt;&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;await&lt;/span&gt; &lt;span class="nx"&gt;notifee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;displayNotification&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hey! Are you available for the shoot tomorrow?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;channelId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;notifee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AndroidStyle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MESSAGING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;person&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;messages&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="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hey! Are you available for the shoot tomorrow?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&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="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;
  
  
  ⚙️ 4. Notification Actions (with Backend Support)
&lt;/h2&gt;

&lt;p&gt;Add buttons directly to your notifications to trigger specific actions.&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="c"&gt;&amp;lt;!--&lt;/span&gt; &lt;span class="nx"&gt;AndroidManifest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;xml&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;activity&lt;/span&gt; &lt;span class="nx"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.MainActivity&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="nx"&gt;intent&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;filter&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;action&lt;/span&gt; &lt;span class="nx"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;OPEN_ACTIVITY_1&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="nx"&gt;category&lt;/span&gt; &lt;span class="nx"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;android.intent.category.DEFAULT&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;/intent-filter&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="sr"&gt;/activity&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then in your notification payload (from backend):&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&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="na"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;NotifyMeApp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;New message received&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="na"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;channelId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;actions&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="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Reply&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;pressAction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;OPEN_ACTIVITY_1&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;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;p&gt;In your app:&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="nx"&gt;notifee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onForegroundEvent&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;detail&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;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;notifee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EventType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ACTION_PRESS&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pressAction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;OPEN_ACTIVITY_1&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User tapped Reply button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Backend can be notified here (e.g., mark as read or open chat)&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;
  
  
  🧠 5. Notification Events Across App States
&lt;/h2&gt;

&lt;p&gt;Recent improvements have made notifications behave &lt;strong&gt;consistently&lt;/strong&gt; across all app states.&lt;br&gt;
Here’s how you can handle each transition cleanly 👇&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Received In&lt;/th&gt;
&lt;th&gt;Opened From&lt;/th&gt;
&lt;th&gt;Expected Behavior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Foreground&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Foreground&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Show custom in-app popup or Notifee local notification&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Foreground&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Background&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Navigate to target screen after resume&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Foreground&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Killed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;getInitialNotification()&lt;/code&gt; to handle navigation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Background&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Foreground&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Auto-navigate to notification target&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Background&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Background&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Open directly to target screen&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Background&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Killed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Retrieve data from FCM launch event&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Killed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Foreground&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fetch from last FCM message using &lt;code&gt;onNotificationOpenedApp&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Killed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Background&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Same as above — delayed navigation allowed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Killed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Killed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Delivered silently; handle upon next app launch&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Implementation Example&lt;/strong&gt;&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="nx"&gt;messaging&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-firebase/messaging&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="nx"&gt;notifee&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;@notifee/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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;navigationRef&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;./NavigationService&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Foreground messages&lt;/span&gt;
&lt;span class="nf"&gt;messaging&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;onMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;remoteMessage&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;await&lt;/span&gt; &lt;span class="nx"&gt;notifee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;displayNotification&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;remoteMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;remoteMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;channelId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;default&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;span class="c1"&gt;// When app is opened from background&lt;/span&gt;
&lt;span class="nf"&gt;messaging&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;onNotificationOpenedApp&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;remoteMessage&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;remoteMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;targetScreen&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;screen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;navigationRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// When app is launched from a killed state&lt;/span&gt;
&lt;span class="nf"&gt;messaging&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInitialNotification&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;remoteMessage&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;remoteMessage&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="nx"&gt;screen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;remoteMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;targetScreen&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;screen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;navigationRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&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;
  
  
  🎧 6. Media &amp;amp; Chat Notifications
&lt;/h2&gt;

&lt;p&gt;To include images, videos, or chat previews inside notifications:&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;await&lt;/span&gt; &lt;span class="nx"&gt;notifee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;displayNotification&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;🎬 Video Upload Complete!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Your project is now ready to share.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;channelId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;media&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;notifee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AndroidStyle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BIGPICTURE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;picture&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://example.com/video-thumbnail.jpg&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;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For chat-like experience:&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;await&lt;/span&gt; &lt;span class="nx"&gt;notifee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;displayNotification&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Anna&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hey! New project details are ready!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;channelId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;notifee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AndroidStyle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MESSAGING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;person&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Anna&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;messages&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="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hey! New project details are ready!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&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="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Let’s discuss soon.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&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="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;
  
  
  ✅ Key Fixes and Improvements
&lt;/h2&gt;

&lt;p&gt;In the latest implementation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Notifications tapped from a &lt;strong&gt;killed&lt;/strong&gt; state now navigate correctly.&lt;/li&gt;
&lt;li&gt;Foreground notifications no longer duplicate when both FCM and Notifee handlers are active.&lt;/li&gt;
&lt;li&gt;Deep links from &lt;strong&gt;background&lt;/strong&gt; notifications navigate smoothly on resume.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Resolved by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using &lt;code&gt;getInitialNotification()&lt;/code&gt; for cold starts&lt;/li&gt;
&lt;li&gt;Ensuring single &lt;strong&gt;Notifee channel creation&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Separating &lt;strong&gt;local + FCM handlers&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Maintaining event order for consistent navigation&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎯 Wrapping Up
&lt;/h2&gt;

&lt;p&gt;In this advanced guide, we covered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Local &amp;amp; scheduled notifications&lt;/li&gt;
&lt;li&gt;Trigger-based alerts&lt;/li&gt;
&lt;li&gt;Media and chat-style notifications&lt;/li&gt;
&lt;li&gt;Custom action buttons integrated with backend&lt;/li&gt;
&lt;li&gt;Complete event handling across all app states&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Together with &lt;strong&gt;Part 1&lt;/strong&gt;, you now have a &lt;strong&gt;production-ready notification system&lt;/strong&gt; for any React Native app.&lt;/p&gt;




&lt;p&gt;✍️ Written by &lt;a href="https://www.linkedin.com/in/dainyjose" rel="noopener noreferrer"&gt;&lt;strong&gt;Dainy Jose&lt;/strong&gt;&lt;/a&gt; — React Native Mobile Application Developer with 3+ years of experience building cross-platform mobile apps using &lt;strong&gt;React Native (Expo, TypeScript, Redux)&lt;/strong&gt;. &lt;br&gt;
Currently expanding backend knowledge through the &lt;strong&gt;MERN Stack (MongoDB, Express.js, React.js, Node.js)&lt;/strong&gt; to create more efficient, full-stack mobile experiences.&lt;/p&gt;

&lt;p&gt;💼 &lt;strong&gt;Tech Stack:&lt;/strong&gt; React Native · TypeScript · Redux · Expo · Firebase · Node.js · Express.js · MongoDB · REST API · JWT · Jest · Google Maps · Razorpay · PayU · Agile · SDLC · Git · Bitbucket · Jira &lt;/p&gt;

&lt;p&gt;📬 &lt;strong&gt;Connect with me&lt;/strong&gt;:&lt;br&gt;
🌐 &lt;a href="https://dainyjose.github.io/my-portfolio/" rel="noopener noreferrer"&gt;Portfolio&lt;/a&gt;&lt;br&gt;
🔗 &lt;a href="https://www.linkedin.com/in/dainyjose" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;br&gt;
💻 &lt;a href="https://github.com/dainyjose" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>firebase</category>
      <category>mobile</category>
      <category>notifications</category>
    </item>
  </channel>
</rss>
