Build Finalization and Submission Readiness

1

Build Finalization and Submission Readiness

▶

Submitting an app to a public store — whether the Apple App Store, Google Play, or another distribution platform — is the culmination of every design decision, line of code, and testing cycle that came before it. Yet the submission process itself is not a formality; it is a disciplined engineering and product management phase in its own right. A poorly prepared submission can be rejected outright, trigger a lengthy review delay, or worse, reach end users in a broken state. This topic walks through every critical dimension of build finalization and submission readiness: configuring a proper release build, executing a structured pre-submission test plan, managing version numbers and release notes, and assembling the complete set of deliverables that stores expect to receive.

Release Build Configuration

A release build is fundamentally different from the debug or development build you use during daily development. During development, many tools and settings exist purely to make your life easier — they expose internal state, bypass security checks, stream verbose logs, and connect to sandboxed test servers. Every single one of those accommodations must be resolved before a build leaves your hands and enters a store's review pipeline.

Disabling debug logging, breakpoints, and developer tools is the first and most critical configuration step. Debug log statements left active in a production build are not merely wasteful — they are a security liability. Log output can expose API keys, user data, internal server addresses, or authentication tokens to anyone with access to a device and a log viewer. On Android, tools like Logcat make it trivial to read application logs from any connected device. On iOS, the unified logging system is similarly accessible. The correct approach is to gate all logging behind a compile-time or runtime flag so that verbose output is completely suppressed in release mode. Many teams use a logging abstraction layer for exactly this reason:

// Example: Conditional logging wrapper (Swift)
func appLog(_ message: String) {
    #if DEBUG
    print("[DEBUG] \(message)")
    #endif
}

Similarly, any in-app developer menus, diagnostic overlays, shake-to-debug panels, or network inspection proxies (such as Charles Proxy configurations or Flipper plugins) must be completely removed or disabled in the release variant. Leaving a hidden developer menu accessible in a production app is a common cause of store rejection and a potential security vulnerability.

Incrementing the app version number and build number before each submission is a hard requirement enforced by every major app store. Both the Apple App Store and Google Play will reject a submission whose version or build identifier matches a previously uploaded build. Beyond avoiding rejection, proper version increments are the foundation of release traceability — they let you correlate crash reports, user complaints, and analytics events to a specific code snapshot. This is covered in greater depth in the version numbering section below.

Configuring production API endpoints, keys, and credentials is one of the most consequential and most frequently overlooked steps. During development, it is standard practice to point the app at a staging or development server, use test API keys, and connect to sandboxed payment or authentication environments. A release build must be wired to production infrastructure. This includes:

  • Base URLs for all REST or GraphQL APIs switched from staging to production hostnames
  • API keys and client credentials rotated to production-tier keys with appropriate rate limits and permissions
  • Payment processor keys switched from test/sandbox mode to live mode
  • Analytics and crash reporting SDKs pointed at production projects so data flows to the correct dashboards
  • Push notification certificates or tokens registered against the production APNs or FCM environment

A robust way to manage this is through build-variant–specific configuration files. In Android, build.gradle supports buildTypes with separate buildConfigField values. In iOS, separate .xcconfig files or environment-specific plist entries serve the same purpose. The goal is that the correct configuration is selected automatically by the build system without any manual find-and-replace editing, which is error-prone.

