<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[InnuNext — React Native & Mobile Engineering]]></title><description><![CDATA[Deep-dive engineering guides on React Native performance, offline architecture, App Store publishing, and mobile product delivery — by Inayat Ali.]]></description><link>https://innunext.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Tue, 10 Nov 2026 11:54:21 GMT</lastBuildDate><atom:link href="https://innunext.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Architecting Offline-First Mobile Apps with SQLite, WatermelonDB & Supabase]]></title><description><![CDATA[When an EV driver enters an underground concrete garage, or a delivery driver hits a low-signal highway corridor, a "spinner-driven" cloud app completely…]]></description><link>https://innunext.hashnode.dev/architecting-offline-first-mobile-apps-with-sqlite-watermelondb-supabase</link><guid isPermaLink="true">https://innunext.hashnode.dev/architecting-offline-first-mobile-apps-with-sqlite-watermelondb-supabase</guid><category><![CDATA[React Native]]></category><category><![CDATA[Mobile Development]]></category><category><![CDATA[architecture]]></category><category><![CDATA[Databases]]></category><dc:creator><![CDATA[Inayat Ali]]></dc:creator><pubDate>Sun, 08 Nov 2026 15:42:03 GMT</pubDate><content:encoded><![CDATA[<h1>Architecting Offline-First Mobile Apps with SQLite, WatermelonDB &amp; Supabase</h1>
<p>When an EV driver enters an underground concrete garage, or a delivery driver hits a low-signal highway corridor, a "spinner-driven" cloud app completely fails.</p>
<p>If your app shows an infinite loading spinner the moment 4G drops to 1 bar, it's not a resilient production product.</p>
<p>Here is the exact architecture pattern I use to build zero-data-loss, offline-first mobile apps.</p>
<hr />
<h2>1. The Core Principle: Local Database as Single Source of Truth</h2>
<p>In traditional apps:</p>
<pre><code class="language-plaintext">UI Component --&gt; Network Request --&gt; Cloud Database --&gt; UI Updates
</code></pre>
<p>If the network stalls, the user is locked out.</p>
<p>In true offline-first apps:</p>
<pre><code class="language-plaintext">UI Component &lt;--&gt; Local SQLite / WatermelonDB (0ms Instant Reads &amp; Writes)
                      |
                      v (Background Sync Engine)
               Supabase / PostgreSQL
