App Dev
Mobile architecture with React Native and Expo, store asset production, performance tuning, and post-launch operations for indie developers shipping apps.
My Ads Never Came Back After a Subscription Expired: Fixing the Direction of an Ad-Free Check
An ad-free flag stayed on after the subscription expired because the check pointed the wrong way. Here is how I rebuilt it to wait for two purchase queries, decide only from confirmed facts, and keep the last value on failure.
When adjustsFontSizeToFit Shrinks Just One Row, Suspect the Box Height, Not the String
Only the 10th row of a list drops to 4pt on iOS, though the data and strings are fine. I read the Yoga rounding and font-fit sources, then counted how often the box comes up short in Node.
When Only EAS Build Fails with "No matching variant", Check Your Local android/build First
Gradle passes on your machine, but the Android build on EAS stops at "No matching variant of project". Reading the reports on GitHub, I traced how a Windows-generated autolinking cache can reach the Linux builder, and wrote a small script that checks for it before you queue a build.
App Review Says "Guideline 2.1, Blank Screen": Three Places to Look in an Expo Release Build
It opens fine in TestFlight, yet review rejects it for a blank screen. Here is the order I check things in an Expo + EAS release build: which environment holds your variables, secret visibility during config resolution, and what the reviewer's device does differently.
When only notifications fail in Expo Go: three checks, then the shortest move to a development build
If push notifications never reach your Android device in Expo Go, check these three things before touching device settings, then move to a development build with the fewest steps. Also: how to spot what else Expo Go can't test.
Your Expo Router App Flashes the Sign-In Screen on Every Launch. Rebuild the Guard With a Third State: Not Known Yet
Signed in, yet the sign-in screen flashes at launch; signed out, yet the screen never changes. How I rebuilt Expo Router Protected routes around three Supabase auth states, including the one the docs never name, and where the _layout.tsx files have to live.
It Crashed, but the Reviews Say "It Freezes" — When an Android Crash Leaves a Blank Screen Behind
Your crash reports show exceptions, yet users only ever say the app freezes. Here is why expo-updates plus the New Architecture can leave an empty Android screen behind, and the order I now use: a way out first, a bad-exit marker second, root cause last.
The three lines I check when prebuild stops on the standard SDK 57 Swift AppDelegate error
Turning on ios.enableSceneSupport for iOS 27 can stop prebuild cold. The cause was not my SDK version but the shape of AppDelegate.swift. Here are the three lines to check, and why copying the SDK 58 migration steps by hand will break your build.
The Token I Deleted Came Back After a Restart — Detecting Failed SecureStore Deletes
On Android, getItemAsync can report null right after sign-out while the value is still sitting on disk. Here is how I rewrote a sign-out path that was verifying deletion by reading instead of by the delete result.
Your First EAS Workflow in a Rork Repo, and the Alert That Goes Missing Exactly When You Need It
Putting two files into .eas/workflows in a repo exported from Rork, and why a notification wired with needs stays silent on exactly the nights it fails — with the output of a small local checker I actually ran.
Those 14 Days of Closed Testing Are for Gathering What the Production Form Asks
Google Play production access starts from a closed test with 12 testers opted in continuously for 14 days. Here is how the count actually works, the order the tracks open in, what the application form asks, and the records worth keeping during those two weeks.
Sending user text to an external AI: what actually goes in Play's Data safety form
Classifying user input sent to an external AI as collected, shared, or ephemeral in Play's Data safety form, plus a redaction ordering bug found by running the code.
Leave image out of eas.json and an SDK bump moves your Xcode and pnpm too
If eas.json has no image field, your builds run on the auto alias. Move one SDK alias and Xcode, Node.js, pnpm and fastlane all change together. Here is how to read the image name out of your last green build and decide whether to pin it before Xcode 27 lands.
After Bumping targetSdk to 36, Which Part of Your Dependencies Should You Actually Read
I opened six real dependency AARs and counted what they contribute to my manifest. Not one declares targetSdkVersion, and twelve permissions arrive that I never wrote. Here is what to check before you submit.
Two weeks of half-finished batch runs, and every log line said success
A job scheduled twice a day was firing once, and nothing in the logs showed it. Here is the run ledger that catches executions that never happened, plus a backlog-slope check, with real command output.
What Android 16 ignores on tablets, and why app.json gives you no way out
Targeting API level 36 means screenOrientation is ignored on displays at least 600dp wide. Here is how to check your project without a tablet, why app.json cannot express a fix, and what the opt-out property actually restores.
Put Your Live Rork App on a Spare iPhone Before iOS 27 Ships
iOS 27 arrives in September and developer beta 7 is already out. Here is how to turn an old iPhone into a beta device, what to check first, and which fixes you can ship from JavaScript without waiting for review.
I Moved the Thumbnails Assuming the Shipped Build Would Keep Asking for the Old Path
Reorganizing image directories on the server does not reach the builds already installed on people's phones. Here is the two-way fallback that returns 200 for both the old and new paths, the ordering rule for images versus catalog, and the four checks I run through a CDN before calling a release live.
Bumping targetSdk to 36 surfaced a 16 KB warning. These are two different deadlines
The August 31 target API 36 requirement and the February 1, 2027 16 KB page size requirement are separate conditions. Here is how to inspect your AAB without installing the NDK, and why a LOAD misalignment and a zip boundary miss need completely different fixes.
Apple's automated pass reads what your purpose strings are for, not whether they exist
Submit a Rork or Expo iOS build and you may get it back under Guideline 5.1.1 with a note about placeholder or otherwise insufficient purpose strings. Here is how to read a rejection that names no key, and how to rewrite the strings from app.json.
The three places I had to fix before a Rork project actually targeted API level 36
My app.json said targetSdkVersion 36. The value my build actually read was 35. Here is the script that reports the effective value, and how I split my apps between raising, leaving alone, and requesting an extension.
My chart broke on day one, not at scale
A line chart that vanished for anyone with only a few days of data. The cause was a zero-height Y axis turning coordinates into NaN. Here is the measured behavior and the small normalization layer that fixed it.
TestFlight External Testing or Phased Release: Where a Solo Developer's Time Actually Pays Off
When you ship a Rork-built app to other people, you can recruit external testers or let a phased release absorb the risk. Here is how I split my limited time between the two, based on where distribution actually stalls and which three areas still deserve pre-release checks.
Deciding overlay text legibility at ingest time instead of on device — four metrics measured side by side
Moving the question of whether text stays readable over a wallpaper out of the device and into the content pipeline. Four candidate metrics measured across 240 images, including what downscaled judging actually computes.
A JSON File 19% Smaller That Ships Only 3% Smaller — Measuring Catalog Payloads Against gzip
Five payload formats measured on a 20,000-item wallpaper catalog. Key shortening saves just 3.2% after gzip, while a columnar layout cuts 26.8%. Real numbers for Brotli, paging, and JSON.parse time.
When 1.10.0 Gets Locked Out: Measuring Four Version Comparison Approaches for Forced Updates
A remote-config gate for minimum supported version, rebuilt after measuring four version comparison approaches. Includes the cases where localeCompare reports equality, the fail-open boundary, and the incident caused by gating on a build still in review.
My generated wallpaper catalog hashed differently on every run — isolating five sources of nondeterminism
The same image folder refused to produce the same catalog.json twice. Directory enumeration order, JSON.stringify key reordering, collation, Unicode normalization, and async completion order — measured one at a time across 1,225 files until the output settled on a single hash.
The same wallpaper appeared twice in my catalog — measuring perceptual hash thresholds across 324 images
Four approaches to image catalog deduplication measured end to end: SHA-256, dHash, a hue signature, and a block signature. dHash alone scored 0.9% precision. Here is why perceptual hashes collapse on smooth images, and how the ground truth turned out to be the thing that was wrong.
Walk Through an App Store Submission Without Writing Code — Sticker Packs as a Dress Rehearsal
An iMessage sticker pack is one of the few things you can ship to the App Store with zero code. It cannot make money — and that constraint is exactly what makes it a clean rehearsal for the submission process.
Placing Native Ads in a Masonry Wallpaper Grid: Designing the Lifetime of an Ad Cell
One native ad in a masonry gallery pushed memory from 180 MB to 420 MB over twenty minutes of scrolling. Here is why cell recycling and ad object lifetime never line up, the pool-based implementation that fixed it, and how I picked the insertion interval from measured numbers.
Long-Press Context Menus for a Gallery Item in a Rork Expo App
Long-pressing a wallpaper card does nothing, yet iOS users expect a preview and a menu. From why Pressable alone falls short, to a native context menu with zeego, resolving the scroll-vs-long-press conflict, wiring up save and share, and a custom overlay fallback for Android — all with working code.
You Only Need to Capture the 6.9-inch iPhone for App Store Screenshots
App Store Connect only requires two screenshot sizes: the 6.9-inch iPhone and the 13-inch iPad. Building on Apple auto-downscaling for smaller devices, here is how I use fastlane snapshot and frameit to cut the screenshot count for a multi-language app.
Answering the New App Store Age Ratings — Field Notes From Updating Several Live Apps
Notes from re-answering the updated App Store age rating questions across live apps, covering the new 13+/16+/18+ tiers, the four new question categories, setting a higher minimum age, and what it means for apps you ship with Rork.
Laying Out Variable-Height Images in Two Columns: A Masonry Wallpaper Gallery in a Rork Expo App
From why numColumns cannot pack variable-aspect images cleanly, to a dependency-free column-balancing algorithm, to keeping virtualization with FlashList masonry and a pragmatic no-dependency fallback, building a wallpaper gallery with real code.
Building a One-Time Code Field in Expo — SMS Autofill and Segmented Display Together
A six-digit verification screen looks trivial, but once you account for SMS autofill, pasting, and deleting one digit at a time, it needs real care. Here is how to nail the iOS and Android autofill first, then build a segmented look on top of a single TextInput that does not break.
Rork Max (Swift) or the Standard Version (React Native): How to Decide as a Solo Developer
Stuck between Rork Max's native Swift and the standard React Native version? Here is a practical decision framework built from a solo developer's perspective, weighing cost, feature boundaries, and how easy each path is to migrate later.
Making Your Rork Max App Resilient to Dropped and Restored Connections: Offline Detection and Retry with NWPathMonitor
Build networking that survives a lost signal in your Rork Max native Swift app with NWPathMonitor. Detect offline states, respect Low Data Mode and cellular, and auto-resend queued work on reconnect — all with working Swift code.
Adding Read-Aloud to a Rork Max App: AVSpeechSynthesizer Voice Selection and Live Word Highlighting
An implementation memo on adding read-aloud to a native Swift app generated by Rork Max — covering AVSpeechSynthesizer voice selection, highlighting the word being spoken, audio session design, and the pitfalls that bite specifically with Japanese text.
Adding PDF Viewing and Export to a Rork Max App — When to Use PDFKit vs. ImageRenderer
Implement PDF viewing, search, and export in Rork Max's native Swift with PDFKit. Covers UIGraphicsPDFRenderer vs. ImageRenderer trade-offs, password protection, and share sheet integration.
Keeping Downloads Alive After Your Rork Max App Is Killed: Background URLSession Design and Relaunch Handling
How to design downloads in a Rork Max native Swift app so transfers continue in the OS daemon even after the app is suspended or terminated. Covers relaunch wiring, resumeData recovery, and measured isDiscretionary behavior with working code.