Home
Blog
Authors
Kendall Gelner

Kendall Gelner is a Senior iOS Engineer at Fieldwire. Previous, he was the founding iOS Architect at Nami ML. He is well regarded in the iOS development community for his technical knowledge and platform experience going back to the App Store launch. The last SDK Kendall was responsible for shipped inside of some of the most widely installed apps, reaching more than 200 million devices.

Latest articles by
Kendall Gelner
Written by
Kendall Gelner
28 Nov

Allow your Fans to ‘Give Thanks’ by adding a Tip Jar to Your App

Tip jars are an easy way to start generating revenue from users that love your app. We step through the entire process of adding a tip jar to an iOS app.

Help your Fans Support You

These days, it's easier than ever to put together an application you see a need for and release it to help the world.

Over time all apps need updating - new devices are released, features like Dark Mode, or just graphic design overhauls.

Anyone can support these changes for a while but eventually, the reality is that all app developers need money to keep an application going.

So why not let your biggest fans, the people who love using your app, help you out? If you don't even try, you might never know just how much people appreciate what you have built.

It seems daunting to put together a payment system, even more, to figure out what areas of your app you might want to change to paid access - but you don't have to go that far, there's a simpler path to start - the tip jar!

What is a Tip Jar?

Simply put, the tip jar is a way for someone who really loves using your application, to show support for you through a one-time in-app purchase. It's a reward for work you've already done and for improving someone's life, a way for someone to ask you to please keep going because they love what you have done.

How does a Tip Jar work in iOS?

Technically speaking, Apple provides three distinct ways to receive payment:

  • Subscriptions (auto and non-renewing)
  • Non-Consumable products (one time purchases that activate some ability in your application)
  • Consumable products (can be purchased at any time, for any reason, as many times as the user wants)

The last category, consumable products, is perfect for tip jars - you can simply message your users from time to time or add a screen for them to find in your app when they seek a way to reward you for your work.

It's a single purchase that doesn't have to be remembered, although you may choose to do so if you wish to remember who recognized your app so you can provide them with some small reward.

Why use Nami to create a Tip Jar?

You can just set up StoreKit yourself to create your own tip jar, but it can be complex to do right and frustrating to add without bugs that are hard to test for.

Nami can help you by providing the UI for the paywall for you, and over time can figure out what people are doing in your app (and for how long) that makes them more likely to tip - that way in the future you can prompt for tips only for users that are gaining the most from your application, and most likely would be happy to share their appreciation!

Using Nami to add a Tip Jar

Setting up payments can be complex, Nami makes these basic cases incredibly simple for you to start using.

Create your tip products!

Create a consumable or non-recurring subscription product for your app (or possibly a few at different price points).  In App Store Connect, visit your app, click on Features, then add products:

Create a consumable IAP in App Store Connect

Give it a name and a product identifier, then set the price:

Give the IAP SKU a reference name and product ID
Assign a pricing tier

Sign-up for a Nami account for your app

Setup an application in our system

You'll need the application bundle ID.

Add your products into the Nami dashboard.

Take the one or more product ID's you created earlier in App Store Connect, In Nami, go to Products, then add the same product ID's you have defined in App Store Connect - if they do not match exactly, you'll not see that product appear in your paywall (which can be a useful thing to double-check if you see a paywall but not your products).

Create a Nami paywall that uses your products

Nami can handle more advanced cases like multiple paywalls, and campaigns that you can change out on the fly - but to start with for our simple Tip Jar, all we need is a single paywall built using the Paywall Creator!

Once you've added your products, go to the paywall tab on the side, and create a new paywall - Name it something like Tip Jar, then for the title and body put in something that makes people excited to be supporting your application, and gives further explanation of how their contributions will help you continue to improve the app. The products you add to this paywall will automatically show up below the title and body and can be purchased by your users. Also, make sure to add a background image for iPad and iPhone which is required to fully set up a paywall!

For example, here's the Nami Tip Jar example paywall:

Lastly even though you have just one paywall, you still need a campaign to display it - so quickly create a campaign, add your paywall you just added, and make the campaign live. You can leave the rules alone for now or have the paywall appear every so often after they open the app by selecting the rule to open after so many sessions. Here's how we have the tip jar for our example configured:

Be sure to make the campaign Active on the Overview tab, then you are ready to go! For more help please see the Nami documentation on setting up paywalls and campaigns.

Create a way to activate your Tip Jar

Although Nami paywalls can be made to show automatically, for tip jars it's great to have a way for users to be able to seek out and find your tip jar to use whenever they like.

