Restoring Purchases
How to restore purchases and provide information in the UI for users when they restore purchases.
In this guide, we walk through the basics of how to enable customers' ability to restore purchases easily in your app as well as how to present information about the restore purchases process in your app's UI.
Apple
On Apple devices, Apple asks you to explicitly provide the functionality to start the restore purchase process somewhere in your app.
Nami processes the receipt for your app each time the app comes to the foreground. If there are any active purchases, they will be activated by this receipt check process.
Nami Paywalls support adding a Restore Purchases button directly to your paywalls with our No-Code Paywall Creator .
You may also start the process of restoring purchases by calling the following method.
NamiPurchaseManager.restorePurchases()
[NamiPurchaseManager restorePurchases];
NativeModules.NamiPurchaseManagerBridge.restorePurchases();
When using Linked Paywalls, if you have a button for Restore Purchases please call the method above to trigger the restoration process.
Reacting to the Restore Purchase Process
Apple does not present any UI to the user during the Restore Purchase process.
The Nami SDK provides a method for registering a callback that will allow you to respond to different states that occur during the Restore Purchase process, and provide information in your UI to let the user know what has occurred.
There are 3 states you can react to during the process:
started
finished
error
Nami Best Practice
We recommend presenting messages in the correct language in your app's UI for at least the
finished
anderror
states.
The code sample below shows how to present a message in the UI to the user letting them know whether any purchases were found and restored during the Restore Purchases process.
It also informs the user if there was an error during the process so they know to try again.
The registerRestorePurchasesHandler
returns 2 sets of purchases:
oldPurchases
- Purchases that were active on the device before the restore purchases process started.newPurchases
- All purchases active on the device after the restore purchases process completed.
To check if a new purchase was found and activated, you are looking to see if there is an additional purchase in the newPurchases
list that was not present in the oldPurchases
list. You can also simplify this check and simply look for any objects in the newPurchases
list and indicate to the user that purchases were found and restored.
NamiPurchaseManager.registerRestorePurchasesHandler { state, newPurchases, oldPurchases, error in
// For Nami Paywalls made with the Paywall Creator, present
// any alerts from this view controller
let presentAlertFromVC = NamiPaywallManager.currentNamiPaywallViewController()
switch state {
case .started:
// optionally react to start of restore purchases
case .finished:
// additionally may want to check that there are more items in
// newPurchases than oldPurchases
if oldPurchases != newPurchases {
// present message to user that purchases were successfully restored
} else {
// present message to user that no purchases were found
}
case .error:
// present message to user that an error occurred
}
const onRestorePurchasesStateChanged = (event) => {
console.log('Restore Purchases State Change: ', event);
if (event.stateDesc == "started") {
// optionally present "Restore Started" message
} else if (event.stateDesc == "finished") {
if (event.newPurchases.length > 0) {
// present message about purchases found and restored
} else {
// present message that no purchases found
}
} else if (event.stateDesc == "error") {
// optionally do something when error occurs
console.log("Restore Purchase Error was" + event.error);
}
}
useEffect(() => {
...
if (
eventEmitter?._subscriber?._subscriptionsForType?.RestorePurchasesStateChanged == null
) {
eventEmitter.addListener('RestorePurchasesStateChanged', onRestorePurchasesStateChanged);
}
...
}
NamiPurchaseManager.RegisterRestorePurchasesHandler(handler: (state, newPurchases, oldPurchases, error) => {
switch (state)
{
case NamiRestorePurchasesState.Started:
// optionally react to restore purchase process started
break;
case NamiRestorePurchasesState.Finished:
// check if there are newPurchases not in old purchases
// optionally let user know new purchases were found and restored
// or no purchases found
break;
case NamiRestorePurchasesState.Error:
// optionally react to error in restore purchases
break;
}
});
For Linked Paywalls the restore purchases call can also trigger the restore purchases handler. See the example below.
NamiPurchaseManager.restorePurchases() { state, newPurchases, oldPurchases, error in
switch state {
case .started:
// optionally react to start of restore purchases
case .finished:
// additionally may want to check that there are more items in
// newPurchases than oldPurchases
if oldPurchases != newPurchases {
// present message to user that purchases were successfully restored
} else {
// present message to user that no purchases were found
}
case .error:
// present message to user that an error occurred
}
}
const restore = () => {
NativeModules.NamiPurchaseManagerBridge.restorePurchasesWithCompletionHandler((result) => {
if (result.stateDesc == "started") {
// Optionally present UI that restore process has started
} else if (result.stateDesc == "finished") {
if (result.newPurchases.length > 0) {
// present UI that purchase was found and restored
Alert.alert(
'Restore Complete',
'Found your subscription!',
[{text: 'OK', onPress: () => console.log("Found Purchase Confirmed") }]
);
} else {
// present UI that restore process completed and no purchases found
Alert.alert(
'Restore Complete',
'No active subscriptions found.',
[{text: 'OK', onPress: () => console.log("Found Purchase Confirmed")}]
);
}
} else if (result.stateDesc == "error") {
// present UI that an error occurred
Alert.alert(
'Restore Failed',
'Restore failed to complete.',
[{text: 'OK', onPress: () => console.log("Restore Purchase Error was" + result.error)}]
);
}
});
}
...
<Button
style={styles.restoreButton}
onPress={() => restore()}
title="Restore Purchases"
/>
Google Play
Purchases are automatically restored when our SDK connects to the Play Billing library on app start. There is no manual restore purchase process similar to the one for Apple devices.
On cross-platform frameworks like React Native, Flutter, and Xamarin, calls to restore purchases on Android take no action.
Updated almost 3 years ago