</code></pre>
<p>The user <strong>never</strong> waits for network round-trips. Every tap, order, or check-in writes immediately to the local encrypted SQLite database and updates the UI in under 10ms.</p>
<hr />
<h2>2. The Idempotent Outbox Pattern (Zero Duplicate Orders)</h2>
<p>The hardest part of offline sync is not storing data locally — it's replaying mutations safely when connectivity returns.</p>
<p>If a driver logs a delivery while offline, and the network retries 3 times on flaky 3G, how do you prevent creating 3 duplicate delivery records in your backend?</p>
<h3>The Pattern: Client-Generated UUID Idempotency Keys</h3>
<pre><code class="language-typescript">interface OutboxMutation {
  idempotencyKey: string; // UUID v4 generated locally on device
  entity: "order_status" | "ticket_scan" | "ble_session";
  payload: Record&lt;string, unknown&gt;;
  recordedAtIso: string;
  retryCount: number;
}
</code></pre>
<p>When network connectivity resumes:</p>
<ol>
<li>The background sync worker reads pending outbox rows in chronological order.</li>
<li>It sends requests with the <code>idempotencyKey</code> in the request header or payload.</li>
<li>Supabase / PostgreSQL uses <code>ON CONFLICT (idempotency_key) DO UPDATE</code> — ensuring 10 retries result in exactly <strong>one</strong> recorded transaction.</li>
</ol>
<hr />
<h2>3. Storage Engine Comparison for Mobile</h2>
<table>
<thead>
<tr>
<th>Storage Engine</th>
<th>Architecture</th>
<th>Query Speed (10k items)</th>
<th>Best Use Case</th>
</tr>
</thead>
<tbody><tr>
<td><strong>AsyncStorage</strong></td>
<td>Key-Value string dump</td>
<td>Poor (&gt; 400ms scan)</td>
<td>Simple auth tokens, user theme</td>
</tr>
<tr>
<td><strong>MMKV</strong></td>
<td>Memory-mapped key-value (JSI)</td>
<td>Instant (&lt; 1ms)</td>
<td>Fast session state, flags</td>
</tr>
<tr>
<td><strong>expo-sqlite</strong></td>
<td>Embedded relational SQL</td>
<td>Fast (&lt; 15ms)</td>
<td>Relational records, local filtering</td>
</tr>
<tr>
<td><strong>WatermelonDB</strong></td>
<td>Observable lazy SQLite engine</td>
<td>Instant (&lt; 5ms)</td>
<td>Large feeds, complex multi-table offline apps</td>
</tr>
</tbody></table>
<hr />
<h2>4. Pairing Offline Storage with Bluetooth BLE &amp; Hardware</h2>
<p>In IoT and hardware companion apps (such as EV charging stations or medical peripherals):</p>
<ol>
<li>The phone pairs directly with the peripheral over <strong>Bluetooth Low Energy (BLE) GATT characteristics</strong>.</li>
<li>Telemetry and billing logs are written directly to local SQLite while 100% offline.</li>
<li>Once the user returns to Wi-Fi or cellular range, the delta synchronizer commits the verified session to Supabase without requiring user intervention.</li>
</ol>
<hr />
<p>Building an enterprise field service, fleet, or offline Bluetooth mobile application? I document production offline patterns at <a href="https://innunext.com">innunext.com</a> and design resilient <a href="https://innunext.com/guides/offline-first-mobile-architecture-sqlite-supabase">offline-first mobile architectures</a>.</p>
<hr />
]]></content:encoded></item><item><title><![CDATA[How to Prevent Apple App Store & Google Play Rejections (The 2025/2026 Checklist)]]></title><description><![CDATA[Most mobile launch delays aren't caused by broken code. They're caused by failing strict platform compliance rules that automated bots and human reviewers…]]></description><link>https://innunext.hashnode.dev/how-to-prevent-apple-app-store-google-play-rejections-the-2025-2026-checklist</link><guid isPermaLink="true">https://innunext.hashnode.dev/how-to-prevent-apple-app-store-google-play-rejections-the-2025-2026-checklist</guid><category><![CDATA[React Native]]></category><category><![CDATA[Android]]></category><category><![CDATA[iOS]]></category><category><![CDATA[app store]]></category><category><![CDATA[Playstore]]></category><dc:creator><![CDATA[Inayat Ali]]></dc:creator><pubDate>Sun, 08 Nov 2026 01:00:28 GMT</pubDate><content:encoded><![CDATA[<h1>How to Prevent Apple App Store &amp; Google Play Rejections (The 2025/2026 Checklist)</h1>
<p>Most mobile launch delays aren't caused by broken code. They're caused by failing strict platform compliance rules that automated bots and human reviewers test in the first 5 minutes.</p>
<p>Here is the exact checklist I use to ship production React Native apps to the App Store and Google Play on the first attempt.</p>
<hr />
<h2>1. Apple Guideline 5.1.1(v) — Missing In-App Account Deletion</h2>
<p>If your app lets users create an account, you <strong>must</strong> allow them to permanently initiate account deletion directly within the app.</p>
<ul>
<li>❌ <strong>Rejection:</strong> Directing users to a web link (<code>"Contact support to delete"</code>) or an email address.</li>
<li>✅ <strong>Approval:</strong> A visible <code>Delete Account</code> button inside <code>Profile -&gt; Settings</code> with a confirmation modal and an automated server-side token revocation job.</li>
</ul>
<hr />
<h2>2. Apple Guideline 3.1.1 — In-App Purchases vs. Stripe</h2>
<p>The rule is straightforward:</p>
<table>
<thead>
<tr>
<th>What you're selling</th>
<th>Allowed payment gateway</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Digital Goods</strong> (AI tokens, SaaS unlock, extra lives, in-app badges)</td>
<td><strong>Apple StoreKit / Google Play Billing</strong> (RevenueCat)</td>
</tr>
<tr>
<td><strong>Real-World Goods &amp; Services</strong> (Rides, physical merch, event tickets, food delivery)</td>
<td><strong>Stripe / PayPal / Card</strong></td>
</tr>
</tbody></table>
<p>If you try to unlock an AI chat feature or premium mobile tier using Stripe, Apple will reject the binary immediately.</p>
<p><strong>Always include on the paywall:</strong></p>
<ul>
<li>A visible <code>Restore Purchases</code> button.</li>
<li>Clear subscription duration and pricing terms.</li>
<li>Direct links to your <code>Privacy Policy</code> and <code>Terms of Use</code>.</li>
</ul>
<hr />
<h2>3. iOS Privacy Manifests (<code>PrivacyInfo.xcprivacy</code>)</h2>
<p>Apple now enforces Privacy Manifests for all apps and third-party SDKs using <strong>Required Reason APIs</strong>:</p>
<ul>
<li>File timestamp access</li>
<li><code>UserDefaults</code> / System boot time</li>
<li>Disk space queries</li>
</ul>
<p>Verify that every native package in your app declares its required reasons. If you use Expo EAS, modern SDKs (51+) generate this automatically, but any custom native module must have an explicit <code>.xcprivacy</code> declaration.</p>
<hr />
<h2>4. Google Play: Background Location &amp; Foreground Services</h2>
<p>Android 14+ will immediately reject your release if you request <code>ACCESS_BACKGROUND_LOCATION</code> or use generic foreground services without justification.</p>
<ul>
<li><p>❌ <strong>Rejection:</strong> Vague permission prompt like <code>"App needs location to work."</code></p>
</li>
<li><p>✅ <strong>Approval:</strong> Prominent user-facing disclosure dialog <em>before</em> the OS prompt appears, clearly explaining the user benefit:</p>
<pre><code class="language-json">"NSLocationWhenInUseUsageDescription": "Used to calculate live turn-by-turn route dispatch and locate nearby transit stops."
</code></pre>
</li>
<li><p><strong>Pro Tip:</strong> Google Play Console requires a 30-second in-app video recording showing how the background feature is triggered by the user.</p>
</li>
</ul>
<hr />
<h2>5. App Store Reviewer Sandbox Credentials (Guideline 2.1)</h2>
<p>Never give Apple reviewers an empty state or broken onboarding flow:</p>
<ul>
<li>Create a dedicated demo account with pre-populated dummy data (orders, messages, profile).</li>
<li>Provide username + password directly in the <strong>App Review Information</strong> notes field.</li>
<li>If your app requires SMS OTP verification, configure a static test phone number (<code>+1 555-0199</code>) with a fixed OTP (<code>123456</code>) in your backend for the reviewer.</li>
</ul>
<hr />
<h2>Summary Cheat Sheet</h2>
<table>
<thead>
<tr>
<th>Requirement</th>
<th>Apple Guideline</th>
<th>Google Play Equivalent</th>
</tr>
</thead>
<tbody><tr>
<td>In-app account deletion</td>
<td>5.1.1(v)</td>
<td>Data Safety Policy</td>
</tr>
<tr>
<td>In-App Purchases for digital unlocks</td>
<td>3.1.1</td>
<td>Play Billing Policy</td>
</tr>
<tr>
<td>Required Reason API manifest</td>
<td>Privacy Manifest</td>
<td>Data Safety Declarations</td>
</tr>
<tr>
<td>Clear permission justification</td>
<td>Human Interface Guidelines</td>
<td>Target API 34+ Foreground Types</td>
</tr>
<tr>
<td>Reviewer demo login with test data</td>
<td>2.1 App Completeness</td>
<td>App Access Instructions</td>
</tr>
</tbody></table>
<hr />
<p>Need help getting an enterprise build approved or resolving an active rejection notice? I document production architecture and submission playbooks at <a href="https://innunext.com">innunext.com</a> and conduct direct <a href="https://innunext.com/guides/apple-app-store-google-play-rejection-checklist">App Store &amp; Google Play compliance reviews</a>.</p>
<hr />
]]></content:encoded></item><item><title><![CDATA[How to Fix React Native Lag, Memory Leaks & Hit 60 FPS in Production]]></title><description><![CDATA[reactnative, javascript, mobile, performance, typescript]]></description><link>https://innunext.hashnode.dev/how-to-fix-react-native-lag-memory-leaks-hit-60-fps-in-production</link><guid isPermaLink="true">https://innunext.hashnode.dev/how-to-fix-react-native-lag-memory-leaks-hit-60-fps-in-production</guid><category><![CDATA[React Native]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[Mobile Development]]></category><category><![CDATA[performance]]></category><category><![CDATA[Performance Optimization]]></category><dc:creator><![CDATA[Inayat Ali]]></dc:creator><pubDate>Fri, 06 Nov 2026 16:25:09 GMT</pubDate><content:encoded><![CDATA[<h1>How to Fix React Native Lag, Memory Leaks &amp; Hit 60 FPS in Production</h1>
<p>After auditing 12+ production React Native codebases, 80% of "the app feels slow" complaints trace back to the same 3 root causes.</p>
<p>Here's the exact fix for each.</p>
<hr />
<h2>1. Stop Re-Rendering Everything on Every State Tick</h2>
<p>The most common frame drop: anonymous inline callbacks creating new function references on every parent render.</p>
<pre><code class="language-js">// ❌ New function on every render → child re-renders every time
&lt;List onPress={() =&gt; navigate("Detail", { id })} /&gt;