Usually, it's good to put this in something like an "About Me" page that you probably have already - for example in our demo app we have a section describing the basic philosophy of color, and telling people who the application developers are. That's the first place someone might look for ways to support your app, without it being too in the face for your users.

For example, to start with our sample Tip Jar application has this About screen:

After adding some text about why someone might want to tip, and a button that will enable the user to get to our tip jar:

Add the Nami SDK

Now that we have the UI to show the user how to get to our tip jar, we are ready to add Nami so that it can present the tip jar for us and handle payments!

Add the SDK to your application as described here:

https://docs.namiml.com/docs/add-the-nami-sdk-to-your-project

After you follow those instructions, you should have the Nami Framework added to your project/workspace like so:

Also make sure you have code in your AppDelegate to tell Nami what your App Platform ID is:

Add code to raise Tip Jar

Once the SDK has been added, you just need one line of code to have the button you added raise the tip jar on demand!

Don't forget to import the Nami framework at the top of the file!

Run the project, and you should see something like this come up in the simulator when you use your button:


If you like, you can go ahead and tap one of the buttons to simulate a purchase.

There's one other thing we need to do to make sure the purchases work as intended - if we are using Consumable products, we need to consume them after purchase so they can be purchased again in the future.

It's also probably a good idea to thank whoever supports your app through purchases, so the last step is to add code that does just that - in the app delegate you can set up a handler to display such a message whenever a purchase through your tip jar is detected.  Let's add a handler to do both things:

Now when a purchase is made, the user should get a nice message and the tip jar product will be cleared!

Once that is working, you should raise the test paywall again and take screenshot of the simulator using the File-New ScreenShot option of the simulator. Upload this image (saved onto your desktop and named "Simulator Screen Shot") into the review metadata for each of the product definitions in App Store Connect:

It is also a good idea to add in a description of how the App Store tester can access the payment screen in your app, to make it easier for them to test payments.

Add products to your next App Store submission

Lastly, you need to make sure the products you are using for your tip jar are added to your next App Store submission for review! Go to the App Store tab in App Store Connect for your app, then click on the prepare for submission item:

Scroll down to find the In-App Purchases section:

Click on "+" and add your products.

Now when you are ready to submit your app, the App Store reviewer will know they need to test these products and they can be added properly to your app on the App Store.

That's it!  Now you have a path for your application community to provide you with support to help make your application even better.

Written by
Kendall Gelner
16 Oct

The App Store Rejected My App! Now What?

So your app was rejected. App Store rejections are common but are usually simple to resolve. This article covers typical rejection reasons, including those relating to apps utilizing StoreKit, in-app purchases and subscriptions.

This article is for people who have submitted to the App Store, but have had the application rejected for some kind of technical (not policy) reason.

First of all, don't panic! App Store rejections are pretty common and it does not affect your standing with Apple or necessarily mean you have a serious problem to fix. Often it’s a small detail of Apple's requirements you need to address, and then all will be well.

Where Should I Start?

So what should you do when your app is rejected? Here are some useful starting steps:

  1. Read the rejection message carefully. They will usually be pretty clear what is wrong, though they will sometimes reference aspects of the App Store terms document or use terms you may not know.
  2. If you feel the App Store is mistaken about something, you can send them feedback through App Store Connect - just be aware it may take them some time to respond. You can also write the App Review Board.
  3. Try to replicate the problem the App Store team saw. When using in-app purchases, try running a fresh install from a TestFlight build (not built from Xcode) on device, using the iTunes Sandbox for purchase testing.
  4. While you are looking into the problem review reported, double check other related systems work - the review team only reports one issue at a time, even if you have multiple issues with the application they could seemingly easily discover at once.
  5. This may go without saying, but check StackOverflow for the wording the App Store team used in your rejections. They mostly use the same wording across many applications, so chances are someone had a similar rejection and might be able to help clarify what aspect of the app has been rejected and how they solved the problem.

5 Tips to Avoid Rejections Related to StoreKit, In-App Purchases and Subscriptions

