<?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: Rushikesh Pandit</title>
    <description>The latest articles on DEV Community by Rushikesh Pandit (@rushikeshpandit).</description>
    <link>https://dev.to/rushikeshpandit</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%2F1365257%2F16e12541-8d0a-40b4-8fde-24b2c6c5ec69.jpeg</url>
      <title>DEV Community: Rushikesh Pandit</title>
      <link>https://dev.to/rushikeshpandit</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rushikeshpandit"/>
    <language>en</language>
    <item>
      <title>A dependency-first checklist for upgrading React Native</title>
      <dc:creator>Rushikesh Pandit</dc:creator>
      <pubDate>Fri, 16 Oct 2026 14:37:45 +0000</pubDate>
      <link>https://dev.to/rushikeshpandit/a-dependency-first-checklist-for-upgrading-react-native-3bb9</link>
      <guid>https://dev.to/rushikeshpandit/a-dependency-first-checklist-for-upgrading-react-native-3bb9</guid>
      <description>&lt;p&gt;Most upgrade guides start with the template diff. I now start about five steps earlier, because that's&lt;br&gt;
where the surprises live.&lt;/p&gt;
&lt;h2&gt;
  
  
  1. List your native dependencies
&lt;/h2&gt;

&lt;p&gt;A native dependency is any package with an &lt;code&gt;ios/&lt;/code&gt; folder, an &lt;code&gt;android/&lt;/code&gt; folder or a &lt;code&gt;.podspec&lt;/code&gt;. Each one&lt;br&gt;
is a separate compatibility question. Here's a small script (Node 18+, run from your project root):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// list-native-deps.mjs&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;readdirSync&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;existsSync&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;statSync&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;node:fs&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;join&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;node:path&lt;/span&gt;&lt;span class="dl"&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;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node_modules&lt;/span&gt;&lt;span class="dl"&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;isNative&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;existsSync&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="nx"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;android&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
  &lt;span class="nf"&gt;existsSync&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="nx"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ios&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
  &lt;span class="nf"&gt;readdirSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;f&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;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.podspec&lt;/span&gt;&lt;span class="dl"&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;candidates&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="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;readdirSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&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;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;continue&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;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@&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="k"&gt;for &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="k"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;readdirSync&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="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="nx"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&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="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&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="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&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;for &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;dir&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&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="nf"&gt;statSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;isDirectory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;isNative&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dir&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="nx"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&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;Caveat: with pnpm, only your direct dependencies appear at the top level of &lt;code&gt;node_modules&lt;/code&gt;, so you'll see&lt;br&gt;
direct native deps but not every transitive one.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Check each against the target version
&lt;/h2&gt;

&lt;p&gt;For each native dependency: when was the last release? Does the README or changelog mention your target&lt;br&gt;
React Native version? Are there open issues with the version number in the title? Write the answer down&lt;br&gt;
as &lt;strong&gt;compatible / unknown / broken&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Check peer dependency ranges
&lt;/h2&gt;

&lt;p&gt;Look at &lt;code&gt;peerDependencies&lt;/code&gt; for &lt;code&gt;react&lt;/code&gt; and &lt;code&gt;react-native&lt;/code&gt; in each library. A pinned upper bound is an early&lt;br&gt;
warning, even if everything installs with &lt;code&gt;--legacy-peer-deps&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Verify the toolchain
&lt;/h2&gt;

&lt;p&gt;Read the release notes for your target version and list the required Xcode, JDK, Node and Android Gradle&lt;br&gt;
Plugin versions. Compare with your CI images and your teammates' machines. Mismatches here fail late.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Dry-run on a throwaway branch
&lt;/h2&gt;

&lt;p&gt;Bump, install, build both platforms, run the app. Time-box it. Record every failure with the file and the&lt;br&gt;
error. This list &lt;em&gt;is&lt;/em&gt; your real estimate.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Now apply the Upgrade Helper diff
&lt;/h2&gt;

&lt;p&gt;With the risk list in hand, the diff is much easier to apply, because you know what's likely to collide.&lt;/p&gt;

&lt;h2&gt;
  
  
  One hop or several?
&lt;/h2&gt;

&lt;p&gt;Jumping many versions at once is faster when it works and harder to debug when it doesn't. If your dry run&lt;br&gt;
shows many unknowns, stepping through intermediate versions can isolate failures. Decide using your risk&lt;br&gt;
list, not habit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automating steps 1–4
&lt;/h2&gt;

&lt;p&gt;I'm building &lt;strong&gt;rn-upgrade-doctor&lt;/strong&gt; to automate the inventory and compatibility checks and produce a&lt;br&gt;
project-specific risk report. CLI public on 20 Oct: &lt;a href="https://rnupgradedoctor.dev/" rel="noopener noreferrer"&gt;rn-upgrade-doctor&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What step would you add to this list?&lt;/p&gt;

</description>
      <category>mobile</category>
      <category>reactnative</category>
      <category>tutorial</category>
      <category>javascript</category>
    </item>
    <item>
      <title>iOS 27 Crashing Your App at Launch? Every Fix for the UIScene Lifecycle Error</title>
      <dc:creator>Rushikesh Pandit</dc:creator>
      <pubDate>Wed, 14 Oct 2026 13:41:43 +0000</pubDate>
      <link>https://dev.to/rushikeshpandit/ios-27-crashing-your-app-at-launch-every-fix-for-the-uiscene-lifecycle-error-5ag8</link>
      <guid>https://dev.to/rushikeshpandit/ios-27-crashing-your-app-at-launch-every-fix-for-the-uiscene-lifecycle-error-5ag8</guid>
      <description>&lt;p&gt;You rebuilt your app, it compiled with zero warnings, and the moment it opens on an iOS 27 device it vanishes. No JS error. No managed exception. Just a flash of the launch screen and a dead process.&lt;/p&gt;

&lt;p&gt;If that's you, you've probably hit this line in the device log:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application failed to launch: UIScene life cycle is required for apps
 built with this SDK.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This post explains what is actually happening, and walks through every fix I could verify, from plain UIKit to React Native, Expo, and a few other stacks.&lt;/p&gt;

&lt;h2&gt;
  
  
  First, a correction to the common story
&lt;/h2&gt;

&lt;p&gt;The popular framing is "apps built with older Xcode crash on iOS 27". The sources I checked say the opposite:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The check is tied to the &lt;strong&gt;SDK you build with&lt;/strong&gt;, not the iOS version on the phone.&lt;/li&gt;
&lt;li&gt;An app built with &lt;strong&gt;Xcode 26&lt;/strong&gt; (iOS 26 SDK) still launches on iOS 27.&lt;/li&gt;
&lt;li&gt;An app built with &lt;strong&gt;Xcode 27&lt;/strong&gt; (iOS 27 SDK) that hasn't adopted the UIScene lifecycle is killed at launch on iOS 27.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Apple's iOS &amp;amp; iPadOS 27 release notes put it in one sentence: apps built with the latest SDK must adopt the scene-based life cycle or they fail to launch. That is why "it worked yesterday" is true: nothing in your code changed, only your toolchain did.&lt;/p&gt;

&lt;p&gt;A nasty side effect: the same Xcode 27 build can still launch fine on iOS 26, so a smoke test on an older phone can pass while every iOS 27 user crashes.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to confirm it's this crash
&lt;/h2&gt;

&lt;p&gt;The crash report looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Exception Type:  EXC_BREAKPOINT (SIGTRAP)
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0  UIKitCore  ___UIApplicationEvaluateRuntimeIssueForNoSceneLifecycleAdoption_block_invoke
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see &lt;code&gt;NoSceneLifecycleAdoption&lt;/code&gt; in the top frames, you're in the right place. It happens in both Debug and Release.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do you need to migrate?
&lt;/h2&gt;

&lt;p&gt;Per Apple's TN3187, migrate if either is true:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;UIApplicationSceneManifest&lt;/code&gt; key is missing from your &lt;code&gt;Info.plist&lt;/code&gt;, or it has no configurations.&lt;/li&gt;
&lt;li&gt;Your app delegate doesn't implement &lt;code&gt;application(_:configurationForConnecting:options:)&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Note that a manifest containing only &lt;code&gt;UIApplicationSupportsMultipleScenes&lt;/code&gt; does not count as adopting scenes. Also, only &lt;em&gt;adoption&lt;/em&gt; is required. You do not have to support multiple windows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 1: Adopt scenes in a native UIKit app (the real fix)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Add the scene manifest to Info.plist
&lt;/h3&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;key&amp;gt;&lt;/span&gt;UIApplicationSceneManifest&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dict&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;UIApplicationSupportsMultipleScenes&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;false/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;UISceneConfigurations&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dict&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;UIWindowSceneSessionRoleApplication&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;array&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;dict&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;UISceneConfigurationName&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;Default Configuration&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;UISceneDelegateClassName&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;$(PRODUCT_MODULE_NAME).SceneDelegate&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;UISceneStoryboardFile&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;Main&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/dict&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/array&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dict&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dict&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you use a storyboard, keep the storyboard name in the scene configuration. If you build your UI in code, drop &lt;code&gt;UISceneStoryboardFile&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Create a SceneDelegate that owns the window
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;UIKit&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;SceneDelegate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIResponder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;UIWindowSceneDelegate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;window&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIWindow&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIScene&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;willConnectTo&lt;/span&gt; &lt;span class="nv"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UISceneSession&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="nv"&gt;connectionOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIScene&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;ConnectionOptions&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;windowScene&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scene&lt;/span&gt; &lt;span class="k"&gt;as?&lt;/span&gt; &lt;span class="kt"&gt;UIWindowScene&lt;/span&gt; &lt;span class="k"&gt;else&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="n"&gt;window&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;UIWindow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;windowScene&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;windowScene&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rootViewController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;YourRootViewController&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeKeyAndVisible&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;Remove window creation from &lt;code&gt;application(_:didFinishLaunchingWithOptions:)&lt;/code&gt;. An app delegate that creates its own &lt;code&gt;UIWindow&lt;/code&gt; with no scene delegate is exactly what triggers the crash.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Move the lifecycle callbacks
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;UIApplicationDelegate&lt;/th&gt;
&lt;th&gt;UISceneDelegate&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;applicationDidBecomeActive(_:)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sceneDidBecomeActive(_:)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;applicationWillResignActive(_:)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sceneWillResignActive(_:)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;applicationDidEnterBackground(_:)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sceneDidEnterBackground(_:)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;applicationWillEnterForeground(_:)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sceneWillEnterForeground(_:)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Optional: configure scenes in code instead of the plist
&lt;/h3&gt;

&lt;p&gt;If you need dynamic configuration, implement this in your app delegate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;application&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIApplication&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;configurationForConnecting&lt;/span&gt; &lt;span class="nv"&gt;connectingSceneSession&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UISceneSession&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIScene&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;ConnectionOptions&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;UISceneConfiguration&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;UISceneConfiguration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Default Configuration"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="nv"&gt;sessionRole&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;connectingSceneSession&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;role&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;
  
  
  Fix 2: Don't forget what silently stops working after you migrate
&lt;/h2&gt;

&lt;p&gt;Adopting scenes fixes the launch crash, but it moves responsibilities. These are the regressions that compile fine and fail quietly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deep links and universal links.&lt;/strong&gt; URL opens and user activities go to the scene delegate. &lt;code&gt;application(_:open:options:)&lt;/code&gt; and &lt;code&gt;application(_:continue:restorationHandler:)&lt;/code&gt; on the app delegate stop being called.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cold-start links.&lt;/strong&gt; A link that launches the app no longer shows up in &lt;code&gt;launchOptions&lt;/code&gt;. It arrives in &lt;code&gt;connectionOptions.urlContexts&lt;/code&gt; and &lt;code&gt;connectionOptions.userActivities&lt;/code&gt; inside &lt;code&gt;scene(_:willConnectTo:options:)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Startup code that assumes a window.&lt;/strong&gt; &lt;code&gt;didFinishLaunching&lt;/code&gt; now returns before any window exists. Anything touching the window or root view controller belongs after the scene connects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code that reads &lt;code&gt;UIApplication.shared.delegate?.window&lt;/code&gt;.&lt;/strong&gt; The app delegate no longer owns the window.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Test deep links two ways: with the app running, and with the app fully closed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 3: React Native
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Check where you stand
&lt;/h3&gt;

&lt;p&gt;You've adopted scenes if your &lt;code&gt;Info.plist&lt;/code&gt; has a &lt;code&gt;UIApplicationSceneManifest&lt;/code&gt; with scene configurations, or your app delegate implements &lt;code&gt;application(_:configurationForConnecting:options:)&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Upgrade path
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;React Native 0.88&lt;/strong&gt; is reported as the first release whose template adopts scenes: a &lt;code&gt;SceneDelegate.swift&lt;/code&gt; starts React Native in the window scene and &lt;code&gt;Info.plist&lt;/code&gt; references it. As of early October it was still a release candidate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;0.87 and earlier&lt;/strong&gt; have nothing in the template. Upgrade, then copy the scene delegate and the Info.plist changes from the &lt;a href="https://react-native-community.github.io/upgrade-helper/" rel="noopener noreferrer"&gt;Upgrade Helper&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The library crash that appears after you adopt scenes
&lt;/h3&gt;

&lt;p&gt;On the new template the &lt;code&gt;AppDelegate&lt;/code&gt; has no &lt;code&gt;window&lt;/code&gt; property. Libraries that still do this will crash:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight objective_c"&gt;&lt;code&gt;&lt;span class="n"&gt;UIViewController&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;UIApplication&lt;/span&gt; &lt;span class="nf"&gt;sharedApplication&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;delegate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rootViewController&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 objective_c"&gt;&lt;code&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;AppDelegate&lt;/span&gt; &lt;span class="nf"&gt;window&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;unrecognized&lt;/span&gt; &lt;span class="n"&gt;selector&lt;/span&gt; &lt;span class="n"&gt;sent&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The one-line fix inside the library is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight objective_c"&gt;&lt;code&gt;&lt;span class="n"&gt;UIViewController&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RCTPresentedViewController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// or RCTKeyWindow().rootViewController&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Libraries reported to be affected by this pattern include &lt;code&gt;react-native-blob-util&lt;/code&gt;, &lt;code&gt;@react-native-firebase/messaging&lt;/code&gt; (crashes at launch), &lt;code&gt;react-native-google-mobile-ads&lt;/code&gt;, &lt;code&gt;react-native-date-picker&lt;/code&gt;, &lt;code&gt;react-native-image-crop-picker&lt;/code&gt;, and &lt;code&gt;rn-fetch-blob&lt;/code&gt;. Until upstream ships fixes, a &lt;code&gt;patch-package&lt;/code&gt; patch with the line above works. Check each library's open PRs first.&lt;/p&gt;