// Android build.gradle example
buildTypes {
    release {
        buildConfigField "String", "API_BASE_URL", '"https://api.production.example.com"'
        buildConfigField "String", "API_KEY", '"prod_key_xyz"'
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
    debug {
        buildConfigField "String", "API_BASE_URL", '"https://api.staging.example.com"'
        buildConfigField "String", "API_KEY", '"dev_key_abc"'
    }
}

Testing release builds on physical devices or production-equivalent environments closes the gap between what works in the simulator or emulator and what users will actually experience. Hardware-specific issues — GPU rendering differences, camera permissions, NFC, biometric authentication, cellular network behavior — only surface on real devices. Ideally, the exact signed release artifact (the .ipa or .aab/.apk) that will be submitted to the store should be installed on physical test devices via TestFlight, Firebase App Distribution, or direct sideloading. This ensures that code signing, entitlements, and ProGuard/R8 obfuscation have not inadvertently broken any functionality.

Pre-Submission Testing Checklist

Testing a release candidate is not the same as running your regular regression suite. Pre-submission testing is a deliberate, end-to-end verification pass conducted against the actual release build, with the explicit goal of catching anything that would cause a bad user experience or a store rejection. A structured checklist approach ensures nothing is skipped under deadline pressure.

Testing all core user flows end-to-end on both minimum and current supported OS versions is the cornerstone of pre-submission testing. Most apps declare a minimum OS version in their manifest or project settings. Users running that minimum version represent a real segment of your audience and typically cannot upgrade their OS due to hardware limitations. Bugs that appear only on older OS versions are common because API behavior changes, deprecated methods get removed, and UI rendering differs across system versions. Your checklist should enumerate every critical user journey — onboarding, login, core feature usage, settings, logout, error states — and verify each one on both the oldest supported OS and the latest release.

Verifying that all external links, URLs, and API integrations are functional in the release build catches a category of bugs that is invisible during unit testing: broken connections to the outside world. Common failures include:

  • Help center or support links that were changed on the website but not updated in the app
  • Social login flows (Sign in with Apple, Google OAuth) that fail because the OAuth redirect URI is registered only for the debug bundle identifier
  • Deep links or universal links that are broken because the associated domain configuration was not updated
  • Production API endpoints that return errors because CORS policies, SSL certificates, or firewall rules differ from the staging environment

Each of these should be exercised manually or through automated integration tests that run against the production environment using a dedicated QA account.

Testing the app on a range of physical device sizes and screen resolutions is especially important for platforms with highly fragmented hardware ecosystems. On Android, the variety of screen densities, aspect ratios, and display cutout shapes is enormous. On iOS, the range spans from the compact iPhone SE form factor to the largest iPad Pro. UI elements that look perfect on the device you used during development may be clipped, overlapping, or incorrectly sized on edge-case screen configurations. Pay particular attention to:

  • Text truncation on narrow screens
  • Keyboard overlap on forms in devices with smaller displays
  • Notch, Dynamic Island, and camera cutout safe area handling
  • Landscape orientation if supported
  • Large text / accessibility font size settings

Reviewing the app against each target platform's review guidelines before submission is the most efficient form of rejection prevention. Both Apple's App Store Review Guidelines and Google Play's Developer Policy Center are detailed, publicly available documents. Common reasons for rejection include: insufficient app functionality, misleading metadata, incomplete privacy nutrition labels, use of private APIs, broken demo account credentials, and missing required permissions justifications. Treating these guidelines as a checklist — not merely as documents to acknowledge during account setup — dramatically reduces the probability of rejection on first submission.

Confirming that in-app purchases, subscriptions, or monetization features function correctly in the production environment is a critical and frequently underestimated testing area. Test environments for in-app purchases (Apple's Sandbox environment, Google Play's test purchase accounts) behave differently from production in several ways: pricing tiers, subscription renewal intervals, receipt validation behavior, and promotional offer eligibility can all differ. Before submission, verify that:

  • All purchasable products are correctly configured and approved in the respective store console
  • Purchase flows complete successfully and unlock the correct content or features
  • Restore purchases functionality works for users who have previously purchased
  • Subscription management links (Apple's subscription management page, Google Play's subscription center) are correctly surfaced in the app
  • Server-side receipt validation, if implemented, functions against production receipts

Version Numbering and Release Notes

Version numbering is both a technical requirement and a communication tool. Done well, it creates a shared language between developers, QA engineers, support teams, and users. Done poorly, it causes confusion, complicates debugging, and can block store submissions.

Version numbers must be incremented with each new submission. Stores enforce this mechanically — attempting to upload a build with a version or build number that matches a previously uploaded build will result in an immediate, automated rejection. The standard convention for user-facing version numbers is Semantic Versioning (SemVer), structured as MAJOR.MINOR.PATCH:

Segment When to Increment Example
MAJOR Breaking changes, complete redesigns, or significant feature overhauls 1.0.0 → 2.0.0
MINOR New features added in a backward-compatible manner 2.3.0 → 2.4.0
PATCH Bug fixes, performance improvements, minor corrections 2.4.1 → 2.4.2

Each platform has a separate internal build number or version code that must also be incremented. The user-facing version string (CFBundleShortVersionString on iOS, versionName on Android) is what users see. But each platform also uses a separate numeric identifier for internal tracking: CFBundleVersion on iOS and versionCode on Android. This internal identifier must be a strictly increasing integer with every upload, even if the user-facing version string does not change (for example, when re-uploading after a rejected build). Many teams automate this using CI/CD pipelines with tools like Fastlane, which can auto-increment build numbers from a remote source of truth such as a Git tag or build server counter.

Release notes should clearly describe new features, bug fixes, and any significant changes. Release notes appear on the store listing and are often the first thing a user reads before deciding whether to update. They serve a dual purpose: informing users about improvements and signaling to reviewers what has changed since the last approved version. Effective release notes are:

  • Specific — "Fixed a crash that occurred when users uploaded photos larger than 10 MB" is more useful than "Bug fixes and performance improvements"
  • User-focused — Frame changes in terms of user benefit, not internal implementation detail
  • Concise — Bullet points work well; lengthy paragraphs are rarely read in full
  • Honest — If a significant behavior has changed, say so; users who are surprised by changes leave negative reviews

Consistent version numbering practices facilitate tracking and rollback. When a critical bug is discovered post-release, the ability to identify exactly which code was shipped to users — and to quickly produce a hotfix build — depends entirely on disciplined version management. Tagging your Git repository with the version number at the time of each release build, storing build artifacts by version in a build server, and maintaining a changelog file in version control are all practices that pay dividends when something goes wrong in production.

Submission Packages and Deliverables

A store submission is not just a binary file upload. It is a structured package of technical artifacts, legal declarations, marketing assets, and operational information. Each element serves a purpose, and missing or incomplete elements are a common source of rejection.

The submission package should include the signed build file, all store listing assets, and completed metadata fields. The signed build is the compiled, code-signed application binary — an .ipa for iOS or an .aab (Android App Bundle) for Google Play. Code signing is not optional; stores reject unsigned or improperly signed binaries immediately. Store listing assets include:

  • App icon at the required resolution and without transparency (Apple requires a 1024×1024 PNG; Google Play requires a 512×512 PNG)
  • Screenshots for each supported device class (phone, tablet, iPad) at the correct pixel dimensions
  • An optional but highly recommended feature graphic (Google Play) or preview video
  • App name, subtitle, and keyword fields (Apple) or short and full description (Google Play)
  • Category selection and content rating questionnaire

A link to a publicly accessible privacy policy must be included in every store submission. This is a non-negotiable requirement on both the App Store and Google Play, and has been for several years. The privacy policy must be hosted at a stable, publicly accessible URL (not behind a login wall), must accurately describe the data the app collects and how it is used, and must be written in plain language. Apple additionally requires a Privacy Nutrition Label — a structured declaration completed in App Store Connect that categorizes data collection by type and purpose. Mismatches between the declared nutrition label and the app's actual behavior are a cause for rejection.

Any required third-party licenses, SDK disclosures, or export compliance declarations must be prepared. Most apps incorporate third-party libraries and SDKs, and many of these carry license obligations (MIT, Apache 2.0, GPL, etc.) that require attribution either within the app (typically in a "Acknowledgements" or "Open Source Licenses" screen) or in accompanying documentation. Export compliance is particularly important: Apple asks explicitly whether the app uses encryption, and if so, requires either an Encryption Registration (ERN) or an annual self-classification report filed with the US Bureau of Industry and Security. Answering this question incorrectly can expose the developer to legal liability.

Demo account credentials should be provided to reviewers if the app requires login to access functionality. App reviewers are not going to create a real account, provide payment information, or complete a multi-step verification process in order to evaluate your app. If any core functionality is gated behind authentication, you must provide a working username and password for a demo account that has the app in a reviewable state. This account should:

  • Be pre-populated with enough data to demonstrate the app's features meaningfully
  • Have any required subscription or premium access already activated
  • Remain active and functional for the duration of the review period
  • Not require SMS verification, email confirmation, or other second-factor steps that the reviewer cannot complete

Failure to provide working credentials when an app requires login is one of the most common and most avoidable causes of rejection.

A notes-to-reviewer section should explain any non-obvious app functionality or special testing requirements. Both App Store Connect and the Google Play Console provide a free-text field for notes to the reviewer. This field is valuable and underused. Use it to explain:

  • How to navigate to features that are not immediately obvious from the main screen
  • Why certain permissions are requested and how they are used (especially for sensitive permissions like location, contacts, or camera)
  • Any hardware requirements — for example, if the app requires an NFC-capable device or a specific sensor
  • Context for features that might appear to violate guidelines at first glance but comply upon closer inspection (for example, an app that shows adult content only after age verification)
  • Known limitations in the review environment that reviewers should be aware of

Think of the reviewer notes as a user guide written specifically for the person whose approval you need. A clear, honest, and thorough set of notes reduces back-and-forth with the review team and increases the likelihood of a smooth first-pass approval.

Taken together, these four areas — release build configuration, pre-submission testing, version management, and submission package assembly — constitute a repeatable, professional release process. Teams that formalize these steps into a written release checklist and practice them consistently across every release cycle find that their rejection rates drop, their time-to-approval shortens, and their post-release incident rates decrease. The discipline applied in the final hours before a submission directly determines the quality of the experience delivered to every user who installs the app.

NotesGuides students through the final steps of preparing a production-ready application build, conducting pre-submission testing, and assembling all required deliverables for store submission.