Here are specific suggestions to issues we’ve seen submitting apps with purchases:

  1. For in-app purchases in particular, make sure all of your purchases you need have been added to the build you are submitting for review - if you don't have all of the product metadata filled out, you'll not be able to add that product for review.
  2. For subscription purchases, be aware that Apple will try out all products you are submitting for review, even if there are multiple subscriptions in the same application group - so make sure you also have tested all of your products in the iOS sandbox before submitting the app for review.
  3. If you have products, make sure that terms and conditions of purchases are available somewhere in your application, along with the option to restore purchases.
  4. If you have any complex uses of your app especially around purchasing, add to the "Notes" field in the app metadata for submission - you can explain common uses of the app or direct them to specific screens for purposes of testing functionality. Often just noting down how your app works can avoid confusion. It could also help them test the application faster, since they are not trying to figure out how your app works from scratch. Make sure to carefully test all of the things you tell them to try!
  5. Nami can help avoid rejections due to purchase issues, as our SDK is built to to handle StoreKit errors and interactions so you don't need to worry about edge cases the reviewers might test. You should always test your in-app purchases in the iOS sandbox to be sure everything works as expected in your application when purchases are made, and can use the Nami bypassStoreKit setting to test app purchase reaction when using the simulator.

Solutions to Common Rejections

Authentication Screen Remained open

Apple considers your payment request screen (paywall) to be a form of authentication, they are saying after a purchase was made there was no indication from the app the purchase succeeded - such as dismissing the paywall view.

Solution: Try to reproduce a case where a paywall remains open after purchase. Does turning off the network not yield any messages when attempting to purchase? Would any error case in purchasing leave the screen up? Make sure a successful purchase messages the user.

Guideline 5.2.1 - Legal - Intellectual Property

This means App Store review has found images in your application or in app preview images for the App Store that are copyrighted - for example if your application sample images showed album covers or images from other people.

Solution: One possibility for App Store preview items, is to simply blur out copyrighted material from preview images so that it is no longer recognizable. You could also edit out anything copyrighted and replace with images you do have rights to.

Guideline 3.1.1 - Business - Payments - In-App Purchase

Read the details of the problem they had, one common item is that your application did not offer a way to restore purchases.

Solution: If your app does offer a restore purchase option, respond directing them as to where it can be found. If it does not already, add that feature - usually it is placed somewhere on the product selection screen (paywall).

Guideline 3.1.2 - Business - Payments - Subscriptions

This category includes specific issues with subscriptions.

One common possibility here is that you forgot to include some way to access purchase terms, and the privacy policy of your app.

Solution: These can be anywhere, make sure to point out where they can be found if the app reviewer says they are missing but you have included them. One common technique is to have these legal documents hosted on your website, and use a Safari web view in your app to display them for reading.

Guideline 2.1 - Performance - App Completeness

This guideline can come into play if you've forgotten to include products to submit with the build of the application you are submitting to the App Store.

Solution: If you have not filled out all product metadata (including screen shots of the purchase screen for app review), then the section to include products in the app metadata for review will not appear - make sure all of the products you want to use in the release of your application are marked as "ready for review" and have been added to a build you are submitting for review.

Another possibility: Tapping purchase buttons produces no result.

Solution: If a user attempts to purchase, there should always be some indication by the application that it is attempting to make a purchase - make sure that the button will always initiate a purchase with StoreKit, and listen to any possible response to fail gracefully if StoreKit returns any errors. Double-check all of your purchases from a device Sandbox test account, to make sure you do not have anything like incorrect product identifiers, and are listening to transaction results from Apple.

Another possibility: A user attempted an in-app purchase outside the application, but the app did not show the purchase was made (for example, an App Store page that shows subscription options might be used to make a purchase instead of in-app).

Solution: Make sure you start up store kit listeners at app launch, and process any incoming transactions as soon as you see them - ave some way for the application to react to purchases made at any time, not just when on a purchase screen (paywall).

Guideline 2.1 - Performance

This more general category may arise if your application does not work on IPV6 networks. They will mention this in the notes if that is the issue.

Solution: Check Apple's documentation on supporting IPV6 networking, including some common items to look for that may trip up IPV6 support. Learn more about how to set up an IPV6 network for testing.

Missing Info.plist key

Accessing a variety of protected system features, like location or bluetooth, requires an entry in the info.plist. Over time, Apple may add new entries (as when they added “when in use”) that require new entries for capabilities you supported with other plots entries previously.

Solution: Review all of the plist entries required for protected capabilities your app supports, also make sure they are clear as to why the user needs to grant you access to that ability.

For more impactful abilities like the location “always” permission, you may want to add something to the Notes metadata file the app submission, so the reviewer is clear as to why the application needs that permission.

Written by
Kendall Gelner
16 Jun

Designing a Mobile SDK

How to put the customer experience at the center of your mobile SDK.

Yesterday, we released of the Nami SDK for iOS. To mark this release, we thought we’d share some details about how we approach development of the SDK including our key design goals.

Creating great customer experiences is a core part of Nami’s company values. As part of our mission of BCE, the Nami SDK was built around five key concepts that we believe to be vitally important:

  • Ease of Adoption
  • Make Subscriptions Simple
  • Protecting the End User Experience
  • Emphasis on End User Privacy
  • Built for Developers