// ✅ Stable reference → no unnecessary re-renders
const handlePress = useCallback(() =&gt; navigate("Detail", { id }), [id]);
&lt;List onPress={handlePress} /&gt;
</code></pre>
<p>Also swap <code>AsyncStorage</code> for <strong>MMKV</strong> on mount reads — it's C++ JSI, synchronous, and 10x faster for cold-start hydration.</p>
<hr />
<h2>2. Memory Leaks — The Silent Killer</h2>
<p>Apps using WebSockets, Supabase listeners, background GPS, or BLE leak memory every time a screen unmounts without cleaning up native subscriptions. Over 20 minutes: Android kills the process, iOS jetsams it.</p>
<pre><code class="language-js">useEffect(() =&gt; {
  const controller = new AbortController();
  const unsubscribe = socket.subscribe("channel", (payload) =&gt; {
    if (!controller.signal.aborted) setState(payload);
  });
  return () =&gt; {
    controller.abort();
    unsubscribe(); // No zombie listeners, no RAM retention
  };
}, [channelId]);
</code></pre>
<p><strong>Rule:</strong> Every <code>useEffect</code> that opens a subscription, timer, or native listener must return a cleanup function. No exceptions.</p>
<hr />
<h2>3. FlatList → FlashList + Fix Your Images</h2>
<p><code>FlatList</code> doesn't recycle views during fast scrolling → blank cells → perceived lag.</p>
<pre><code class="language-jsx">// Drop-in replacement, same API
import { FlashList } from "@shopify/flash-list";

