Back to Home

// APP LESSONS

Building an App: Lessons Learned

Everything They Don't Tell You Before You Ship.

I built WORKA from scratch — a full AI fitness app on both the App Store and Google Play. These are the things I had to figure out the hard way: frameworks, submissions, licenses, paywalls, permissions, testing, and building for Apple Watch. Save yourself the pain.

Shipping a mobile app to both stores is a different game than building a website. There are licenses, legal requirements, platform-specific rules, and build tooling quirks that will blindside you if you don't know about them ahead of time.

This isn't a tutorial on how to build an app. It's the list of things I wish someone told me before I started — the stuff that cost me hours of debugging, rejected submissions, and frustration.

10 lessons. All from experience. All things that would have saved me time if I knew them on day one.

// THE LESSONS

10 Things I Learned Shipping to Both Stores

// FRAMEWORK CHOICE

01

If You Want Android and iOS — Use Expo.

Expo is the best cross-platform framework right now. It handles native modules, OTA updates, build tooling (EAS), and has a massive ecosystem of pre-built packages. You write once and deploy to both platforms without touching Xcode or Android Studio for most things.

Other solid options: React Native (bare workflow if you need full native control), Flutter (Dart-based, great UI toolkit from Google), and .NET MAUI (if you're in the Microsoft/C# ecosystem). Each has trade-offs, but for most indie builders, Expo is the fastest path to both stores.

If you're only targeting iOS, skip the cross-platform overhead entirely. Go straight Swift with SwiftUI — it's Apple's native framework and gives you the best performance, tightest OS integration, and access to every new API on day one.

> Expo + EAS Build is the lowest friction path from zero to both app stores. Start there unless you have a specific reason not to.

// SUBMISSION REQUIREMENTS

02

You Need a Privacy Policy and Terms — Or You Don't Submit.

Both Apple and Google require a privacy policy URL and terms of service before you can submit your app. This isn't optional — your app will get rejected without them. Apple checks these during review, and Google requires them in the Play Console before you can even publish.

You can host them as simple pages on your website, or use a free generator to get started. Just make sure they're accessible via a public URL and actually describe what your app does with user data.

Don't leave this for the last minute. Set them up early, link them in your app's settings screen, and make sure they're referenced in your store listing.

> Create a /privacy and /terms page on your marketing site. Simple, static, and always accessible.

// DEVELOPER LICENSES

03

$99/Year for Apple. $25 One-Time for Google. Budget Accordingly.

Apple Developer Program costs $99/year. You need it to distribute on the App Store, test on physical devices via Xcode, and access APIs like push notifications, Sign in with Apple, and CloudKit. No license = no App Store.

Google Play Developer registration is a one-time $25 fee. That's it. You pay once and you're in forever. The barrier to entry is much lower, which is why the Play Store has more apps (and more junk).

If you're bootstrapping, factor these into your costs from day one. The Apple fee renews annually — if it lapses, your apps get pulled from the store.

> Sign up for both early. Apple's enrollment can take a few days to process, and you don't want that blocking your launch.

// AI APP DISCLOSURES

04

AI Apps Need Disclosures — What Data Goes Where and to Which APIs.

If your app uses AI (OpenAI, Claude, Gemini, etc.), both stores now require you to disclose what user data is sent to third-party AI services. Apple updated their guidelines to specifically address this — you need to explain what data leaves the device, which APIs receive it, and how it's processed.

Google has its own AI-generated content policy. If your app generates content using AI, you need to be transparent about it. This includes labeling AI-generated content and disclosing third-party AI service usage in your data safety section.

Be specific in your privacy policy: 'We send your workout data to the OpenAI API for coaching recommendations' is better than 'We use AI features.' Reviewers read these now.

> Add an in-app disclosure screen that explains your AI features and data flow. It helps with both store reviews and user trust.

// PAYWALL SETUP

05

Your Paywall Needs Terms, Privacy, and Crystal-Clear Trial Info.

Apple and Google both require that your paywall screen includes links to your Terms of Service and Privacy Policy. If you have a free trial, you must clearly state how long it lasts, what happens when it ends, and how much the user will be charged. This is a top rejection reason.

Add these links at the bottom of your paywall. Make the trial terms impossible to miss — not buried in fine print. 'Start your 7-day free trial. $9.99/month after.' That's it. Clear, honest, visible.

If your app uses AI features behind the paywall, add a disclosure about what data the AI processes. RevenueCat's paywall components have built-in support for terms/privacy links — use them.

> Use RevenueCat for subscription management. Their paywall templates already include the required legal links and follow store guidelines.

// GPS TESTING

06

You Can Test GPS From a Simulator — Or Build a Dev Version.

If your app uses location services, you don't need to run around outside to test it. Xcode's iOS Simulator lets you set custom GPS coordinates, simulate routes (like a freeway drive), and load GPX files with custom paths. Android Studio's emulator has the same — Extended Controls lets you set lat/long or simulate GPS routes.

For more realistic testing, build a development version and install it on your actual phone. This is especially important for background location, geofencing, and GPS accuracy testing — simulators don't perfectly replicate real-world GPS behavior.

Either way, test GPS early. Location permissions, background tracking, and battery impact are all things that behave differently on real devices vs simulators.

> Use GPX files for repeatable location test routes. Both Xcode and Android Studio support them.

// IOS DEV BUILDS

07

To Test on Your iPhone — You Need the License and Developer Mode.

To build and run a dev version of your app on a physical iPhone, you need an active Apple Developer license ($99/year) and Developer Mode enabled on your device. Without both, Xcode won't let you install your app.

Enable Developer Mode in Settings > Privacy & Security > Developer Mode (iOS 16+). Then in Xcode, select your iPhone as the build target and hit Run. Xcode handles provisioning profiles and signing automatically if you're signed into your developer account.

First-time setup takes a few minutes — Xcode needs to register your device and create certificates. After that, building to your phone is one click.

> If you're using Expo, you can also create dev builds with EAS Build and install them via QR code — no Xcode required for the build itself.

// ANDROID VS IOS BUILDS

08

Android Is Easier to Test. iOS Requires Xcode. It's Annoying AF.

Android builds are faster and simpler. You can build an APK or AAB from the terminal with a single Gradle command (./gradlew assembleDebug or bundleRelease), transfer it to your phone, and you're testing. No IDE required for the build step.

iOS? You need Xcode. Period. Even if you use Expo and EAS Build for production builds, local dev builds still need Xcode for the simulator and device deployment. Xcode is slow, takes up 15+ GB of disk space, and the build process is noticeably longer than Android.

This isn't a deal breaker — it's just reality. Budget more time for iOS builds and testing. If you're on a tight timeline, get your Android version stable first, then tackle iOS-specific issues.

> Keep Xcode updated — outdated versions cause the most cryptic build failures. And buy more storage. You'll need it.

// PERMISSIONS

09

Android Wants a Prominent Disclosure. iOS Doesn't. Handle Both.

Permissions work differently on each platform. On iOS, you add purpose strings (NSLocationWhenInUseUsageDescription, etc.) to your Info.plist explaining why you need the permission. The system shows these when requesting access. That's it — Apple doesn't require a separate disclosure screen.

Android is stricter for background permissions. Google Play requires a 'prominent disclosure' — an in-app screen that clearly explains why you need background location (or other sensitive permissions) before you request them. If you skip this, your app gets rejected.

Build a permissions flow that handles both: on Android, show the disclosure screen first, then request the permission. On iOS, just request it with a clear purpose string. Use Platform.OS checks to handle the difference.

> For background location on Android, the prominent disclosure must appear BEFORE the system permission dialog. Google reviews this manually.

// APPLE WATCH

10

Apple Watch Needs a Separate Swift Repo — With the Bacon Plugin for Expo.

If you want to build for Apple Watch, you need a separate Swift/SwiftUI target that builds alongside your iOS app. The Watch app lives in its own directory within the Xcode project and communicates with your iOS app via WatchConnectivity.

If you're using Expo, you can't build a Watch app purely in JavaScript. You need the @bacons/apple-targets config plugin (from Evan Bacon) which lets you add a native watchOS target to your Expo project. It generates the required Xcode project structure and lets your Watch app build alongside the Expo iOS app.

The Watch app itself is written in Swift/SwiftUI — there's no way around that. But the plugin handles the build configuration so you don't have to manually manage the Xcode workspace. It's the bridge between Expo's managed workflow and Apple's native watchOS tooling.

> Start with a minimal Watch complication or glance before building a full Watch app. WatchConnectivity debugging is painful — keep the data transfer simple.

Ship it. Even if it's not perfect.

Every rejection teaches you something. Every platform quirk you solve makes the next app easier. The hardest part isn't the code — it's navigating the ecosystem around it. Now you know what to expect.

Follow for more →