A guide to setting up the distribution of iOS applications to your users using "custom apps"

Here’s a thorough guide on the recommended process to distribute an app to iOS devices.

Introduction

With enterprise apps being discouraged by Apple, private / “custom apps” are becoming the only viable option to distribute iOS apps.

There are two components to distributing your “custom apps”:

  1. Apps must be published on the App Store, with distribution restricted to one or more specific organizations.
  2. Your customer organization* must have an Apple Business account.

Typically you, as a customer of JourneyApps, will be responsible for both (1) and (2).
To proceed below you need an Apple developer account. Registering for an Apple developer account is outside the scope of this post.

*Customer Organization means the organization that the end-users belong to. There may be more than one, in which case each needs an Apple Business account.

Publishing “custom apps” to the App Store

The process is 99% the same as publishing an app to the public App Store. The same review process is required. This means there are some caveats to take into account versus enterprise builds:

  1. A full description of your app and screenshots are required.
  2. Apple needs a test account for reviewers to test the app. This needs to be a functional app, and should match the app’s description. If your app only uses SSO, the reviewer will need an account on that SSO system.
  3. All updates need to go through the review process, which at the time of writing takes around 2 days.

Prerequisites:

  • Accept agreements for Free Apps and Paid Apps, even if the app will not be a paid app. Someone with the Legal role will need to do this.

Obtaining the app IPA file

You need an IPA (iOS package App Store) of your iOS app to publish it to the App Store. The IPA is generated when you create a custom-branded iOS app using OXIDE and requires several steps using your Apple Developer account.

See these docs for further instructions.

App Store Submission

Next you need to create an app on the App Store, using the same developer account (this can be done in parallel with the previous steps):

  1. Start on App Store Connect → My Apps: https://appstoreconnect.apple.com/WebObjects/iTunesConnect.woa/ra/ng/app and create new app.
  • Name: Must be globally unique on the App Store, e.g. “JourneyApps Snaglist” instead of “Snaglist”. Does not have to match the app / home screen name.
  • Bundle ID: Pick previously created one.
  • SKU: Anything, but use the Bundle ID as a convention.
  1. User Access: Default to Full Access. Affects developer users that can access the app, not end-users.

  2. Complete all the required App Info:

  • Privacy Policy: Provide your own privacy policy.
  • Category: Default to Productivity
  • Age rating: Complete the survey, and the result should end up as “Ages 4+”, but not “designed for kids”.
  1. Pricing and availability:
  • Price Schedule: Free
  • Availability: All Countries
  • Distribution for Business and Education: Choose the last option - “Available for private distribution to specific organizations on Apple Business Manager or Apple School Manager”
  • Organization ID and name: Available on the Apple Business Portal (see section below).
  1. Add an app version.
  • Description: Make it clear that this is a private app intended for the specific customer only.

  • Build: Add the IPA obtained in the previous section.

  • App Review Information: Sign-in required; add some test credentials and notes for the reviewer to test the app.

  • Contact Information: Details of anyone who is able to answer reviewer’s questions.

  • Screenshots: You need at least these:

    1. 5.5": 1242 x 2208
    2. 6.5": 1242 x 2688
    3. 12.9" iPad Pro: 2048 x 2732
    4. We recommend Chrome’s developer tools to take screenshots. [See section below]
  1. Save and submit for review.
  • Advertising id: Not used.

  • Encryption:

    1. Does your app use encryption? Select Yes even if your app only uses the standard encryption within Apple’s operating system. Yes
    2. What type of encryption algorithms does your app implement? Standard encryption algorithms instead of, or in addition to, using or accessing the encryption within Apple’s operating system
      • Details: Our app uses both HTTPS, and local encryption of the user’s data. We do not use end-to-end encryption. It is our view that this qualifies for the exemptions mentioned. However, this is not legal advice. If a developer customer makes their own submission, they need to take full responsibility here to follow the legal requirements.
    3. Is your app going to be available on the App Store in France? No (currently not supported)

Review Considerations

A common point for rejection are enabled container-level features that are not used in the app. Ensure that only necessary features are enabled. You can review enabled features using the summary page for a build in OXIDE, and you can enable and disable container features when configuring a container.

The Apple reviewer will actually test the app, and reject it if there are major bugs.

The reviewer has sign into an app matching the description. For security purposes, it is recommended to use the actual app it’s intended for, but create a dedicated staging or production environment for this. This isolates the data nicely from the rest, and allows setting up basic test data specifically for the review process.

If the app is using SSO, this can get more complicated. In this case, actual test SSO credentials will have to be provided.

TestFlight

TestFlight is available once the App Store entry above has been created (but does not have to be submitted for review yet).

TestFlight can be used for beta testing, before or in addition to publishing on the private App Store. For users on the Apple developer account, no review is required to get the build into TestFlight. For external users, a beta review must be performed first. This review process is a lot less strict, but can also take 2 days on average. You then get an invite link that can be sent to any user. These builds are installed via the TestFlight app, and expire after 3 months (then needs a version bump and new upload). The app may still be usable on the device after the 3 months, but do not rely on this.

To use TestFlight, you need to manage the users that have access under App Store Connect → TestFlight → App Store Connect Users

For internal users, the iCloud account doesn’t have to be on the device. The process works like this:

  1. Add Apple developer user to the app’s TestFlight users.
  2. The user will receive an email with an invite link.
  3. Opening the link gives a redemption code.
  4. The redemption code can be used on any one device with TestFlight installed.

Using Chrome for screenshots

  1. Enroll to your app using https://testing.onjourneyapps.com
  2. Open developer tools, and toggle the device toolbar.

  1. In the device dropdown menu, select Edit and add a device like this:

  1. Now use the following three devices for screenshots:
  • iPhone 6/7/8 Plus (built-in) - 1242 x 2208
  • iPhone 11 Pro Max (the custom one created in step 3 above) - 1242 x 2688
  • iPad Pro (built-in) - 2048 x 2732
  1. Note that these resolutions are the resolutions in Chrome, multiplied by the device pixel ratio.
  2. Use Chrome’s screenshot tool - available in the more menu. If you use the built-in OS screenshot tool, the device pixel ratio will not be applied, and the resolution will be incorrect.

We have recently been seeing some responses from Apple regarding NFC references in our builds. If Apple responds asking about the NFC use, but you explicitly did not enable the “NFC Tag Reading” during the Identifier creation, the following can be shared with Apple:

It is true that our framework references NFC. However, without the NFC entitlement, there is no code that actually triggers NFC or is able to do so.

This guide could greatly use some elaboration within step 4 at:

Build: Add the IPA we shared with you.

Is XCode a hard requirement for this or are there alternatives?