&lt;FlashList
  data={items}
  renderItem={renderItem}
  estimatedItemSize={72} // Measure your actual item height
/&gt;
</code></pre>
<p>And never decode a 4000×3000px upload inside an 80×80px avatar:</p>
<pre><code class="language-jsx">// ✅ Request the right size from your CDN
const thumb = `${user.avatarUrl}?w=160&amp;h=160&amp;fit=crop`;
</code></pre>
<p>Use <code>expo-image</code> over the built-in <code>Image</code> for hardware-decoded caching.</p>
<hr />
<h2>4. Move Animations to the UI Thread</h2>
<p>Any <code>Animated.Value</code> on the JS thread drops frames the moment a network call or navigation fires.</p>
<pre><code class="language-js">// ❌ JS thread — stutters during API calls
Animated.timing(opacity, { toValue: 1, useNativeDriver: true }).start();

// ✅ Reanimated worklet — C++ UI thread, frame-perfect
const opacity = useSharedValue(0);
const style = useAnimatedStyle(() =&gt; ({ opacity: withTiming(opacity.value) }));
</code></pre>
<hr />
<h2>Diagnostic Order</h2>
<p>Profile on a <strong>real mid-range Android device in release mode</strong> — never Metro dev mode (timings are 3–5x slower).</p>
<pre><code class="language-plaintext">1. React DevTools Profiler → find heaviest re-render tree
2. Audit all useEffects for missing cleanup
3. FlatList → FlashList on any list &gt; 50 items
4. CDN-resize images to display size
5. Migrate animations to Reanimated worklets
6. Enable New Architecture in app.json (Expo SDK 51+)
</code></pre>
<hr />
<p>Performance bugs in React Native are diagnosable, not mysterious. These 4 patterns cover 90% of real-world production cases.</p>
<p>If your existing app is lagging or crashing on Android, I write about more patterns like this at <a href="https://innunext.com">innunext.com</a> and do deep-dive <a href="https://innunext.com/guides/fix-react-native-memory-leaks-60fps">production audits</a>.</p>
<hr />
<p><em>Tags:</em> <code>reactnative</code> <code>javascript</code> <code>mobile</code> <code>performance</code> <code>typescript</code></p>
]]></content:encoded></item></channel></rss>