&lt;h3&gt;
  
  
  Forward deep links from the scene delegate
&lt;/h3&gt;

&lt;p&gt;Nothing crashes if you forget this. &lt;code&gt;Linking&lt;/code&gt; just stops firing. A sketch to adapt to your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIScene&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;openURLContexts&lt;/span&gt; &lt;span class="kt"&gt;URLContexts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;UIOpenURLContext&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="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;URLContexts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="k"&gt;else&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="kt"&gt;RCTLinkingManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;UIApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;open&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;options&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;func&lt;/span&gt; &lt;span class="nf"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIScene&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt; &lt;span class="nv"&gt;userActivity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;NSUserActivity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;RCTLinkingManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;UIApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                  &lt;span class="nv"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;userActivity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                  &lt;span class="nv"&gt;restorationHandler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;in&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;Also read &lt;code&gt;connectionOptions.urlContexts&lt;/code&gt; in &lt;code&gt;willConnectTo&lt;/code&gt; for cold starts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 4: Expo
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SDK 58&lt;/strong&gt; (in beta since mid-September) is reported to generate the scene delegate by default.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SDK 57&lt;/strong&gt; can opt in. It needs &lt;code&gt;expo&lt;/code&gt; 57.0.23+ and &lt;code&gt;expo-build-properties&lt;/code&gt; 57.0.20+:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"expo-build-properties"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"ios"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"enableSceneSupport"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then regenerate the native 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 prebuild &lt;span class="nt"&gt;--clean&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SDK 56 and earlier&lt;/strong&gt; need an SDK upgrade first.&lt;/li&gt;
&lt;li&gt;If your &lt;code&gt;ios/&lt;/code&gt; folder is generated by prebuild and the template still creates the window in &lt;code&gt;didFinishLaunching&lt;/code&gt;, one team solved it durably with a small config plugin that applies the two changes on every prebuild, rather than hand-editing a folder that gets regenerated.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Fix 5: Other stacks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;.NET MAUI.&lt;/strong&gt; Add &lt;code&gt;Platforms/iOS/SceneDelegate.cs&lt;/code&gt; deriving from &lt;code&gt;MauiUISceneDelegate&lt;/code&gt; (registered as &lt;code&gt;SceneDelegate&lt;/code&gt;), and add the scene manifest to every iOS &lt;code&gt;Info.plist&lt;/code&gt;, using the configuration name &lt;code&gt;__MAUI_DEFAULT_SCENE_CONFIGURATION__&lt;/code&gt;. Templates from MAUI 10.0.110 (22 Sept 2026) include this. Older projects don't get it automatically, so upgrading the package alone does not fix an existing app. Don't forget every flavor-specific plist.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cordova.&lt;/strong&gt; &lt;code&gt;cordova-ios&lt;/code&gt; 8.1.1 apps built with Xcode 27 are reported to show a blank screen and the same error. Track the open issue in &lt;code&gt;apache/cordova-ios&lt;/code&gt; (#1725) and update the platform and any plugins that inject windows into the app delegate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tauri / Dioxus.&lt;/strong&gt; Release builds with a scene manifest crashed until a fix in &lt;code&gt;tao&lt;/code&gt;, reported as shipped in &lt;code&gt;tao&lt;/code&gt; 0.37.0. Update the dependency and regenerate the iOS project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flutter and native plugins.&lt;/strong&gt; One vendor reported an &lt;code&gt;EXC_BAD_ACCESS&lt;/code&gt; near &lt;code&gt;GeneratedPluginRegistrant.register(with:)&lt;/code&gt; after adopting scenes, caused by plugin code that expected registrar setup in the app delegate. If you use Flutter, check your Flutter version's iOS scene guidance and update plugins that handle deep links.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Third-party SDKs.&lt;/strong&gt; Some vendors ship separate SDK lines per Xcode major version (for example Microsoft's Intune SDK has a release line for Xcode 26 and a different one for Xcode 16). Check your SDKs' release notes before switching toolchains.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Fix 6: Stay on Xcode 26 for now (a stopgap, not a plan)
&lt;/h2&gt;

&lt;p&gt;If you can't migrate this week, keep production builds on the toolchain that works. One open-source team fixed a TestFlight launch crash on iOS 27.2 by pinning their store builds to Xcode 26.6, after confirming the working build was linked against the iOS 26.5 SDK.&lt;/p&gt;

&lt;p&gt;In practice that means:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pin Xcode 26.6 on your CI image (for EAS, a &lt;code&gt;macos-tahoe-26.5-xcode-26.6&lt;/code&gt; image).&lt;/li&gt;
&lt;li&gt;Keep a separate lane that builds with Xcode 27 so you find breakage early.&lt;/li&gt;
&lt;li&gt;Check your build's SDK: the &lt;code&gt;DTXcode&lt;/code&gt; and &lt;code&gt;DTSDKName&lt;/code&gt; keys in the built &lt;code&gt;Info.plist&lt;/code&gt; tell you which SDK produced it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A reported deadline makes this temporary: Apple is said to have announced that from April 2027, apps uploaded to App Store Connect must be built with the iOS 27 SDK. I could not confirm that on Apple's own pages, so verify it in your App Store Connect announcements before planning around it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 7: Other Xcode 27 issues you may hit in the same upgrade
&lt;/h2&gt;

&lt;p&gt;These are build-time or tooling problems rather than the launch crash, but they tend to show up together:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deployment target errors.&lt;/strong&gt; Xcode 27 rejects pods declaring an &lt;code&gt;IPHONEOS_DEPLOYMENT_TARGET&lt;/code&gt; below 15.0. A common fix is a &lt;code&gt;post_install&lt;/code&gt; hook in your &lt;code&gt;Podfile&lt;/code&gt; that raises the target for offending pods.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No &lt;code&gt;Simulator.app&lt;/code&gt;.&lt;/strong&gt; One report says Xcode 27 no longer ships &lt;code&gt;Simulator.app&lt;/code&gt; (it ships &lt;code&gt;DeviceHub.app&lt;/code&gt;), which broke &lt;code&gt;expo run:ios&lt;/code&gt; on older &lt;code&gt;@expo/cli&lt;/code&gt; versions. Update your CLI tooling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stale build data.&lt;/strong&gt; After toolchain changes, clear it: &lt;code&gt;rm -rf ~/Library/Developer/Xcode/DerivedData/*&lt;/code&gt; and rebuild.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Beta-era dyld crashes.&lt;/strong&gt; If your app dies before any Swift runs on an iOS 27 beta device, it can be a third-party framework symbol issue rather than scenes. Update the dependency and file a Feedback report.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A checklist you can paste into a ticket
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Confirm the crash: &lt;code&gt;NoSceneLifecycleAdoption&lt;/code&gt; in the report.&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;UIApplicationSceneManifest&lt;/code&gt; with a scene configuration to &lt;strong&gt;every&lt;/strong&gt; &lt;code&gt;Info.plist&lt;/code&gt; (all flavors).&lt;/li&gt;
&lt;li&gt;Add a &lt;code&gt;SceneDelegate&lt;/code&gt; that creates the window; remove window creation from the app delegate.&lt;/li&gt;
&lt;li&gt;Move &lt;code&gt;applicationDidBecomeActive&lt;/code&gt; and friends to the scene equivalents.&lt;/li&gt;
&lt;li&gt;Move URL and user-activity handling to the scene delegate; handle cold-start links from &lt;code&gt;connectionOptions&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Audit dependencies for &lt;code&gt;delegate.window&lt;/code&gt; and similar app-delegate assumptions.&lt;/li&gt;
&lt;li&gt;Delete DerivedData, rebuild with Xcode 27.&lt;/li&gt;
&lt;li&gt;Test on an &lt;strong&gt;iOS 27&lt;/strong&gt; simulator or device. An iOS 26 device will not show the problem.&lt;/li&gt;
&lt;li&gt;Test deep links, push taps and every picker/ad/menu that presents UI, from both warm and cold starts.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;The takeaway is less "old Xcode breaks on iOS 27" and more "the moment you move to Xcode 27, Apple's long-announced scene requirement becomes an assert". The fix itself is small, the follow-on regressions (deep links, window-dependent startup, third-party libraries) are where the time goes, so adopt scenes while you're still on Xcode 26, ship it, and then upgrade the toolchain.&lt;/p&gt;

&lt;p&gt;If you've hit a variant I didn't cover, tell me in the comments and I'll add it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Apple, &lt;a href="https://developer.apple.com/documentation/technotes/tn3187-migrating-to-the-uikit-scene-based-life-cycle" rel="noopener noreferrer"&gt;TN3187: Migrating to the UIKit scene-based life cycle&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Apple, iOS &amp;amp; iPadOS 27 Release Notes (UIKit deprecations)&lt;/li&gt;
&lt;li&gt;Dan Ardelean, &lt;a href="https://dev.to/danardelean/your-net-maui-ios-app-will-crash-at-launch-with-xcode-27-here-is-the-two-file-fix-mlm"&gt;.NET MAUI crash at launch with Xcode 27&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Alican Akyol, &lt;a href="https://dev.to/keel_alican_akyol/xcode-27-wont-launch-93-of-react-native-apps-the-uiscene-change-and-the-libraries-that-crash-2gb5"&gt;Xcode 27 won't launch 93% of React Native apps&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@dgond0003/expo-sdk-57-xcode-27-ios-27-fix-app-crash-on-launch-with-scene-lifecycle-953e9721eca6" rel="noopener noreferrer"&gt;Expo SDK 57 + Xcode 27 scene lifecycle fix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/apache/cordova-ios/issues/1725" rel="noopener noreferrer"&gt;apache/cordova-ios #1725&lt;/a&gt;, &lt;a href="https://github.com/DioxusLabs/dioxus/issues/5853" rel="noopener noreferrer"&gt;DioxusLabs/dioxus #5853&lt;/a&gt;, &lt;a href="https://github.com/multica-ai/multica/issues/8447" rel="noopener noreferrer"&gt;multica-ai/multica #8447&lt;/a&gt; and &lt;a href="https://github.com/multica-ai/multica/issues/9025" rel="noopener noreferrer"&gt;#9025&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/mbeckm/workout-tracker/pull/129" rel="noopener noreferrer"&gt;mbeckm/workout-tracker PR #129&lt;/a&gt; (pinning to Xcode 26.6)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://help.airbridge.io/en/developers/troubleshooting-deprecated-flutter-sdk-v3" rel="noopener noreferrer"&gt;Airbridge SceneDelegate migration guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Found this helpful? Drop a ❤️ on the article!&lt;br&gt;
Questions or suggestions? Drop them in the comments below.&lt;/p&gt;

&lt;p&gt;Feel free to reach out:&lt;br&gt;
LinkedIn: &lt;a href="https://www.linkedin.com/in/rushikesh-pandit-646834100/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/rushikesh-pandit-646834100/&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/rushikeshpandit" rel="noopener noreferrer"&gt;https://github.com/rushikeshpandit&lt;/a&gt;&lt;br&gt;
Portfolio: &lt;a href="https://www.rushikeshpandit.in" rel="noopener noreferrer"&gt;https://www.rushikeshpandit.in&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;#ReactNative #MobileDevelopment #SoftwareEngineering #iOS #Swift #iOS27&lt;/p&gt;

</description>
      <category>ios</category>
      <category>swift</category>
      <category>reactnative</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Why every React Native upgrade takes longer than you estimated (and how to estimate honestly)</title>
      <dc:creator>Rushikesh Pandit</dc:creator>
      <pubDate>Tue, 13 Oct 2026 14:43:03 +0000</pubDate>
      <link>https://dev.to/rushikeshpandit/why-every-react-native-upgrade-takes-longer-than-you-estimated-and-how-to-estimate-honestly-26en</link>
      <guid>https://dev.to/rushikeshpandit/why-every-react-native-upgrade-takes-longer-than-you-estimated-and-how-to-estimate-honestly-26en</guid>
      <description>&lt;p&gt;Almost every React Native upgrade I've worked on was estimated in days and delivered in weeks.&lt;br&gt;
It's not that engineers estimate badly. It's that the estimate usually covers the wrong thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we usually estimate
&lt;/h2&gt;

&lt;p&gt;"Bump &lt;code&gt;react-native&lt;/code&gt;, fix whatever the Upgrade Helper diff says, run the app."&lt;br&gt;
That's the visible part of the work. The &lt;a href="https://react-native-community.github.io/upgrade-helper/" rel="noopener noreferrer"&gt;React Native Upgrade Helper&lt;/a&gt;&lt;br&gt;
is excellent at it: it shows the file-by-file changes between two versions of a fresh template.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually takes the time
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Native dependencies.&lt;/strong&gt; Every library with an &lt;code&gt;ios/&lt;/code&gt; or &lt;code&gt;android/&lt;/code&gt; folder is a separate upgrade inside your upgrade. Each has its own compatibility story, maintainers and release cadence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Toolchain coupling.&lt;/strong&gt; A React Native bump can pull in new requirements for Xcode, the Android Gradle Plugin, the JDK or Node. These fail late, in CI, on someone else's machine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Template drift.&lt;/strong&gt; Your project's native files stopped matching the template years ago. A diff against a clean template can't know about your custom changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Architecture changes.&lt;/strong&gt; Newer React Native versions change defaults (for example around the New Architecture). Libraries that never adopted the new model become blockers. Check the release notes of your target version for the current state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unknown unknowns.&lt;/strong&gt; Abandoned packages, patched dependencies (&lt;code&gt;patch-package&lt;/code&gt;) and forks.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  A more honest estimate in four steps
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Count native dependencies.&lt;/strong&gt; The number matters more than total dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Classify each one:&lt;/strong&gt; actively maintained / slow / abandoned, and "known compatible with the target version" / "unknown" / "known broken".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do a time-boxed dry run&lt;/strong&gt; on a throwaway branch: bump, install, build iOS and Android, record every failure. Stop after a fixed time (say a day).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Estimate from the dry run:&lt;/strong&gt; your known failures plus a buffer proportional to the unknown count.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Give stakeholders a risk range, not a date
&lt;/h2&gt;

&lt;p&gt;"Two weeks if three unknown dependencies behave, five if they don't" is more useful and more honest than a single number. It also tells your manager where the risk is.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm building
&lt;/h2&gt;

&lt;p&gt;I'm working on a tool, &lt;strong&gt;rn-upgrade-doctor&lt;/strong&gt;, that automates steps 1 and 2 and produces a project-specific risk report. The CLI goes public on 20 Oct. If you want early access: [&lt;a href="https://rnupgradedoctor.dev" rel="noopener noreferrer"&gt;https://rnupgradedoctor.dev&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;What was the worst upgrade estimate you ever got wrong? I'd love to hear it in the comments.&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>mobile</category>
      <category>javascript</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Building a Native QR/Barcode Scanner for React Native — New Architecture Ready</title>
      <dc:creator>Rushikesh Pandit</dc:creator>
      <pubDate>Sat, 30 May 2026 09:25:44 +0000</pubDate>
      <link>https://dev.to/rushikeshpandit/building-a-native-qrbarcode-scanner-for-react-native-new-architecture-ready-mff</link>
      <guid>https://dev.to/rushikeshpandit/building-a-native-qrbarcode-scanner-for-react-native-new-architecture-ready-mff</guid>
      <description>&lt;p&gt;Most QR scanner libraries for React Native share the same problems — they're unmaintained, they don't support the New Architecture, or they pull in a full camera SDK for what is a single-feature module. I wanted something lean, production-grade, and built the right way. So I built it.&lt;/p&gt;

&lt;p&gt;This is &lt;code&gt;react-native-qr-camera-pro&lt;/code&gt; — a QR and barcode scanner for React Native built entirely with native code. No JavaScript frame processing. No unnecessary dependencies. Swift on iOS, Kotlin on Android, TurboModules and Fabric throughout.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Native-Only?
&lt;/h2&gt;

&lt;p&gt;The common alternative is running frame analysis in JavaScript — grabbing frames via a JS-accessible camera API and running a WASM or JS barcode decoder on them. It works, but it puts real pressure on the JS thread and limits your frame rate.&lt;/p&gt;

&lt;p&gt;With native-only processing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;iOS uses &lt;code&gt;AVCaptureMetadataOutput&lt;/code&gt; — Apple's own pipeline for detecting machine-readable codes. Frames are never copied to user space; the kernel hands off a reference to the same buffer.&lt;/li&gt;
&lt;li&gt;Android uses CameraX &lt;code&gt;ImageAnalysis&lt;/code&gt; + ML Kit — Google's on-device barcode scanner backed by hardware-accelerated inference where available.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The JS bridge is touched at most once every 500ms to deliver a result. Everything else stays native.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;The module is three layers:&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;The module is three layers, each with a single responsibility:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;JavaScript / TypeScript&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Public API — &lt;code&gt;QrCameraProView&lt;/code&gt;, &lt;code&gt;startScanning()&lt;/code&gt;, &lt;code&gt;stopScanning()&lt;/code&gt;, &lt;code&gt;toggleTorch()&lt;/code&gt;, &lt;code&gt;useBarcodeScanner()&lt;/code&gt;, &lt;code&gt;useCameraError()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Native Bridge (TurboModules + Fabric)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Type-safe JSI communication between JS and native. Codegen spec drives both the iOS C++ adapter and the Android Kotlin stub.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Native Platform (iOS + Android)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;All camera and barcode logic. AVFoundation on iOS, CameraX + ML Kit on Android. Zero JS involvement in frame processing.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  iOS (Swift)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Class&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;QrCameraProSwift&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Owns the &lt;code&gt;AVCaptureSession&lt;/code&gt; lifecycle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;BarcodeThrottler&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Throttle + dedup logic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;BarcodeTypeMapper&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Maps &lt;code&gt;AVMetadataObject.ObjectType&lt;/code&gt; → JS string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;QrCameraProView&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hosts &lt;code&gt;AVCaptureVideoPreviewLayer&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;QrCameraProViewManager&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Vends view instances to Fabric&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Android (Kotlin)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Class&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;QrCameraProModule&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Camera session lifecycle + event emission&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;BarcodeThrottler&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Throttle + dedup logic (same contract as iOS)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;BarcodeFormatMapper&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Maps ML Kit &lt;code&gt;FORMAT_*&lt;/code&gt; int → JS string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;BarcodeAnalyzer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CameraX frame analysis + ML Kit client&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;QrCameraProView&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hosts CameraX &lt;code&gt;PreviewView&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;QrCameraProViewManager&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Vends view instances to Fabric&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;TurboModules&lt;/strong&gt; handle all imperative calls (&lt;code&gt;startScanning&lt;/code&gt;, &lt;code&gt;stopScanning&lt;/code&gt;, &lt;code&gt;toggleTorch&lt;/code&gt;) and event emission (&lt;code&gt;onBarcodeScanned&lt;/code&gt;, &lt;code&gt;onCameraError&lt;/code&gt;) via JSI — no JSON serialisation, no async queue hop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fabric&lt;/strong&gt; handles the camera preview component. The preview surface (&lt;code&gt;AVCaptureVideoPreviewLayer&lt;/code&gt; on iOS, CameraX &lt;code&gt;PreviewView&lt;/code&gt; on Android) is a native sublayer that React Native sizes and positions. The preview frame rate is fully decoupled from the JS render cycle.&lt;/p&gt;




&lt;h2&gt;
  
  
  Threading
&lt;/h2&gt;

&lt;p&gt;Getting threads right is the most important part of a camera module.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;AVCaptureSession&lt;/code&gt; setup and &lt;code&gt;startRunning()&lt;/code&gt; run on a dedicated background &lt;code&gt;DispatchQueue&lt;/code&gt; — Apple's docs are explicit that &lt;code&gt;startRunning()&lt;/code&gt; blocks and must not run on the main thread&lt;/li&gt;
&lt;li&gt;Metadata callbacks run on &lt;code&gt;DispatchQueue.main&lt;/code&gt; — lightweight string reads, no extra context switch needed&lt;/li&gt;
&lt;li&gt;All &lt;code&gt;NotificationCenter&lt;/code&gt; posts to &lt;code&gt;QrCameraProView&lt;/code&gt; happen on main (UIKit requirement)&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bindToLifecycle&lt;/code&gt; runs on the UI thread (CameraX requirement)&lt;/li&gt;
&lt;li&gt;Frame analysis runs on a dedicated single-thread &lt;code&gt;ExecutorService&lt;/code&gt; — keeps the main thread clear&lt;/li&gt;
&lt;li&gt;ML Kit results are handled on the same executor thread before being forwarded to JS&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Scan Throttling
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;AVCaptureMetadataOutput&lt;/code&gt; and ML Kit can fire multiple times per second for a single held barcode. Forwarding every detection to JavaScript would saturate the bridge.&lt;/p&gt;

&lt;p&gt;Both platforms implement a &lt;code&gt;BarcodeThrottler&lt;/code&gt; that gates emissions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Same code within 500ms → suppressed&lt;/li&gt;
&lt;li&gt;Same code after 500ms → allowed (intentional re-scan)&lt;/li&gt;
&lt;li&gt;Different code → always allowed&lt;/li&gt;
&lt;li&gt;Throttle state resets on every &lt;code&gt;stopScanning()&lt;/code&gt; call&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The 500ms default keeps the bridge load minimal while remaining imperceptible to users.&lt;/p&gt;




&lt;h2&gt;
  
  
  The JS API
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Hooks
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Subscribe to scan results&lt;/span&gt;
&lt;span class="nf"&gt;useBarcodeScanner&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;barcode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Barcode&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;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="nx"&gt;barcode&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;barcode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Subscribe to camera errors&lt;/span&gt;
&lt;span class="nf"&gt;useCameraError&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CameraErrorEvent&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;Alert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Camera Error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&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;Both hooks subscribe once on mount and unsubscribe once on unmount — regardless of how many times the parent re-renders or passes a new callback reference. The latest callback is always called via a ref. This keeps the native listener count stable at 1 for the lifetime of the component.&lt;/p&gt;

&lt;h3&gt;
  
  
  Imperative API
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;startScanning&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;   &lt;span class="c1"&gt;// starts the session, requests permission on Android&lt;/span&gt;
&lt;span class="nf"&gt;stopScanning&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;    &lt;span class="c1"&gt;// stops the session, releases camera hardware&lt;/span&gt;
&lt;span class="nf"&gt;toggleTorch&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="c1"&gt;// torch on&lt;/span&gt;
&lt;span class="nf"&gt;toggleTorch&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="c1"&gt;// torch off&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Native view
&lt;/h3&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;QrCameraProView&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&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;Renders &lt;code&gt;AVCaptureVideoPreviewLayer&lt;/code&gt; on iOS and CameraX &lt;code&gt;PreviewView&lt;/code&gt; on Android. Style it like any other &lt;code&gt;View&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Supported Formats
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type string&lt;/th&gt;
&lt;th&gt;Format&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;QR_CODE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;QR Code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;EAN_8&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;EAN-8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;EAN_13&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;EAN-13&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PDF_417&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;PDF-417&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;AZTEC&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Aztec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CODE_128&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Code 128&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CODE_39&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Code 39&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CODE_93&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Code 93&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DATA_MATRIX&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Data Matrix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ITF&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Interleaved 2 of 5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ITF_14&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ITF-14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;UPC_E&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;UPC-E&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add react-native-qr-camera-pro
&lt;span class="c"&gt;# or&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;react-native-qr-camera-pro
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;iOS&lt;/strong&gt; — add to &lt;code&gt;Info.plist&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;NSCameraUsageDescription&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;$(PRODUCT_NAME) needs camera access to scan QR codes.&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then &lt;code&gt;cd ios &amp;amp;&amp;amp; pod install&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Android&lt;/strong&gt; — the &lt;code&gt;CAMERA&lt;/code&gt; permission is declared in the library manifest and merged automatically. No manual edits needed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Use Cases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Retail / inventory&lt;/strong&gt; — scan product barcodes for stock checks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event check-in&lt;/strong&gt; — verify QR-coded tickets at entry&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logistics&lt;/strong&gt; — track packages by scanning shipping labels&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Payments&lt;/strong&gt; — read QR codes for payment flows&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authentication&lt;/strong&gt; — QR-based 2FA or login&lt;/li&gt;
&lt;/ul&gt;




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

&lt;ul&gt;
&lt;li&gt;Scan region / viewfinder crop&lt;/li&gt;
&lt;li&gt;Scan success haptic feedback&lt;/li&gt;
&lt;li&gt;Expo plugin&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're building anything on React Native that needs reliable, fast barcode scanning without pulling in a full camera SDK — give it a try. Feedback welcome, especially from anyone hitting edge cases on specific devices or Android versions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/react-native-qr-camera-pro" rel="noopener noreferrer"&gt;npm Package&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/rushikeshpandit/react-native-qr-camera-pro" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/rushikeshpandit/react-native-qr-camera-pro/blob/master/README.md" rel="noopener noreferrer"&gt;Full Documentation&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/rushikeshpandit/react-native-qr-camera-pro/issues" rel="noopener noreferrer"&gt;Issue Tracker&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Found this helpful? Drop a ❤️ on the article and ⭐ on GitHub!&lt;br&gt;
Questions or suggestions? Drop them in the comments below.&lt;/p&gt;

&lt;p&gt;Feel free to reach out:&lt;br&gt;
LinkedIn: &lt;a href="https://www.linkedin.com/in/rushikesh-pandit-646834100/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/rushikesh-pandit-646834100/&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/rushikeshpandit" rel="noopener noreferrer"&gt;https://github.com/rushikeshpandit&lt;/a&gt;&lt;br&gt;
Portfolio: &lt;a href="https://www.rushikeshpandit.in" rel="noopener noreferrer"&gt;https://www.rushikeshpandit.in&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  ReactNative #TypeScript #MobileDevelopment #SoftwareEngineering #iOS #Android #Swift #Kotlin #OpenSource #TurboModules #CameraX #AVFoundation
&lt;/h1&gt;

</description>
      <category>reactnative</category>
      <category>mobile</category>
      <category>ios</category>
      <category>android</category>
    </item>
    <item>
      <title>Handling Sensitive UI Data in React Native: Practical Approaches Across iOS and Android</title>
      <dc:creator>Rushikesh Pandit</dc:creator>
      <pubDate>Tue, 31 Mar 2026 10:06:41 +0000</pubDate>
      <link>https://dev.to/rushikeshpandit/handling-sensitive-ui-data-in-react-native-practical-approaches-across-ios-and-android-41nk</link>
      <guid>https://dev.to/rushikeshpandit/handling-sensitive-ui-data-in-react-native-practical-approaches-across-ios-and-android-41nk</guid>
      <description>&lt;h1&gt;
  
  
  Handling Sensitive UI Data in React Native
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As mobile applications increasingly deal with sensitive user data—financial details, personal health information, authentication flows—UI-level privacy becomes a non-trivial concern.&lt;/p&gt;

&lt;p&gt;While backend security is well understood, protecting &lt;strong&gt;what’s visible on the screen&lt;/strong&gt; is often overlooked.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Core Problem
&lt;/h2&gt;

&lt;p&gt;Each platform handles screen privacy differently:&lt;/p&gt;

&lt;h3&gt;
  
  
  Android
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Uses &lt;code&gt;FLAG_SECURE&lt;/code&gt; to block screenshots and recordings
&lt;/li&gt;
&lt;li&gt;Requires &lt;code&gt;ContentObserver&lt;/code&gt; to detect screenshots
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  iOS
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;No direct API to block screenshots
&lt;/li&gt;
&lt;li&gt;Relies on &lt;code&gt;UITextField&lt;/code&gt; (&lt;code&gt;isSecureTextEntry&lt;/code&gt;) behavior
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Key Areas to Address
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Screen Capture Protection
&lt;/h3&gt;

&lt;p&gt;Android provides native support. iOS requires workaround techniques.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. App Switcher Snapshots
&lt;/h3&gt;

&lt;p&gt;Apps must hide sensitive data before going to background.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Screenshot Detection
&lt;/h3&gt;

&lt;p&gt;Detection is possible, prevention is limited.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Clipboard Management
&lt;/h3&gt;

&lt;p&gt;Sensitive data should be cleared proactively.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Copy/Paste Restrictions
&lt;/h3&gt;

&lt;p&gt;Needs native-level interception.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architectural Approach
&lt;/h2&gt;

&lt;p&gt;A scalable approach includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hooks for declarative usage
&lt;/li&gt;
&lt;li&gt;Imperative APIs for lifecycle control
&lt;/li&gt;
&lt;li&gt;View wrappers for sensitive UI
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Trade-offs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;iOS limitations on screenshot blocking
&lt;/li&gt;
&lt;li&gt;Android emulator bypasses
&lt;/li&gt;
&lt;li&gt;UX vs security balance
&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;UI privacy is a cross-platform engineering problem requiring thoughtful abstraction and careful handling of OS differences.&lt;/p&gt;

&lt;p&gt;If you're building anything in fintech, banking, or enterprise on React Native and want a lightweight security layer without pulling in a large SDK — give it a try.&lt;br&gt;
Feedback welcome, especially if you hit false positives on specific devices.&lt;/p&gt;

&lt;p&gt;Built with Swift, Kotlin, and C++. No external dependencies.&lt;/p&gt;

&lt;p&gt;Links:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/react-native-privacy-guard-kit" rel="noopener noreferrer"&gt;npm Package&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/rushikeshpandit/react-native-privacy-guard-kit" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/rushikeshpandit/react-native-privacy-guard-kit/blob/master/README.md" rel="noopener noreferrer"&gt;Full Documentation&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/rushikeshpandit/react-native-privacy-guard-kit/issues" rel="noopener noreferrer"&gt;Issue Tracker&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Found this helpful? Drop a ❤️ on the article and ⭐ on GitHub!&lt;br&gt;
Questions or suggestions? Drop them in the comments below! &lt;/p&gt;

&lt;p&gt;Feel free to reach out to me if you have any questions or need assistance.&lt;br&gt;
LinkedIn: &lt;a href="https://www.linkedin.com/in/rushikesh-pandit-646834100/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/rushikesh-pandit-646834100/&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/rushikeshpandit" rel="noopener noreferrer"&gt;https://github.com/rushikeshpandit&lt;/a&gt;&lt;br&gt;
Portfolio: &lt;a href="https://www.rushikeshpandit.in" rel="noopener noreferrer"&gt;https://www.rushikeshpandit.in&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;#ReactNative #TypeScript #MobileDevelopment #SoftwareEngineering #DevCommunity #root-detection #jailbreak-detection #mobile-security&lt;br&gt;
 #device-integrity&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>mobile</category>
      <category>security</category>
    </item>
    <item>
      <title>Detecting Rooted &amp; Jailbroken Devices in React Native — How I Built It and What I Learned</title>
      <dc:creator>Rushikesh Pandit</dc:creator>
      <pubDate>Sun, 08 Mar 2026 06:08:32 +0000</pubDate>
      <link>https://dev.to/rushikeshpandit/detecting-rooted-jailbroken-devices-in-react-native-how-i-built-it-and-what-i-learned-1jaa</link>
      <guid>https://dev.to/rushikeshpandit/detecting-rooted-jailbroken-devices-in-react-native-how-i-built-it-and-what-i-learned-1jaa</guid>
      <description>&lt;p&gt;I've been working on a React Native security library for the past few months. Not because there wasn't anything out there, but because most existing solutions were either outdated, not maintained, or didn't support the New Architecture.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;react-native-root-jail-detect&lt;/strong&gt; from scratch — native Swift for iOS, Kotlin + C++ for Android, full TurboModules and Fabric support.&lt;br&gt;
Here's what I learned building it.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Problem With Simple File Checks
&lt;/h2&gt;

&lt;p&gt;Most jailbreak detection libraries do something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;jailbreakPaths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"/Applications/Cydia.app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"/bin/bash"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;jailbreakPaths&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kt"&gt;FileManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fileExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;atPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$0&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 works — until it doesn't. &lt;code&gt;/bin/sh&lt;/code&gt; exists on stock iOS. &lt;code&gt;/var/log/syslog&lt;/code&gt; exists on non-jailbroken devices. And on the simulator, the entire macOS filesystem is exposed, so paths like &lt;code&gt;/usr/bin/ssh&lt;/code&gt; and &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt; all exist on a perfectly clean machine.&lt;/p&gt;

&lt;p&gt;The fix isn't just a better list of paths. It's knowing which paths are safe to check, where, and when.&lt;br&gt;
For the simulator I gate real-device-only checks behind:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="cp"&gt;#if targetEnvironment(simulator)&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="cp"&gt;#else&lt;/span&gt;
&lt;span class="c1"&gt;// actual checks&lt;/span&gt;
&lt;span class="cp"&gt;#endif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And paths like &lt;code&gt;/bin/bash&lt;/code&gt; only go into a &lt;code&gt;realDeviceOnlyPaths&lt;/code&gt; list that never runs on simulator.&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugger Detection Is Trickier Than It Looks
&lt;/h2&gt;

&lt;p&gt;There are four common approaches:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;sysctl P_TRACED — most reliable
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;kinfo_proc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;MemoryLayout&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;kinfo_proc&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Int32&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="kt"&gt;CTL_KERN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;KERN_PROC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;KERN_PROC_PID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;getpid&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sysctl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kp_proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;p_flag&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="kt"&gt;P_TRACED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Mach exception ports — catches LLDB specifically
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// If EXC_MASK_BREAKPOINT has a valid port registered,&lt;/span&gt;
&lt;span class="c1"&gt;// something is listening for breakpoints&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;task_get_exception_ports&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;mach_task_self_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nf"&gt;exception_mask_t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;EXC_MASK_BREAKPOINT&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;masks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;behaviors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flavors&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// Validate ports are not MACH_PORT_NULL — avoids false positives&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;ptrace TRACEME
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;ptrace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;PT_TRACE_ME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&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="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;errno&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kt"&gt;EPERM&lt;/span&gt;  &lt;span class="c1"&gt;// already being traced&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;ptrace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;PT_DETACH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;TracerPid on Android
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/proc/self/status"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEachLine&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"TracerPid:"&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="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substringAfter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toInt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&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;The gotcha I hit: when you run your app via Xcode on a real device, Xcode automatically attaches LLDB. No breakpoints needed — just running from Xcode is enough to trigger all three iOS checks. The fix is gating these behind &lt;code&gt;#if DEBUG&lt;/code&gt; or a custom build flag like &lt;code&gt;SECURITY_CHECKS_ENABLED&lt;/code&gt; that you only set on Release and Staging schemes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frida Detection
&lt;/h2&gt;

&lt;p&gt;Frida is the main tool attackers use to hook into running apps and bypass security checks. Detecting it has a few layers:&lt;/p&gt;

&lt;h3&gt;
  
  
  Loaded image scan:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&amp;lt;&lt;/span&gt;&lt;span class="nf"&gt;_dyld_image_count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;_dyld_get_image_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lowercased&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;name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"frida"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"gum-js"&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="kc"&gt;true&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;h3&gt;
  
  
  Symbol lookup:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;suspiciousSymbols&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"gum_js_loop"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"frida_agent_main"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"gum_script_backend_create"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;sym&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;suspiciousSymbols&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;dlsym&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;UnsafeMutableRawPointer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;bitPattern&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;sym&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&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;h3&gt;
  
  
  On Android — memory map scan:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ifstream&lt;/span&gt; &lt;span class="nf"&gt;maps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/proc/self/maps"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;getline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&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="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"frida"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;npos&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
        &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"gum-js"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;npos&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="nb"&gt;true&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;These only catch unobfuscated Frida. A determined attacker can rename the agent. But most script-kiddie level attacks use default Frida, and this catches those reliably.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Runtime Watchdog
&lt;/h2&gt;

&lt;p&gt;This was the most interesting part to build. File path checks and debugger checks at launch are good, but they miss a common attack pattern:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;App launches — device looks clean&lt;/li&gt;
&lt;li&gt;Attacker attaches Frida or LLDB after launch&lt;/li&gt;
&lt;li&gt;App never re-checks — attacker is in&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The watchdog solves this by running checks continuously on a background thread with randomized timing (±40% jitter to make it harder to predict and bypass):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;randomDelay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TimeInterval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;TimeInterval&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;jitter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.4&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="kt"&gt;TimeInterval&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;jitter&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="n"&gt;jitter&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;It also checks for timing gaps — if the loop stalls for more than &lt;code&gt;interval * 4&lt;/code&gt;, it's a signal that the process was paused (e.g. by a debugger hitting a breakpoint):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lastRun&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;interval&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;handleThreat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;detector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;detector&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;Three response modes depending on how aggressive you want to be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="kt"&gt;ProtectionMode&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;logOnly&lt;/span&gt;       &lt;span class="c1"&gt;// log and continue&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;throwException&lt;/span&gt; &lt;span class="c1"&gt;// crash with reason&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;terminate&lt;/span&gt;     &lt;span class="c1"&gt;// kill(getpid(), SIGKILL)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For most apps I'd recommend &lt;code&gt;logOnly&lt;/code&gt; in staging and &lt;code&gt;terminate&lt;/code&gt; in production.&lt;/p&gt;

&lt;p&gt;Method Swizzling Detection — What Didn't Work&lt;br&gt;
My first approach was checking if &lt;code&gt;UIViewController.viewDidLoad&lt;/code&gt;'s IMP pointed back to UIKit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ This doesn't work&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;imagePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lowercased&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="n"&gt;imagePath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"uikit"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Problem: &lt;code&gt;viewDidLoad&lt;/code&gt; is a Swift method. Its IMP can point to a Swift-to-ObjC thunk or a dispatch stub — neither resolves to a UIKit path via &lt;code&gt;dladdr&lt;/code&gt;. Every app that overrides viewDidLoad would trigger this.&lt;br&gt;
The fix is checking pure ObjC methods with stable, well-known IMPs instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ✅ This works&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="kt"&gt;AnyClass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;String&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="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;NSObject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;#selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;NSObject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;"libobjc"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;NSObject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;NSSelectorFromString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"respondsToSelector:"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;"libobjc"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;NSArray&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="k"&gt;#selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;getter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;NSArray&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;"corefounda"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="c1"&gt;// Verify each IMP resolves back to its expected binary via dladdr&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Usage
&lt;/h2&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-root-jail-detect
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;RootJailDetect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SecurityWatchdog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ProtectionMode&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-native-root-jail-detect&lt;/span&gt;&lt;span class="dl"&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 plaintext"&gt;&lt;code&gt;// One-shot check
const isCompromised = await RootJailDetect.isDeviceRooted();
const reasons = await RootJailDetect.getDetectionReasons();

// Continuous monitoring
SecurityWatchdog.start({
  intervalMs: 3000,
  mode: ProtectionMode.TERMINATE,
});

// Stop monitoring
SecurityWatchdog.stop();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;Certificate pinning integration&lt;/li&gt;
&lt;li&gt;Integrity check for the JS bundle itself&lt;/li&gt;
&lt;li&gt;Anti-tampering for the native binary&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're building anything in fintech, banking, or enterprise on React Native and want a lightweight security layer without pulling in a large SDK — give it a try.&lt;br&gt;
Feedback welcome, especially if you hit false positives on specific devices.&lt;/p&gt;

&lt;p&gt;Built with Swift, Kotlin, and C++. No external dependencies.&lt;/p&gt;

&lt;p&gt;Links:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/react-native-root-jail-detect" rel="noopener noreferrer"&gt;npm Package&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/rushikeshpandit/react-native-root-jail-detect" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/rushikeshpandit/react-native-root-jail-detect/blob/master/README.md" rel="noopener noreferrer"&gt;Full Documentation&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/rushikeshpandit/react-native-root-jail-detect/issues" rel="noopener noreferrer"&gt;Issue Tracker&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Found this helpful? Drop a ❤️ on the article and ⭐ on GitHub!&lt;br&gt;
Questions or suggestions? Drop them in the comments below! &lt;/p&gt;

&lt;p&gt;Feel free to reach out to me if you have any questions or need assistance.&lt;br&gt;
LinkedIn: &lt;a href="https://www.linkedin.com/in/rushikesh-pandit-646834100/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/rushikesh-pandit-646834100/&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/rushikeshpandit" rel="noopener noreferrer"&gt;https://github.com/rushikeshpandit&lt;/a&gt;&lt;br&gt;
Portfolio: &lt;a href="https://www.rushikeshpandit.in" rel="noopener noreferrer"&gt;https://www.rushikeshpandit.in&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;#ReactNative #TypeScript #MobileDevelopment #SoftwareEngineering #DevCommunity #root-detection #jailbreak-detection #mobile-security&lt;br&gt;
 #device-integrity&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>security</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Published a Lightweight Library for Root/Jailbreak Detection React Native</title>
      <dc:creator>Rushikesh Pandit</dc:creator>
      <pubDate>Sun, 22 Feb 2026 12:55:02 +0000</pubDate>
      <link>https://dev.to/rushikeshpandit/published-a-lightweight-library-for-rootjailbreak-detection-react-native-1eam</link>
      <guid>https://dev.to/rushikeshpandit/published-a-lightweight-library-for-rootjailbreak-detection-react-native-1eam</guid>
      <description>&lt;h2&gt;
  
  
  react-native-root-jail-detect
&lt;/h2&gt;

&lt;p&gt;Security is first thing in mobile app development, especially for banking, fintech, and enterprise applications. One critical security measure is detecting whether a device has been rooted (Android) or jailbroken (iOS). These compromised devices can expose your app to security vulnerabilities, data breaches, and unauthorized access.&lt;/p&gt;

&lt;p&gt;Today, I'm excited to share &lt;strong&gt;react-native-root-jail-detect&lt;/strong&gt; - a lightweight, open-source library that makes device security checks incredibly simple.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Another Root/Jailbreak Detection Library?
&lt;/h2&gt;

&lt;p&gt;When building security-focused React Native apps, I noticed most existing solutions were either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Too heavy (bloating app size)&lt;/li&gt;
&lt;li&gt;Performance-intensive&lt;/li&gt;
&lt;li&gt;Closed-source or poorly maintained&lt;/li&gt;
&lt;li&gt;Complex APIs requiring extensive setup&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wanted something different: simple, fast, tiny, and open source forever.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Makes This Special?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Incredibly Lightweight (~60KB)
&lt;/h3&gt;

&lt;p&gt;In a world where every kilobyte matters for app store optimization and user experience, this library weighs in at just ~60KB. That's smaller than most image assets in your app!&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;# Installation is a breeze&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;react-native-root-jail-detect
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Clean &amp;amp; Simple API
&lt;/h3&gt;

&lt;p&gt;Forget complex configurations. One method, one promise, one boolean result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;RootJailDetect&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-root-jail-detect&lt;/span&gt;&lt;span class="dl"&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;isCompromised&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;RootJailDetect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isDeviceRooted&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;isCompromised&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Handle accordingly - restrict features, show warning, etc.&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 it. No configuration files, no initialization, no complex setup.&lt;/p&gt;

&lt;h3&gt;
  
  
  New Architecture Ready
&lt;/h3&gt;

&lt;p&gt;Built from the ground up to support React Native's new architecture (Fabric and TurboModules). Future-proof your security implementation today.&lt;/p&gt;

&lt;h3&gt;
  
  
  Battle-Tested Detection Methods
&lt;/h3&gt;

&lt;p&gt;The library doesn't rely on a single detection method. Instead, it employs multiple techniques:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For Android (Root Detection)&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Binary file scanning (su, Superuser.apk, etc.)&lt;/li&gt;
&lt;li&gt;Runtime command execution attempts&lt;/li&gt;
&lt;li&gt;Multiple common root path checks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;For iOS (Jailbreak Detection)&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cydia and jailbreak app detection&lt;/li&gt;
&lt;li&gt;Restricted file system access attempts&lt;/li&gt;
&lt;li&gt;Sandbox integrity verification&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Real-World Usage Example
&lt;/h2&gt;

&lt;p&gt;Here's how you might integrate it into a banking app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useEffect, useState } from 'react';
import { Alert } from 'react-native';
import RootJailDetect from 'react-native-root-jail-detect';

const BankingApp = () =&amp;gt; {
  const [securityPassed, setSecurityPassed] = useState(false);

  useEffect(() =&amp;gt; {
    performSecurityCheck();
  }, []);

  const performSecurityCheck = async () =&amp;gt; {
    try {
      const isRooted = await RootJailDetect.isDeviceRooted();

      if (isRooted) {
        Alert.alert(
          'Security Alert',
          'Your device appears to be rooted/jailbroken. ' +
          'For your security, some features will be restricted.',
          [
            { text: 'Learn More', onPress: () =&amp;gt; openSecurityInfo() },
            { text: 'OK', style: 'cancel' }
          ]
        );
        setSecurityPassed(false);
      } else {
        setSecurityPassed(true);
      }
    } catch (error) {
      console.error('Security check failed:', error);
      // Handle gracefully - perhaps allow access but log the incident
      setSecurityPassed(true);
    }
  };

  if (!securityPassed) {
    return &amp;lt;RestrictedModeUI /&amp;gt;;
  }

  return &amp;lt;FullBankingFeatures /&amp;gt;;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Perfect Use Cases
&lt;/h2&gt;

&lt;p&gt;This library shines in applications requiring enhanced security:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Banking &amp;amp; Fintech Apps: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Protect transaction integrity&lt;/li&gt;
&lt;li&gt;Comply with financial regulations&lt;/li&gt;
&lt;li&gt;Prevent unauthorized access to accounts&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enterprise Applications &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enforce corporate security policies&lt;/li&gt;
&lt;li&gt;MDM compliance&lt;/li&gt;
&lt;li&gt;Protect confidential business data&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Healthcare Apps&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HIPAA compliance requirements&lt;/li&gt;
&lt;li&gt;Patient data protection&lt;/li&gt;
&lt;li&gt;Secure telehealth platforms&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Gaming Apps &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prevent cheating&lt;/li&gt;
&lt;li&gt;Protect in-app purchases&lt;/li&gt;
&lt;li&gt;Maintain fair gameplay&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;E-commerce &amp;amp; Payment Apps &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PCI-DSS compliance&lt;/li&gt;
&lt;li&gt;Secure payment processing&lt;/li&gt;
&lt;li&gt;Fraud prevention&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Important Considerations
&lt;/h2&gt;

&lt;p&gt;While this library is highly effective, it's important to understand its limitations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Not 100% Foolproof: Sophisticated concealment tools exist (RootCloak, Liberty, etc.)&lt;/li&gt;
&lt;li&gt;Part of Defense-in-Depth: Use alongside SSL pinning, code obfuscation, and server-side validation&lt;/li&gt;
&lt;li&gt;User Experience Matters: Don't alienate legitimate users with heavy-handed restrictions&lt;/li&gt;
&lt;li&gt;Keep Updated: Root/jailbreak methods evolve; regular updates are crucial&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Best Practices for Implementation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Graceful Degradation
&lt;/h3&gt;

&lt;p&gt;Don't immediately lock users out. Consider a tiered approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const handleRootedDevice = async () =&amp;gt; {
  const isRooted = await RootJailDetect.isDeviceRooted();

  if (isRooted) {
    // Tier 1: Show warning, allow basic features
    showSecurityWarning();

    // Tier 2: Disable sensitive features
    disableBiometricAuth();
    disableStoredPaymentMethods();

    // Tier 3: Require additional verification
    requireTwoFactorAuth();

    // Analytics: Log for fraud detection
    logSecurityEvent('rooted_device_detected');
  }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Combine with Other Security Measures
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const comprehensiveSecurityCheck = async () =&amp;gt; {
  const checks = await Promise.all([
    RootJailDetect.isDeviceRooted(),
    checkSSLPinning(),
    validateAppIntegrity(),
    verifyDebuggerAbsence()
  ]);

  return checks.every(check =&amp;gt; check === true);
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Server-Side Validation
&lt;/h3&gt;

&lt;p&gt;Never rely solely on client-side checks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const authenticateWithSecurityCheck = async (credentials) =&amp;gt; {
  const isRooted = await RootJailDetect.isDeviceRooted();

  // Send security status to backend
  const response = await fetch('/api/auth', {
    method: 'POST',
    body: JSON.stringify({
      ...credentials,
      deviceSecurity: {
        isRooted,
        deviceId: getDeviceId(),
        appIntegrity: getAppSignature()
      }
    })
  });

  // Server makes final decision on access
  return response.json();
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Open Source Forever
&lt;/h2&gt;

&lt;p&gt;This project is and will always remain 100% open source under the MIT license. Why?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Transparency: Security through obscurity doesn't work&lt;/li&gt;
&lt;li&gt;Community: Better detection methods emerge from collaborative effort&lt;/li&gt;
&lt;li&gt;Trust: You can audit every line of code&lt;/li&gt;
&lt;li&gt;Innovation: Fork it, modify it, contribute back&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every contribution, no matter how small, makes a difference!&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Started Today
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Install
npm install react-native-root-jail-detect

# iOS
cd ios &amp;amp;&amp;amp; pod install &amp;amp;&amp;amp; cd ..

# Use
import RootJailDetect from 'react-native-root-jail-detect';
const isRooted = await RootJailDetect.isDeviceRooted();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Building secure mobile apps doesn't have to be complicated or expensive. With react-native-root-jail-detect, you get enterprise-grade security detection in a package smaller than a thumbnail image.&lt;/p&gt;

&lt;p&gt;Whether you're building the next fintech unicorn or a simple app that handles sensitive data, this library provides the peace of mind that comes with knowing your users' device integrity.&lt;/p&gt;

&lt;p&gt;Give it a try, star the repo, and join me in making React Native apps more secure for everyone!&lt;/p&gt;

&lt;p&gt;Links:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/react-native-root-jail-detect" rel="noopener noreferrer"&gt;npm Package&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/rushikeshpandit/react-native-root-jail-detect" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/rushikeshpandit/react-native-root-jail-detect/blob/master/README.md" rel="noopener noreferrer"&gt;Full Documentation&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/rushikeshpandit/react-native-root-jail-detect/issues" rel="noopener noreferrer"&gt;Issue Tracker&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Found this helpful? Drop a ❤️ on the article and ⭐ on GitHub!&lt;br&gt;
Questions or suggestions? Drop them in the comments below! &lt;/p&gt;

&lt;p&gt;Feel free to reach out to me if you have any questions or need assistance.&lt;br&gt;
LinkedIn: &lt;a href="https://www.linkedin.com/in/rushikesh-pandit-646834100/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/rushikesh-pandit-646834100/&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/rushikeshpandit" rel="noopener noreferrer"&gt;https://github.com/rushikeshpandit&lt;/a&gt;&lt;br&gt;
Portfolio: &lt;a href="https://www.rushikeshpandit.in" rel="noopener noreferrer"&gt;https://www.rushikeshpandit.in&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;#ReactNative #TypeScript #MobileDevelopment #SoftwareEngineering #DevCommunity #root-detection #jailbreak-detection #mobile-security&lt;br&gt;
 #device-integrity&lt;/p&gt;

</description>
      <category>mobile</category>
      <category>reactnative</category>
      <category>typescript</category>
      <category>npm</category>
    </item>
    <item>
      <title>Mastering React Native with TypeScript: From Basics to Brilliance - Part 3</title>
      <dc:creator>Rushikesh Pandit</dc:creator>
      <pubDate>Sat, 02 Aug 2025 15:03:53 +0000</pubDate>
      <link>https://dev.to/rushikeshpandit/mastering-react-native-with-typescript-from-basics-to-brilliance-part-3-p0m</link>
      <guid>https://dev.to/rushikeshpandit/mastering-react-native-with-typescript-from-basics-to-brilliance-part-3-p0m</guid>
      <description>&lt;p&gt;React Native has come a long way, and with the latest versions offering improved performance and TypeScript-first development, it’s a great time to dive into building robust apps with navigation and API communication in mind.&lt;br&gt;
In this article, we’ll explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setting up React Navigation in a TypeScript project&lt;/li&gt;
&lt;li&gt;Working with Stacks and Tabs&lt;/li&gt;
&lt;li&gt;Managing API calls with &lt;code&gt;axios&lt;/code&gt; and &lt;code&gt;useEffect&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Handling loading, error, and data states&lt;/li&gt;
&lt;li&gt;Bonus: Tips for organizing your codebase!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Node.js 18+&lt;/li&gt;
&lt;li&gt;React Native CLI or Expo (we'll go with bare React Native here)&lt;/li&gt;
&lt;li&gt;React Native 0.76+&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;Basic understanding of React Native components&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Setup React Navigation
&lt;/h2&gt;

&lt;p&gt;First, install the required dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @react-navigation/native
npm install react-native-screens react-native-safe-area-context react-native-gesture-handler react-native-reanimated
npx pod-install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then install the stack and bottom tab navigators:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @react-navigation/native-stack @react-navigation/bottom-tabs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update &lt;code&gt;babel.config.js&lt;/code&gt; for reanimated (if not Expo):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {
  presets: ['module:metro-react-native-babel-preset'],
  plugins: ['react-native-reanimated/plugin'],
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create Navigation Structure
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;navigation/RootNavigator.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import HomeScreen from '../screens/HomeScreen';
import DetailsScreen from '../screens/DetailsScreen';

export type RootStackParamList = {
  Home: undefined;
  Details: { userId: number };
};

const Stack = createNativeStackNavigator&amp;lt;RootStackParamList&amp;gt;();

const RootNavigator = () =&amp;gt; (
  &amp;lt;NavigationContainer&amp;gt;
    &amp;lt;Stack.Navigator initialRouteName="Home"&amp;gt;
      &amp;lt;Stack.Screen name="Home" component={HomeScreen} /&amp;gt;
      &amp;lt;Stack.Screen name="Details" component={DetailsScreen} /&amp;gt;
    &amp;lt;/Stack.Navigator&amp;gt;
  &amp;lt;/NavigationContainer&amp;gt;
);

export default RootNavigator;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create Screen Components for Home Screen
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;screens/HomeScreen.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useEffect, useState } from 'react';
import { View, Text, Button, FlatList, ActivityIndicator } from 'react-native';
import axios from 'axios';
import { NativeStackScreenProps } from '@react-navigation/native-stack';
import { RootStackParamList } from '../navigation/RootNavigator';

type Props = NativeStackScreenProps&amp;lt;RootStackParamList, 'Home'&amp;gt;;

interface User {
  id: number;
  name: string;
}

const HomeScreen: React.FC&amp;lt;Props&amp;gt; = ({ navigation }) =&amp;gt; {
  const [users, setUsers] = useState&amp;lt;User[]&amp;gt;([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState&amp;lt;string | null&amp;gt;(null);

  useEffect(() =&amp;gt; {
    axios.get&amp;lt;User[]&amp;gt;('https://jsonplaceholder.typicode.com/users')
      .then(response =&amp;gt; setUsers(response.data))
      .catch(err =&amp;gt; setError(err.message))
      .finally(() =&amp;gt; setLoading(false));
  }, []);

  if (loading) return &amp;lt;ActivityIndicator /&amp;gt;;
  if (error) return &amp;lt;Text&amp;gt;Error: {error}&amp;lt;/Text&amp;gt;;

  return (
    &amp;lt;FlatList
      data={users}
      keyExtractor={item =&amp;gt; item.id.toString()}
      renderItem={({ item }) =&amp;gt; (
        &amp;lt;View style={{ padding: 10 }}&amp;gt;
          &amp;lt;Text&amp;gt;{item.name}&amp;lt;/Text&amp;gt;
          &amp;lt;Button
            title="View Details"
            onPress={() =&amp;gt; navigation.navigate('Details', { userId: item.id })}
          /&amp;gt;
        &amp;lt;/View&amp;gt;
      )}
    /&amp;gt;
  );
};

export default HomeScreen;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create Screen Components for Detail Screen
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;screens/DetailsScreen.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useEffect, useState } from 'react';
import { View, Text, ActivityIndicator } from 'react-native';
import { NativeStackScreenProps } from '@react-navigation/native-stack';
import axios from 'axios';
import { RootStackParamList } from '../navigation/RootNavigator';

type Props = NativeStackScreenProps&amp;lt;RootStackParamList, 'Details'&amp;gt;;

interface UserDetail {
  id: number;
  name: string;
  email: string;
  phone: string;
}

const DetailsScreen: React.FC&amp;lt;Props&amp;gt; = ({ route }) =&amp;gt; {
  const { userId } = route.params;
  const [user, setUser] = useState&amp;lt;UserDetail | null&amp;gt;(null);
  const [loading, setLoading] = useState(true);

  useEffect(() =&amp;gt; {
    axios.get&amp;lt;UserDetail&amp;gt;(`https://jsonplaceholder.typicode.com/users/${userId}`)
      .then(response =&amp;gt; setUser(response.data))
      .finally(() =&amp;gt; setLoading(false));
  }, [userId]);

  if (loading) return &amp;lt;ActivityIndicator /&amp;gt;;
  if (!user) return &amp;lt;Text&amp;gt;No user found&amp;lt;/Text&amp;gt;;

  return (
    &amp;lt;View style={{ padding: 20 }}&amp;gt;
      &amp;lt;Text style={{ fontSize: 18 }}&amp;gt;{user.name}&amp;lt;/Text&amp;gt;
      &amp;lt;Text&amp;gt;{user.email}&amp;lt;/Text&amp;gt;
      &amp;lt;Text&amp;gt;{user.phone}&amp;lt;/Text&amp;gt;
    &amp;lt;/View&amp;gt;
  );
};

export default DetailsScreen;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Organize API Layer (Optional but Recommended)
&lt;/h2&gt;

&lt;p&gt;Create a file &lt;code&gt;api/client.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import axios from 'axios';

const client = axios.create({
  baseURL: 'https://jsonplaceholder.typicode.com/',
  timeout: 5000,
});

export default client;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then import and use &lt;code&gt;client.get()&lt;/code&gt; instead of &lt;code&gt;axios.get()&lt;/code&gt;.&lt;/p&gt;

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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/src
  /navigation
    RootNavigator.tsx
  /screens
    HomeScreen.tsx
    DetailsScreen.tsx
  /api
    client.ts
  /types
    index.ts
App.tsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;React Navigation’s TypeScript support makes route safety a breeze.&lt;/li&gt;
&lt;li&gt;Centralizing API calls helps scale and debug faster.&lt;/li&gt;
&lt;li&gt;Handling loading/error/data states improves user experience.&lt;/li&gt;
&lt;li&gt;Organize your folders early—it pays off later!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's it for today. In the next part of this series, we’ll explore advanced topics like redux toolkit and it's implementation.&lt;/p&gt;

&lt;p&gt;Feel free to reach out to me if you have any questions or need assistance.&lt;br&gt;
LinkedIn: &lt;a href="https://www.linkedin.com/in/rushikesh-pandit-646834100/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/rushikesh-pandit-646834100/&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/rushikeshpandit" rel="noopener noreferrer"&gt;https://github.com/rushikeshpandit&lt;/a&gt;&lt;br&gt;
Portfolio: &lt;a href="https://www.rushikeshpandit.in" rel="noopener noreferrer"&gt;https://www.rushikeshpandit.in&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;#ReactNative #TypeScript #MobileDevelopment #SoftwareEngineering #DevCommunity&lt;/p&gt;

</description>
      <category>mobile</category>
      <category>reactnative</category>
      <category>typescript</category>
      <category>programming</category>
    </item>
    <item>
      <title>Mastering React Native with TypeScript: From Basics to Brilliance - Part 2</title>
      <dc:creator>Rushikesh Pandit</dc:creator>
      <pubDate>Sat, 26 Jul 2025 07:21:13 +0000</pubDate>
      <link>https://dev.to/rushikeshpandit/mastering-react-native-with-typescript-from-basics-to-brilliance-part-2-16fa</link>
      <guid>https://dev.to/rushikeshpandit/mastering-react-native-with-typescript-from-basics-to-brilliance-part-2-16fa</guid>
      <description>&lt;p&gt;React Native hooks provide an intuitive way to manage state and side effects in your components. Introduced in React 16.8, hooks allow us to use state and other React features without writing class components, making functional components powerful and more readable.&lt;/p&gt;

&lt;p&gt;In this article, we will explore the most commonly used hooks, how they work, and how you can leverage them in your React Native projects. We’ll also look at how to create custom hooks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Hooks?
&lt;/h3&gt;

&lt;p&gt;Hooks are functions that let you “hook into” React state and lifecycle features from function components. They make your code cleaner, easier to understand, and reusable.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;useState&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;useState&lt;/code&gt; is one of the most commonly used hooks. It lets you add state to functional components. With &lt;code&gt;useState&lt;/code&gt;, you can create variables that store component-level data and re-render your component whenever that data changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState } from 'react';
import { Text, Button, View } from 'react-native';

const Counter = () =&amp;gt; {
  const [count, setCount] = useState&amp;lt;number&amp;gt;(0);

  return (
    &amp;lt;View&amp;gt;
      &amp;lt;Text&amp;gt;Count: {count}&amp;lt;/Text&amp;gt;
      &amp;lt;Button title="Increase" onPress={() =&amp;gt; setCount(count + 1)} /&amp;gt;
    &amp;lt;/View&amp;gt;
  );
};

export default Counter;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How it works:
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;useState&lt;/code&gt; takes the initial value (0 in the example) and returns an array containing the current value (&lt;code&gt;count&lt;/code&gt;) and a function to update it (&lt;code&gt;setCount&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;useEffect&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;useEffect&lt;/code&gt; is used to perform side effects in function components. It runs after every render by default but can also be customized to run only when specific values change.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState, useEffect } from 'react';
import { Text, View } from 'react-native';

const DataFetcher = () =&amp;gt; {
  const [data, setData] = useState&amp;lt;string | null&amp;gt;(null);

  useEffect(() =&amp;gt; {
    // Simulate fetching data from an API
    const fetchData = async () =&amp;gt; {
      const result = await new Promise((resolve) =&amp;gt; 
        setTimeout(() =&amp;gt; resolve("Fetched Data"), 2000)
      );
      setData(result as string);
    };

    fetchData();
  }, []); // empty array ensures this runs once when the component mounts

  return &amp;lt;View&amp;gt;{data ? &amp;lt;Text&amp;gt;{data}&amp;lt;/Text&amp;gt; : &amp;lt;Text&amp;gt;Loading...&amp;lt;/Text&amp;gt;}&amp;lt;/View&amp;gt;;
};

export default DataFetcher;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How it works:
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;useEffect&lt;/code&gt; runs after the component renders. In this case, we simulate fetching data, and the effect only runs once because of the empty dependency array &lt;code&gt;[]&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;useContext&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;useContext&lt;/code&gt; allows you to use values from React's Context API. This is helpful for passing data like theme or authentication information without prop drilling.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { createContext, useContext } from 'react';
import { Text, View } from 'react-native';

// Create a context
const ThemeContext = createContext('light');

const ThemedComponent = () =&amp;gt; {
  const theme = useContext(ThemeContext);
  return &amp;lt;Text&amp;gt;Current Theme: {theme}&amp;lt;/Text&amp;gt;;
};

const App = () =&amp;gt; (
  &amp;lt;ThemeContext.Provider value="dark"&amp;gt;
    &amp;lt;View&amp;gt;
      &amp;lt;ThemedComponent /&amp;gt;
    &amp;lt;/View&amp;gt;
  &amp;lt;/ThemeContext.Provider&amp;gt;
);

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How it works:
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;useContext&lt;/code&gt; allows you to consume the value of the nearest &lt;code&gt;ThemeContext.Provider&lt;/code&gt;, eliminating the need to pass down props manually.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;useReducer&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;useReducer&lt;/code&gt; is similar to &lt;code&gt;useState&lt;/code&gt; but is used for more complex state logic. It is often used when the state has multiple transitions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useReducer } from 'react';
import { Text, Button, View } from 'react-native';

type Action = { type: 'increment' | 'decrement' };
const reducer = (state: number, action: Action) =&amp;gt; {
  switch (action.type) {
    case 'increment':
      return state + 1;
    case 'decrement':
      return state - 1;
    default:
      return state;
  }
};

const Counter = () =&amp;gt; {
  const [count, dispatch] = useReducer(reducer, 0);

  return (
    &amp;lt;View&amp;gt;
      &amp;lt;Text&amp;gt;Count: {count}&amp;lt;/Text&amp;gt;
      &amp;lt;Button title="Increase" onPress={() =&amp;gt; dispatch({ type: 'increment' })} /&amp;gt;
      &amp;lt;Button title="Decrease" onPress={() =&amp;gt; dispatch({ type: 'decrement' })} /&amp;gt;
    &amp;lt;/View&amp;gt;
  );
};

export default Counter;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How it works:
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;useReducer&lt;/code&gt; takes a reducer function and an initial state, returning the current state and a &lt;code&gt;dispatch&lt;/code&gt; function to trigger state changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;useCallback&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;useCallback&lt;/code&gt; is used to memoize functions so they aren’t recreated on every render, which can be useful for optimization in child components.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState, useCallback } from 'react';
import { Text, Button, View } from 'react-native';

const ChildComponent = React.memo(({ onClick }: { onClick: () =&amp;gt; void }) =&amp;gt; (
  &amp;lt;Button title="Click me" onPress={onClick} /&amp;gt;
));

const ParentComponent = () =&amp;gt; {
  const [count, setCount] = useState(0);

  const increment = useCallback(() =&amp;gt; {
    setCount((prev) =&amp;gt; prev + 1);
  }, []); // Function is memoized, won't recreate unless dependencies change

  return (
    &amp;lt;View&amp;gt;
      &amp;lt;Text&amp;gt;Count: {count}&amp;lt;/Text&amp;gt;
      &amp;lt;ChildComponent onClick={increment} /&amp;gt;
    &amp;lt;/View&amp;gt;
  );
};

export default ParentComponent;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How it works:
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;useCallback&lt;/code&gt; returns a memoized version of the &lt;code&gt;increment&lt;/code&gt; function, ensuring it is not recreated unless dependencies change.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;useMemo&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;useMemo&lt;/code&gt; is used to memoize values instead of functions. It recalculates the value only when dependencies change, improving performance in expensive calculations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useMemo, useState } from 'react';
import { Text, Button, View } from 'react-native';

const ExpensiveComponent = () =&amp;gt; {
  const [count, setCount] = useState(0);

  const expensiveCalculation = useMemo(() =&amp;gt; {
    // Simulate an expensive computation
    return count * 1000;
  }, [count]);

  return (
    &amp;lt;View&amp;gt;
      &amp;lt;Text&amp;gt;Result: {expensiveCalculation}&amp;lt;/Text&amp;gt;
      &amp;lt;Button title="Increase Count" onPress={() =&amp;gt; setCount(count + 1)} /&amp;gt;
    &amp;lt;/View&amp;gt;
  );
};

export default ExpensiveComponent;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How it works:
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;useMemo&lt;/code&gt; ensures the expensive calculation runs only when &lt;code&gt;count&lt;/code&gt; changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;useRef&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;useRef&lt;/code&gt; is used to persist values across renders without causing a re-render. It’s often used to reference DOM elements or hold mutable values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useRef } from 'react';
import { Button, TextInput, View } from 'react-native';

const InputFocus = () =&amp;gt; {
  const inputRef = useRef&amp;lt;TextInput | null&amp;gt;(null);

  const focusInput = () =&amp;gt; {
    inputRef.current?.focus();
  };

  return (
    &amp;lt;View&amp;gt;
      &amp;lt;TextInput ref={inputRef} style={{ height: 40, borderColor: 'gray', borderWidth: 1 }} /&amp;gt;
      &amp;lt;Button title="Focus Input" onPress={focusInput} /&amp;gt;
    &amp;lt;/View&amp;gt;
  );
};

export default InputFocus;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How it works:
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;useRef&lt;/code&gt; creates a reference to the &lt;code&gt;TextInput&lt;/code&gt; component, allowing us to programmatically control its focus.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;useLayoutEffect&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;useLayoutEffect&lt;/code&gt; works similarly to &lt;code&gt;useEffect&lt;/code&gt; but is fired synchronously after all DOM mutations, ensuring your effect runs before the browser paints.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useLayoutEffect, useState } from 'react';
import { Text, View } from 'react-native';

const LayoutEffectComponent = () =&amp;gt; {
  const [layout, setLayout] = useState({ width: 0, height: 0 });

  useLayoutEffect(() =&amp;gt; {
    // This effect runs before the browser updates the screen
    setLayout({ width: 100, height: 100 });
  }, []);

  return (
    &amp;lt;View style={{ width: layout.width, height: layout.height }}&amp;gt;
      &amp;lt;Text&amp;gt;Layout size: {layout.width} x {layout.height}&amp;lt;/Text&amp;gt;
    &amp;lt;/View&amp;gt;
  );
};

export default LayoutEffectComponent;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How it works:
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;useLayoutEffect&lt;/code&gt; is useful for reading layout measurements and synchronizing DOM mutations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating Custom Hooks
&lt;/h2&gt;

&lt;p&gt;Custom hooks allow you to extract and reuse logic from components. They are simply functions that use hooks internally.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useState, useEffect } from 'react';

const useFetchData = (url: string) =&amp;gt; {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() =&amp;gt; {
    const fetchData = async () =&amp;gt; {
      const response = await fetch(url);
      const result = await response.json();
      setData(result);
      setLoading(false);
    };
    fetchData();
  }, [url]);

  return { data, loading };
};

export default useFetchData;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now use &lt;code&gt;useFetchData&lt;/code&gt; in any component to fetch data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import { Text, View } from 'react-native';
import useFetchData from './useFetchData';

const DataComponent = () =&amp;gt; {
  const { data, loading } = useFetchData('https://jsonplaceholder.typicode.com/todos/1');

  return (
    &amp;lt;View&amp;gt;{loading ? &amp;lt;Text&amp;gt;Loading...&amp;lt;/Text&amp;gt; : &amp;lt;Text&amp;gt;{JSON.stringify(data)}&amp;lt;/Text&amp;gt;}&amp;lt;/View&amp;gt;
  );
};

export default DataComponent;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;React hooks, combined with TypeScript, offer a powerful and concise way to manage state and side effects in your React Native apps. By mastering hooks like &lt;code&gt;useState&lt;/code&gt;, &lt;code&gt;useEffect&lt;/code&gt;, and others, you can write cleaner, more efficient components. Additionally, creating custom hooks allows you to reuse logic across your application.&lt;/p&gt;

&lt;p&gt;That's it for today. In the next part of this series, we’ll explore advanced topics like navigation, animations, and working with APIs.&lt;/p&gt;

&lt;p&gt;Feel free to reach out to me if you have any questions or need assistance.&lt;br&gt;
LinkedIn: &lt;a href="https://www.linkedin.com/in/rushikesh-pandit-646834100/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/rushikesh-pandit-646834100/&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/rushikeshpandit" rel="noopener noreferrer"&gt;https://github.com/rushikeshpandit&lt;/a&gt;&lt;br&gt;
Portfolio: &lt;a href="https://www.rushikeshpandit.in" rel="noopener noreferrer"&gt;https://www.rushikeshpandit.in&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;#ReactNative #TypeScript #MobileDevelopment #SoftwareEngineering #DevCommunity&lt;/p&gt;

</description>
      <category>mobile</category>
      <category>reactnative</category>
      <category>hooks</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Mastering React Native with TypeScript: From Basics to Brilliance - Part 1</title>
      <dc:creator>Rushikesh Pandit</dc:creator>
      <pubDate>Thu, 09 Jan 2025 14:37:05 +0000</pubDate>
      <link>https://dev.to/rushikeshpandit/mastering-react-native-with-typescript-from-basics-to-brilliance-part-1-4a46</link>
      <guid>https://dev.to/rushikeshpandit/mastering-react-native-with-typescript-from-basics-to-brilliance-part-1-4a46</guid>
      <description>&lt;p&gt;Are you ready to dive into the world of mobile app development without mastering two separate languages for iOS and Android? Meet &lt;strong&gt;React Native&lt;/strong&gt;—the game-changing framework from Facebook that lets you build high-performance, cross-platform apps using the language you already love: JavaScript (and in our case, TypeScript)!&lt;/p&gt;

&lt;p&gt;With React Native, you can build apps that look, feel, and perform as a true native app would. No wonder it's powering industry-leading apps like Instagram, Airbnb, and Tesla.&lt;/p&gt;

&lt;p&gt;Kickstarting your journey into the world of React Native 0.76 with TypeScript, we are going to go over what the core building blocks of any application are. Whether you're a curious beginner or an experienced developer seeking to hone your abilities in TypeScript, this guide will get you moving toward mobile development greatness.&lt;/p&gt;

&lt;p&gt;We're covering everything you need to know to build your first app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Core Components include &lt;code&gt;View&lt;/code&gt;, &lt;code&gt;Text&lt;/code&gt;, and &lt;code&gt;ScrollView&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Styling techniques that make your UI pop&lt;/li&gt;
&lt;li&gt;Managing Props and State for dynamic interactions&lt;/li&gt;
&lt;li&gt;Mastering lists with &lt;code&gt;FlatList&lt;/code&gt; for seamless data handling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the end of this series, you’ll not only understand the foundation of React Native but also have practical, real-world code snippets to kickstart your app development journey. Let’s make your dream app a reality—starting now!!&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Components in React Native
&lt;/h2&gt;

&lt;p&gt;Core components are the basic building blocks of every React Native application. They connect the JavaScript world with the native world, and that is where you get the building blocks to craft amazing user interfaces. Let's take a look at each of them.&lt;/p&gt;

&lt;p&gt;1 . &lt;strong&gt;View&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;View&lt;/code&gt; component is the fundamental container in React Native. It’s used to group and layout other components. Think of it as a &lt;code&gt;div&lt;/code&gt; in web development.&lt;/p&gt;

&lt;p&gt;Example: Creating a Centered Box&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import { View, StyleSheet } from 'react-native';

const App = () =&amp;gt; (
  &amp;lt;View style={styles.container}&amp;gt;
    &amp;lt;View style={styles.box} /&amp;gt;
  &amp;lt;/View&amp;gt;
);

const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: 'center', alignItems: 'center' },
  box: { width: 100, height: 100, backgroundColor: 'blue' },
});

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we use &lt;code&gt;flex: 1&lt;/code&gt; to ensure the &lt;code&gt;View&lt;/code&gt; fills the entire screen, and &lt;code&gt;justifyContent&lt;/code&gt; and &lt;code&gt;alignItems&lt;/code&gt; center the box.&lt;/p&gt;

&lt;p&gt;2 . &lt;strong&gt;Text&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Text&lt;/code&gt; component is used for rendering text on the screen. It supports various text styles and nested elements.&lt;/p&gt;

&lt;p&gt;Example: Displaying Styled Text&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import { Text, StyleSheet } from 'react-native';

const App = () =&amp;gt; (
  &amp;lt;Text style={styles.text}&amp;gt;Hello, React Native with TypeScript!&amp;lt;/Text&amp;gt;
);

const styles = StyleSheet.create({
  text: { fontSize: 20, color: 'purple', textAlign: 'center', marginTop: 20 },
});

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how we use &lt;code&gt;fontSize&lt;/code&gt;, &lt;code&gt;color&lt;/code&gt;, and &lt;code&gt;textAlign&lt;/code&gt; to style the Text component.&lt;/p&gt;

&lt;p&gt;3 . &lt;strong&gt;Image&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Image&lt;/code&gt; component is used to display images. It supports both local and remote image sources.&lt;/p&gt;

&lt;p&gt;Example: Displaying a Remote Image&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import { Image, StyleSheet } from 'react-native';

const App = () =&amp;gt; (
  &amp;lt;Image
    source={{ uri: 'https://reactnative.dev/img/tiny_logo.png' }}
    style={styles.image}
  /&amp;gt;
);

const styles = StyleSheet.create({
  image: { width: 100, height: 100, borderRadius: 10 },
});

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;borderRadius&lt;/code&gt; property gives the image rounded corners.&lt;/p&gt;

&lt;p&gt;4 . &lt;strong&gt;TextInput&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;TextInput&lt;/code&gt; component captures user input. It supports properties like &lt;code&gt;placeholder&lt;/code&gt;, &lt;code&gt;onChangeText&lt;/code&gt;, and &lt;code&gt;value&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Example: Handling User Input&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState } from 'react';
import { TextInput, StyleSheet, View, Text } from 'react-native';

const App = () =&amp;gt; {
  const [input, setInput] = useState&amp;lt;string&amp;gt;('');

  return (
    &amp;lt;View style={styles.container}&amp;gt;
      &amp;lt;TextInput
        style={styles.input}
        placeholder="Type here..."
        value={input}
        onChangeText={setInput}
      /&amp;gt;
      &amp;lt;Text&amp;gt;You typed: {input}&amp;lt;/Text&amp;gt;
    &amp;lt;/View&amp;gt;
  );
};

const styles = StyleSheet.create({
  container: { padding: 20 },
  input: { borderWidth: 1, borderColor: '#ccc', padding: 10, borderRadius: 5, marginBottom: 10 },
});

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;onChangeText&lt;/code&gt; handler updates the state with the user’s input.&lt;/p&gt;

&lt;p&gt;5 . &lt;strong&gt;TouchableOpacity&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;TouchableOpacity&lt;/code&gt; component enables touch interactions with a fading effect.&lt;/p&gt;

&lt;p&gt;Example: Creating a Button&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import { TouchableOpacity, Text, StyleSheet } from 'react-native';

const App = () =&amp;gt; (
  &amp;lt;TouchableOpacity style={styles.button} onPress={() =&amp;gt; alert('Button Pressed!')}&amp;gt;
    &amp;lt;Text style={styles.text}&amp;gt;Press Me&amp;lt;/Text&amp;gt;
  &amp;lt;/TouchableOpacity&amp;gt;
);

const styles = StyleSheet.create({
  button: { backgroundColor: 'blue', padding: 10, borderRadius: 5 },
  text: { color: 'white', textAlign: 'center' },
});

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;onPress&lt;/code&gt; handler triggers an action when the button is tapped.&lt;/p&gt;

&lt;p&gt;6 . &lt;strong&gt;ScrollView&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ScrollView&lt;/code&gt; component allows for scrollable content. It’s ideal for layouts with a small amount of content that won’t require heavy performance optimization.&lt;/p&gt;

&lt;p&gt;Example: Rendering a Scrollable List&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import { ScrollView, Text, StyleSheet } from 'react-native';

const App = () =&amp;gt; (
  &amp;lt;ScrollView contentContainerStyle={styles.container}&amp;gt;
    {Array.from({ length: 20 }, (_, i) =&amp;gt; (
      &amp;lt;Text key={i} style={styles.text}&amp;gt;Item {i + 1}&amp;lt;/Text&amp;gt;
    ))}
  &amp;lt;/ScrollView&amp;gt;
);

const styles = StyleSheet.create({
  container: { padding: 10 },
  text: { fontSize: 16, marginVertical: 5 },
});

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we dynamically generate 20 items and render them inside a &lt;code&gt;ScrollView&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;7 . &lt;strong&gt;FlatList&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;FlatList&lt;/code&gt; component is designed for rendering large datasets efficiently. It only renders items currently visible on the screen, significantly improving performance.&lt;/p&gt;

&lt;p&gt;Example: Rendering a List&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import { FlatList, Text, View, StyleSheet } from 'react-native';

const data = [
  { id: '1', name: 'Item 1' },
  { id: '2', name: 'Item 2' },
  { id: '3', name: 'Item 3' },
];

const App = () =&amp;gt; (
  &amp;lt;FlatList
    data={data}
    keyExtractor={(item) =&amp;gt; item.id}
    renderItem={({ item }) =&amp;gt; (
      &amp;lt;View style={styles.item}&amp;gt;
        &amp;lt;Text style={styles.text}&amp;gt;{item.name}&amp;lt;/Text&amp;gt;
      &amp;lt;/View&amp;gt;
    )}
  /&amp;gt;
);

const styles = StyleSheet.create({
  item: {
    padding: 20,
    borderBottomWidth: 1,
    borderBottomColor: '#ccc',
  },
  text: {
    fontSize: 18,
  },
});

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Difference Between FlatList and ScrollView:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use &lt;code&gt;FlatList&lt;/code&gt; for large, dynamic datasets to optimize performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use &lt;code&gt;ScrollView&lt;/code&gt; for smaller datasets or static content.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Styling in React Native
&lt;/h2&gt;

&lt;p&gt;Styling in React Native is achieved using the &lt;code&gt;StyleSheet&lt;/code&gt; API. It borrows heavily from CSS but is tailored to work with native platforms for optimal performance.&lt;/p&gt;

&lt;p&gt;1 . &lt;strong&gt;StyleSheet API&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;StyleSheet&lt;/code&gt; API provides a way to define styles separately and reuse them across components.&lt;/p&gt;

&lt;p&gt;Example: Creating Reusable Styles&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import { View, Text, StyleSheet } from 'react-native';

const App = () =&amp;gt; (
  &amp;lt;View style={styles.container}&amp;gt;
    &amp;lt;Text style={styles.text}&amp;gt;Reusable Styles with StyleSheet&amp;lt;/Text&amp;gt;
  &amp;lt;/View&amp;gt;
);

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#f0f0f0',
  },
  text: {
    fontSize: 20,
    color: 'blue',
  },
});

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2 . &lt;strong&gt;Flexbox Layout&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;React Native employs Flexbox for layout management. Flexbox helps to define the alignment, distribution, and spacing of elements within a container.&lt;/p&gt;

&lt;p&gt;Example: Aligning Items Horizontally&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    padding: 10,
  },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3 . &lt;strong&gt;Platform-Specific Styling&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;React Native allows platform-specific styles using the &lt;code&gt;Platform&lt;/code&gt; module.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Platform, StyleSheet } from 'react-native';

const styles = StyleSheet.create({
  text: {
    fontSize: Platform.OS === 'ios' ? 20 : 18,
    color: Platform.OS === 'ios' ? 'blue' : 'green',
  },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Props and State Management
&lt;/h2&gt;

&lt;p&gt;1 . &lt;strong&gt;Props&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Props allow you to pass data from a parent component to a child component.&lt;/p&gt;

&lt;p&gt;Example: Custom Greeting Component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import { Text } from 'react-native';

const Greeting = ({ name }: { name: string }) =&amp;gt; (
  &amp;lt;Text&amp;gt;Hello, {name}!&amp;lt;/Text&amp;gt;
);

const App = () =&amp;gt; &amp;lt;Greeting name="React Native" /&amp;gt;;

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2 . &lt;strong&gt;State Management with &lt;code&gt;useState&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;useState&lt;/code&gt; hook is used to manage state in functional components.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState } from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';

const Counter = () =&amp;gt; {
  const [count, setCount] = useState&amp;lt;number&amp;gt;(0);

  return (
    &amp;lt;View style={styles.container}&amp;gt;
      &amp;lt;Text style={styles.text}&amp;gt;Count: {count}&amp;lt;/Text&amp;gt;
      &amp;lt;Button title="Increase" onPress={() =&amp;gt; setCount(count + 1)} /&amp;gt;
    &amp;lt;/View&amp;gt;
  );
};

const styles = StyleSheet.create({
  container: {
    padding: 20,
  },
  text: {
    fontSize: 18,
    marginBottom: 10,
  },
});

export default Counter;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3 . &lt;strong&gt;Typing Props with TypeScript&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Using TypeScript ensures type safety when passing props.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface GreetingProps {
  name: string;
}

const Greeting = ({ name }: GreetingProps) =&amp;gt; (
  &amp;lt;Text&amp;gt;Hello, {name}!&amp;lt;/Text&amp;gt;
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it for today. In the next part of this series, we’ll explore advanced topics like navigation, animations, hooks, and working with APIs.&lt;/p&gt;

&lt;p&gt;Feel free to reach out to me if you have any questions or need assistance.&lt;br&gt;
LinkedIn: &lt;a href="https://www.linkedin.com/in/rushikesh-pandit-646834100/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/rushikesh-pandit-646834100/&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/rushikeshpandit" rel="noopener noreferrer"&gt;https://github.com/rushikeshpandit&lt;/a&gt;&lt;br&gt;
Portfolio: &lt;a href="https://www.rushikeshpandit.in" rel="noopener noreferrer"&gt;https://www.rushikeshpandit.in&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;#ReactNative #TypeScript #MobileDevelopment #SoftwareEngineering   #DevCommunity&lt;/p&gt;

</description>
      <category>mobile</category>
      <category>reactnative</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Leverage ETS for Shared State in Phoenix</title>
      <dc:creator>Rushikesh Pandit</dc:creator>
      <pubDate>Mon, 09 Dec 2024 13:45:00 +0000</pubDate>
      <link>https://dev.to/rushikeshpandit/leverage-ets-for-shared-state-in-phoenix-2mo8</link>
      <guid>https://dev.to/rushikeshpandit/leverage-ets-for-shared-state-in-phoenix-2mo8</guid>
      <description>&lt;p&gt;When building web applications, managing shared state efficiently is often a challenge. For Elixir developers, &lt;strong&gt;ETS (Erlang Term Storage)&lt;/strong&gt; provides an incredibly powerful tool to tackle this problem. ETS is a robust, in-memory data store built into the Erlang VM, offering fast lookups, concurrent access, and persistence during a process’s lifetime.&lt;/p&gt;

&lt;p&gt;In this blog, we’ll explore &lt;strong&gt;how ETS works&lt;/strong&gt;, &lt;strong&gt;why it’s an excellent choice for shared state in Phoenix applications&lt;/strong&gt;, and demonstrate practical examples with code snippets.&lt;/p&gt;

&lt;h1&gt;
  
  
  What is ETS?
&lt;/h1&gt;

&lt;p&gt;ETS (Erlang Term Storage) is a highly efficient in-memory storage system available in Elixir and Erlang. It supports storing key-value pairs, lists, and tuples and is designed to handle high-performance operations with concurrent reads and writes. ETS tables live as long as the process that owns them, making them ideal for managing temporary or shared state.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why Use ETS in Phoenix?
&lt;/h1&gt;

&lt;p&gt;ETS is a great fit for Phoenix applications in scenarios such as:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Caching&lt;/strong&gt;: Store frequently accessed data, such as API responses or computed results, for quick retrieval.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Session Management&lt;/strong&gt;: Maintain temporary user session data across requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate Limiting&lt;/strong&gt;: Track user activity to enforce API rate limits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-Time Data Sharing&lt;/strong&gt;: Share data between processes efficiently.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  ETS Basics
&lt;/h1&gt;

&lt;p&gt;To get started, let’s create and manipulate a simple ETS table. You can create a table using &lt;code&gt;:ets.new/2&lt;/code&gt; and interact with it using functions like &lt;code&gt;:ets.insert/2&lt;/code&gt; and &lt;code&gt;:ets.lookup/2&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Creating an ETS table
table = :ets.new(:example_table, [:set, :public])

# Inserting data
:ets.insert(table, {:key, "value"})

# Retrieving data
case :ets.lookup(table, :key) do
  [{:key, value}] -&amp;gt; IO.puts("Found: #{value}")
  [] -&amp;gt; IO.puts("Not found")
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Using ETS in Phoenix
&lt;/h1&gt;

&lt;p&gt;Let’s dive into a practical example: caching frequently accessed data in a Phoenix application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. ETS for Caching API Data&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Suppose you have a Phoenix controller that fetches data from an external API. Instead of fetching the data on every request, you can cache the result in ETS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ETS Cache Setup&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create a module to manage your ETS table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;defmodule MyApp.Cache do
  @table :api_cache

  def start_link do
    :ets.new(@table, [:named_table, :set, :public, read_concurrency: true])
    {:ok, %{}}
  end

  def put(key, value) do
    :ets.insert(@table, {key, value})
  end

  def get(key) do
    case :ets.lookup(@table, key) do
      [{^key, value}] -&amp;gt; {:ok, value}
      [] -&amp;gt; :error
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fetching and Caching API Data&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use this module in your controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;defmodule MyAppWeb.PageController do
  use MyAppWeb, :controller

  alias MyApp.Cache

  def index(conn, _params) do
    data =
      case Cache.get(:api_data) do
        {:ok, cached_data} -&amp;gt;
          cached_data

        :error -&amp;gt;
          # Fetch data from external API
          api_data = fetch_data_from_api()
          Cache.put(:api_data, api_data)
          api_data
      end

    render(conn, "index.html", data: data)
  end

  defp fetch_data_from_api do
    # Simulated API call
    %{key: "value", timestamp: DateTime.utc_now()}
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, subsequent requests to &lt;code&gt;index/2&lt;/code&gt; will retrieve data from the ETS cache instead of making repeated API calls.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Rate Limiting with ETS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Another practical use case is rate limiting. You can use ETS to track how many requests a user has made within a given time window.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rate Limiter Module&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;defmodule MyApp.RateLimiter do
  @table :rate_limiter

  def start_link do
    :ets.new(@table, [:named_table, :set, :public])
    {:ok, %{}}
  end

  def allow?(user_id, limit \\ 10) do
    case :ets.lookup(@table, user_id) do
      [{^user_id, count}] when count &amp;gt;= limit -&amp;gt;
        false

      [{^user_id, count}] -&amp;gt;
        :ets.insert(@table, {user_id, count + 1})
        true

      [] -&amp;gt;
        :ets.insert(@table, {user_id, 1})
        true
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Using the Rate Limiter&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Integrate it into a Phoenix controller to enforce limits:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;defmodule MyAppWeb.ApiController do
  use MyAppWeb, :controller

  alias MyApp.RateLimiter

  def index(conn, _params) do
    user_id = get_user_id(conn)

    if RateLimiter.allow?(user_id) do
      json(conn, %{message: "Request allowed"})
    else
      conn
      |&amp;gt; put_status(:too_many_requests)
      |&amp;gt; json(%{error: "Rate limit exceeded"})
    end
  end

  defp get_user_id(conn) do
    # Example: extract user ID from session or token
    conn.assigns[:current_user].id
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This setup ensures that a user cannot exceed the specified request limit, and ETS handles the tracking efficiently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Advanced ETS Tips&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Named Tables&lt;/strong&gt;: Use named tables (&lt;code&gt;[:named_table]&lt;/code&gt;) for global access across processes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrency Options&lt;/strong&gt;: Use &lt;code&gt;:read_concurrency&lt;/code&gt; and &lt;code&gt;:write_concurrency&lt;/code&gt; for performance optimization in read-heavy or write-heavy scenarios.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistence&lt;/strong&gt;: Combine ETS with &lt;code&gt;:dets&lt;/code&gt; (Disk ETS) to persist data across application restarts.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Limitations of ETS&lt;/strong&gt;&lt;br&gt;
While ETS is powerful, it’s important to be aware of its limitations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Table Lifespan&lt;/strong&gt;: Tables are tied to the lifecycle of their owning process. If the process crashes, the table is lost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manual Garbage Collection&lt;/strong&gt;: ETS doesn’t automatically manage expired data. You’ll need to implement a cleanup mechanism if necessary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cluster Awareness&lt;/strong&gt;: ETS is not distributed across nodes in a cluster. For distributed setups, consider using Mnesia or a database.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ETS is a fantastic tool for managing shared state in Phoenix applications. Its simplicity and speed make it ideal for caching, rate limiting, and real-time data sharing. However, understanding its limitations is key to using it effectively.&lt;/p&gt;

&lt;p&gt;Have you used ETS in your Phoenix projects? Share your experiences in the comments or let me know what other ETS use cases you'd like to explore!&lt;/p&gt;

&lt;p&gt;Feel free to reach out if you need help.&lt;/p&gt;

&lt;p&gt;LinkedIn: &lt;a href="https://www.linkedin.com/in/rushikesh-pandit" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/rushikesh-pandit&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/rushikeshpandit" rel="noopener noreferrer"&gt;https://github.com/rushikeshpandit&lt;/a&gt;&lt;br&gt;
Portfolio: &lt;a href="https://www.rushikeshpandit.in" rel="noopener noreferrer"&gt;https://www.rushikeshpandit.in&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;#myelixirstatus , #elixir , #phoenixframework&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>elixir</category>
      <category>phoenixframework</category>
    </item>
    <item>
      <title>Harness PubSub for Real-Time Features in Phoenix Framework</title>
      <dc:creator>Rushikesh Pandit</dc:creator>
      <pubDate>Mon, 02 Dec 2024 13:03:14 +0000</pubDate>
      <link>https://dev.to/rushikeshpandit/harness-pubsub-for-real-time-features-in-phoenix-framework-2hk7</link>
      <guid>https://dev.to/rushikeshpandit/harness-pubsub-for-real-time-features-in-phoenix-framework-2hk7</guid>
      <description>&lt;p&gt;When it comes to building real-time web applications, the Phoenix framework is hard to beat. At the heart of its real-time capabilities lies Phoenix.PubSub, a powerful messaging system that allows processes to subscribe to and broadcast messages within an application. Whether you’re building live notifications, collaborative tools, or event-driven systems, PubSub is your go-to tool.&lt;/p&gt;

&lt;p&gt;In this blog, we’ll explore &lt;strong&gt;how Phoenix.PubSub works&lt;/strong&gt;, dive into &lt;strong&gt;practical use cases&lt;/strong&gt;, and demonstrate &lt;strong&gt;step-by-step examples&lt;/strong&gt; to integrate it into your projects.&lt;/p&gt;

&lt;h1&gt;
  
  
  What is Phoenix.PubSub?
&lt;/h1&gt;

&lt;p&gt;Phoenix.PubSub is a publish-subscribe mechanism built into the Phoenix framework. It allows you to broadcast messages to multiple subscribers efficiently, enabling real-time communication across your application.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Publishers:&lt;/strong&gt; Send messages to a specific topic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subscribers:&lt;/strong&gt; Listen for messages on topics they are interested in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Topics:&lt;/strong&gt; Strings representing the channel for communication (e.g., &lt;code&gt;"notifications"&lt;/code&gt;, &lt;code&gt;"room:lobby"&lt;/code&gt;).
PubSub is transport-agnostic, meaning it can work seamlessly across distributed systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Why Use PubSub?
&lt;/h1&gt;

&lt;p&gt;PubSub is an excellent fit for scenarios like:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Real-time notifications:&lt;/strong&gt; Push updates instantly to users (e.g., alerts, badges).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Collaborative tools:&lt;/strong&gt; Enable live edits or actions in shared environments (e.g., Google Docs-style collaboration).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event broadcasting:&lt;/strong&gt; Notify multiple processes of significant events (e.g., user activity).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability:&lt;/strong&gt; Distribute messages across nodes in a clustered environment.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Setting Up PubSub
&lt;/h1&gt;

&lt;p&gt;PubSub is automatically included in new Phoenix applications, but to use it effectively, let’s break down the setup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Configuration&lt;/strong&gt;&lt;br&gt;
Ensure your application’s &lt;code&gt;PubSub&lt;/code&gt; module is defined in &lt;code&gt;lib/my_app/application.ex&lt;/code&gt;. It’s typically added by default.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;defmodule MyApp.Application do
  use Application

  def start(_type, _args) do
    children = [
      {Phoenix.PubSub, name: MyApp.PubSub}
    ]

    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
    Supervisor.start_link(children, opts)
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Broadcasting Messages&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;Phoenix.PubSub.broadcast/3&lt;/code&gt; to send messages to a specific topic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Phoenix.PubSub.broadcast(MyApp.PubSub, "notifications", %{message: "New user signed up!"})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Subscribing to Topics&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Processes can subscribe to a topic using &lt;code&gt;Phoenix.PubSub.subscribe/2&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Phoenix.PubSub.subscribe(MyApp.PubSub, "notifications")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Real-World Example: Notifications System
&lt;/h1&gt;

&lt;p&gt;Let’s build a simple notification system where users receive real-time updates whenever a new notification is added.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the PubSub Integration
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Subscribe to Notifications&lt;/strong&gt;&lt;br&gt;
When a LiveView mounts, subscribe the process to the &lt;code&gt;"notifications"&lt;/code&gt; topic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def mount(_params, _session, socket) do
  Phoenix.PubSub.subscribe(MyApp.PubSub, "notifications")
  {:ok, assign(socket, notifications: [])}
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Handle Incoming Messages&lt;/strong&gt;&lt;br&gt;
When a message is broadcasted, handle it with &lt;code&gt;handle_info/2&lt;/code&gt; and update the LiveView state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def handle_info(%{message: message}, socket) do
  {:noreply, assign(socket, notifications: [message | socket.assigns.notifications])}
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Broadcast Notifications&lt;/strong&gt;&lt;br&gt;
Trigger broadcasts from any part of the app (e.g., a controller or background worker).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def notify_users(message) do
  Phoenix.PubSub.broadcast(MyApp.PubSub, "notifications", %{message: message})
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;LiveView Template&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div id="notifications"&amp;gt;
  &amp;lt;h3&amp;gt;Notifications&amp;lt;/h3&amp;gt;
  &amp;lt;ul&amp;gt;
    &amp;lt;%= for notification &amp;lt;- @notifications do %&amp;gt;
      &amp;lt;li&amp;gt;&amp;lt;%= notification %&amp;gt;&amp;lt;/li&amp;gt;
    &amp;lt;% end %&amp;gt;
  &amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these steps, users will receive live updates in their notifications list whenever &lt;code&gt;notify_users/1&lt;/code&gt; is called.&lt;/p&gt;

&lt;h1&gt;
  
  
  Advanced Use Case: Collaborative Editing
&lt;/h1&gt;

&lt;p&gt;PubSub shines in collaborative tools. For instance, imagine a real-time collaborative text editor where multiple users edit the same document.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Broadcasting Edits&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def handle_event("edit", %{"content" =&amp;gt; content}, socket) do
  Phoenix.PubSub.broadcast(MyApp.PubSub, "document:123", %{content: content})
  {:noreply, socket}
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Subscribing to Edits&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def mount(_params, _session, socket) do
  Phoenix.PubSub.subscribe(MyApp.PubSub, "document:123")
  {:ok, assign(socket, content: "")}
end

def handle_info(%{content: content}, socket) do
  {:noreply, assign(socket, content: content)}
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Testing PubSub
&lt;/h1&gt;

&lt;p&gt;You can test your PubSub implementation easily using &lt;code&gt;iex&lt;/code&gt;. Open multiple &lt;code&gt;iex&lt;/code&gt; sessions and ensure they subscribe to the same topic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Phoenix.PubSub.subscribe(MyApp.PubSub, "test_topic")

Phoenix.PubSub.broadcast(MyApp.PubSub, "test_topic", %{data: "Hello, PubSub!"})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All subscribers to &lt;code&gt;"test_topic"&lt;/code&gt; should receive the broadcast message.&lt;/p&gt;

&lt;h1&gt;
  
  
  Scaling PubSub Across Nodes
&lt;/h1&gt;

&lt;p&gt;Phoenix.PubSub supports distributed systems out of the box. To enable clustering:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add &lt;code&gt;:libcluster&lt;/code&gt; to your dependencies.&lt;/li&gt;
&lt;li&gt;Configure clustering in &lt;code&gt;config/runtime.exs&lt;/code&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;config :libcluster,
  topologies: [
    example: [
      strategy: Cluster.Strategy.Gossip
    ]
  ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Start your application on multiple nodes, and messages will seamlessly propagate across them.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Phoenix.PubSub is a powerful tool for building real-time features in Elixir applications. Whether you’re creating a simple notification system or scaling to a distributed collaborative environment, PubSub provides the flexibility and performance you need.&lt;/p&gt;

&lt;p&gt;If you’ve built something cool with Phoenix.PubSub, let me know in the comments—I’d love to hear about your experience!&lt;/p&gt;

&lt;p&gt;Feel free to reach out if you need help.&lt;/p&gt;

&lt;p&gt;LinkedIn: &lt;a href="https://www.linkedin.com/in/rushikesh-pandit" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/rushikesh-pandit&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/rushikeshpandit" rel="noopener noreferrer"&gt;https://github.com/rushikeshpandit&lt;/a&gt;&lt;br&gt;
Portfolio: &lt;a href="https://www.rushikeshpandit.in" rel="noopener noreferrer"&gt;https://www.rushikeshpandit.in&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;#myelixirstatus , #elixir , #phoenixframework&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>webdev</category>
      <category>phoenixframework</category>
      <category>pubsub</category>
    </item>
  </channel>
</rss>
