Home
Blog
Monetizing a SwiftUI App: IAP & Subscriptions

Monetizing a SwiftUI App: IAP & Subscriptions

Portrait photo of blog author
Dan Burcaw
Co-Founder & CEO

We shipped a new SwiftUI app, offering a lifetime IAP and two subscriptions plans powered by Nami. See how to do it.

Table of Contents:

In this blog post:

We decided it was time to build and ship a brand new app using SwiftUI to experience first hand the latest from Apple.

The app, now available on the App Store, is called Serenity Now.

It’s a simple audio player with a SwiftUI interface and AVFoundation under the hood. The app is filled with a collection of sounds for focus, relaxation, and better sleep.

👉Read more: Adding In-App Purchases to SwiftUI Apps

App Monetization Goals

We’re in the monetization business, so we set out to implement our own Nami SDK to offer IAPs and subscriptions.

Here are the three products we want to offer:

  • Lifetime Access - $49.99 for life (only available as a launch exclusive)
  • Monthly Subscription - 3 day free trial, then $3.99 / month
  • Yearly Subscription - 1 month free trial, then $39.99 / year

Users who buy one of these products gets access to our Serenity Now Premium features. Those features include:

  • Premium-only sound collections - Nature, Uplifting, Water & Sleep
  • Premium controls -  Repeat & AirPlay
  • Ad-free experience

We want users to encounter our paywall during the app experience in three different places:

  • First Launch - The first time the user launch the app
  • Gated Content - Upon tapping a content tile that requires premium access
  • Marketing Tile - Tapping the premium access marketing tile in Settings

Now that our goals are clear, let’s see what it takes to accomplish.

The SwiftUI Lifecycle & SDK Initialization

SwiftUI apps don’t use the the AppDelegate we have all come to know from years of building iOS apps. Instead, the entry point for SwiftUI apps is a struct conforming to the App protocol.  

That protocol has one requirement, which is the implementation of a property called body. Digging into the specifics of body is outside the scope of this article, but suffice it to say that is where you’ll kick off your app’s user interface.

For our purposes, we need a place to configure the Nami SDK. It turns out, we can provide a custom init() method on our App struct for this purpose.

Here we setup our NamiConfiguration object with our app’s unique appPlatformID (found in the Nami Control Center > Integrations > [your Apple App Store integration]

Setting up an ObservableObject to Track Purchase State

We will need to monitor changes to the the entitlements a user has access to. A change may occur if they buy one of our IAP products, or if they have a subscription that expires.

In Serenity Now, if a user buys any one of the three IAP products, we grant them access to an entitlement called premium_access.  

In SwiftUI, we can monitor for user entitlement changes by setting up an ObservableObject. Specifically,  we need to register with the Nami SDK’s registerEntitlementsChangedHandler callback to update our ObservableObject’s premium var.

Since premium has a @Published property wrapper, any SwiftUI view’s body will be re-invoked any time the value changes.

This is exactly what we want. If a user buys one of our products, we want any of the SwiftUI views that rely on the value of premium, to be updated. Concretely, this means any view that gates access based upon the premium_access entitlement will update if the value changes.

Paywall Use Case: Initial App Launch

Next, we want to show our paywall the first time the user launches the app.

Serenity Now app paywall

In our main SwiftUI view, SerenityNowHome, we run some code in .onAppear that checks UserDefaults for the value of a key didLaunchBefore.  If the value is false, it’s the first launch of our app so we tell the Nami SDK to show a paywall if NamiDataSource’s premium var is False.

Paywall Use Case: Gating Premium Content

Next, we want to gate access to certain premium content in our app.

Gating premium access with Nami

If the user does not have access to the premium content (e.g. NamiDataSource’s premium var is False), we want to present the paywall. Otherwise, we want to show the SwiftUI with the relevant content.

Paywall Use Case: Premium Marketing Tile

Finally, we want to give users a way to access our paywall from a marketing tile in the Settings section of our app.

Providing a premium upsell banner in SwiftUI

In our Settings view, if the user does not have premium access (via our NamiDataSource), we show our NamiUpsellBannerView. If the user taps on it, we show our paywall.

If the user does have premium access, we instead show a link to Manage subscription which takes the user to the system Settings.

👉Read more:What’s New with In-App Purchases at WWDC 21

Final Thoughts

There is much more we want to do with our SwiftUI app and some advanced use cases we want to discuss in future blog posts.  For now, we hope this article shows how is it is to get up and running with some very common use cases for selling IAPs and subscriptions.

You may be wondering about the paywall view itself. The paywall was created via Nami’s no-code paywall designer. The Nami SDK provides a native Swift that is configurable from the Nami Control Center so you can make changes instantly.

The SDK provided paywall integrates seamlessly with our SwiftUI app from both a user interface and usability perspective. If you’re interested in giving Nami a spin for your own SwiftUI app, you can create a free account here.


       

       if(window.strchfSettings === undefined) window.strchfSettings = {};
   window.strchfSettings.stats = {url: "https://nami.storychief.io/en/monetizing-swiftui-app-iap-subscriptions?id=1919917807&type=26",title: "Monetizing a SwiftUI App: IAP & Subscriptions",id: "51b60849-ff21-4408-b48f-9543da3cae59"};
           (function(d, s, id) {
     var js, sjs = d.getElementsByTagName(s)[0];
     if (d.getElementById(id)) {window.strchf.update(); return;}
     js = d.createElement(s); js.id = id;
     js.src = "https://d37oebn0w9ir6a.cloudfront.net/scripts/v0/strchf.js";
     js.async = true;
     sjs.parentNode.insertBefore(js, sjs);
   }(document, 'script', 'storychief-jssdk'))
   
   

Dan Burcaw is Co-Founder & CEO of Nami ML. He built a top mobile app development agency responsible for some of the most elite apps on the App Store and then found himself inside the mobile marketing industry after selling his last company to Oracle.

Sign up to our newsletter

Get the latest articles delivered straight to your inbox.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Similar articles

Read similar articles to this one