Below we’ll touch on each of these concepts in more detail.

Ease of Adoption

We’ve experienced SDKs that take way too much time to integrate or create additional unforeseen work. Adding a new SDK to your app should be as painless as possible. That’s why we’ve focused on making the Nami SDK incredibly straightforward to adopt.

Minimal code to get started. We strive to get you up and running with just a few lines of code. The basic integration steps are straight forward so you can stay focused on what really matters: building a great app!

No third-party dependencies. The Nami SDK does not require any third-party code or dependencies. This helps us keep the size small and the integration points to a minimum. The Nami SDK will never generate a dependency conflict.

Make Subscriptions Simple

Receipt validation. We take care of the complexity in the Apple APIs for details around app purchase receipts, including monitoring updates to purchases including users canceling a subscription or getting a refund for a purchase, thus re-disabling a feature in an application.

Easy purchase testing. We know that testing in-app purchases is a hassle. That’s why we wanted to make it much easier to test a variety of purchase flows, so that you do not have to spend as much time managing StoreKit test users or going through tedious system prompts just to test your apps reaction to purchase changes.

Cached purchase details. StoreKit doesn’t offer a way to ask for purchased products, so developers typically have to cache purchases. The Nami SDK stores away information about purchases so they can be easily checked at launch if the user is already subscribed without relying on the network.

Avoiding "Restore Purchases”. The restore purchase flow is clumsy for a user of any application so we use receipt validation and other techniques to determine if a user on a new device or with a reloaded app has previously purchased products.

Cloud-enable your existing sales sheet. Attach your existing subscription sales sheet or offer screen to the Nami SDK to make it more dynamic. This means you can make changes from the cloud and require fewer app updates.

Adopt a Nami Paywall. Ready to turn over control of the sales sheet to your product or marketing team? The Nami Paywall is a native (no WebViews!), feature rich sales sheet experience that can be fully managed in the cloud by non-developers. Meanwhile, in your app code the Nami Paywall handles much of the complexity of offering subscriptions with StoreKit.

Protecting the End User Experience

Maintain main app performance. Nami uses background, low priority queues for work whenever possible. Sometimes providing a great user experience means processing or information must be fetched quickly. When this is necessary, we strive to do as little work on the main thread as we can, or at times when app performance is not impacted.

No UI impact. We strive to ensure whenever possible that none of the work that Nami does will impact UI performance. As described above, whenever possible Nami works on the background thread, but we also take extra care to avoid doing work during certain kinds of animations such as controller transitions.

Protect and conserve battery life. We avoid unneeded work on the device. This means taking care to exercise power consuming features like network requests in a way that allows the system to batch with other requests as much as possible.

Emphasis on End User Privacy

Customers are expecting more privacy in apps every day and the regulatory landscape is constantly changing, making it more risky to be producing software and not have your user’s privacy as a top priority.  Are your vendors and partners helping you reach your privacy goals? The Nami SDK strives to be a strong partner in your goal to protect your users data.

Privacy is core tenant of our company mission: BCE, so expect read more in future posts detailing our technical approaches.

No PII. While we do have to collect a unique identifier to be able to offer personalized experiences, the Nami SDK does not collect email addresses, geolocation information (except at a country level), or device identifiers.

Data minimization. We employ data minimization to limit what we collect to only what is absolutely necessary. This is in stark contrast to the many SDKs that collect voluminous and invasive data with little regard for the user.

Built For Developers

Simplify but do not hide complex StoreKit workflows. We want our SDK to help provide you with the simplest possible means of receiving important information about the purchase flow within an application, while still providing access to the underlying StoreKit metadata you may need for more complex workflows.

Built for Swift 5. We built the Nami SDK using Swift 5 to ensure we get all the benefits of Apple’s modern programming language. This helps us iterate more quickly and keep quality high.

Detailed release notes. With each update to our SDK, we’re adding detailed release notes to our GitHub repository. While it’s generally a good idea to keep the SDKs you ship in your app current, our detailed release notes will help you prioritize updates.

Example apps included. Code fragments are great, but we appreciate SDKs that include fully functional example apps (that compile!). With our latest release, we shipped our first example app with more to come. We’ll be sure to keep examples updated with new operating system, developer IDE, and toolchain releases.

Take a look at our developer documentation and let us know how we’re doing.

* * *

We want the Nami SDK to be as delightful as possible to use, so if there is anything you find confusing or would find helpful, please let us know or open a GitHub issue!