iOS Tutorial iStore - In App Purchases

The iStore library allows you to use the store In-App Purchases features inside your app.
You can let the user purchase digital products from inside your app.

(Unsurprisingly) the configuration required is a bit tedious.

In order to test this feature (and later release it) you need to create an app in iTunes Connect and create one or more in-app products. You don't need to actually upload the app binary file however you do need to fill all the fields and prepare the app. Later you can change them as needed.

After you've created an app placeholder in iTunes you need to carefully follow these instructions:
https://developer.apple.com/library/ios/technotes/tn2259/_index.html

The main steps:
  1. iOS Paid Applications contract should appear under "contracts in effect".
  2. You need to create an explicit App Id (without wildcards) and download a new provision file.
    You can use #ProvisionFile to tell the IDE which provision file should be used.
  3. Create a test account as explained in the tech note. Later you will sign out of the store from the Settings app. Note that you should not sign in to the store with the test account from the Settings app. The test account should only be used inside your app.
  4. Create one or more in-app products and make sure not to upload a screenshot during development.
iStore library supports two types of products: consumable and non-consumable products.
Consumable - The user can purchase these products multiple times. For example in a game a user can purchase extra health or coins.
Non-consumable - The user can purchase such products once. For example the user can use such product to permanently remove ads from the app. If you are selling such products then you need to allow the user to restore such products if the user switches to a different device (with a "restore transactions" button).

Code

The code is quite simple.
First you initialize a Store object and check whether the device supports this feature:
B4X:
Dim MyStore As Store 'declare it in Process Globals
...
MyStore.Initialize("MyStore")
If MyStore.CanMakePayments = False Then ...

Later you can request a payment and then handle the PurchaseCompleted event:
B4X:
MyStore.RequestPayment("product.id")

Sub MyStore_PurchaseCompleted (Success As Boolean, Product As Purchase)
   Log("Purchase completed")
   If Product.IsInitialized Then
     Log("Product: " & Product.ProductIdentifier & ", date=" & DateTime.Time(Product.TransactionDate) & _
       ", Transaction identifier=" & Product.TransactionIdentifier)
   End If
   Log("Success = " & Success)
End Sub

The user will be asked to log in to his store account (use the test account here) and approve the purchase.

Restoring non-consumable purchases

As noted above, if you are selling such products then you are expected to provide a way for the user to restore completed transaction.
Once the user requests to restore transactions you need to call MyStore.RestoreTransactions. The PurchaseCompleted event will be raised for each previous purchase of non-consumable products.
The TransactionsRestored event will be raised at the end.

Note that the user might be asked to log in to his account, therefore you shouldn't call this method when the apps starts to find existing purchases (unlike the Android library).
 
Last edited:

sorex

Expert
Licensed User
Each In-App Purchase test user account is tied to one and only one email address. As such, you cannot reuse an existing email address with another test user account.

ok, but will that still allowe me to test in-apps from different apps with one email account?

or do I need to create an e-mail account for each app?
 

marcick

Well-Known Member
Licensed User
It seems clear to me: one email address and one test user account to test all your apps. If you want to create a second test account, you need to provide a different email.
 

sorex

Expert
Licensed User
Is this library also checking the purchases at each init online or from an offline cache when no internet connection is available? (like the Android one does)

Or is only the purchase action being passed so that we need to store this in a file to check on at later restarts of the app?
 

ilan

Expert
Licensed User
Restoring non-consumable purchases

As noted above, if you are selling such products then you are expected to provide a way for the user to restore completed transaction.
Once the user requests to restore transactions you need to call MyStore.RestoreTransactions. The PurchaseCompleted event will be raised for each previous purchase of non-consumable products.
The TransactionsRestored event will be raised at the end.

Note that the user might be asked to log in to his account, therefore you shouldn't call this method when the apps starts to find existing purchases (unlike the Android library).
 

sorex

Expert
Licensed User
thanks, I guess this is the case aswell if you bought an ad remover and want to apply it on a second device having that app?

It's bound to an account, not a device.
 

sorex

Expert
Licensed User
You can use #MobileProvision to tell the IDE which provision file should be used.

is this a typo? shouldn't it be #provisionfile instead?

Is it normal that the purshases work fine with the default provision file in debug mode?
Or is this in-app provisioning file only required for the release version?
 

sorex

Expert
Licensed User
maybe I had an app fixed provision file before and changed it back to the wildcard one when I had that certificate trouble earlier this week.

I now pointed to the right one for release mode.
 

sorex

Expert
Licensed User
I did some more testing here.

In my first app (Binairo) I added a "restore purchase" button to restore the purchase (ad remover) after a remove and reinstall of the app.

While this works fine it now appears to be overkill.

When I make another purchase of this non-consumable it seems like it will be another purshase with mentioning of description and given price.

But once you select "yes purshase" or whatever it was you get another screen telling something like "You already seemed to have purchased this. Purchase again for free?"

selecting yes hits the same callback as a valid purchase so it's less trouble.
 

marcick

Well-Known Member
Licensed User
Is it good to show the price of the various InApp purchases inside the app, in a "purchase" page ?
Or is it better only to place the buttons and let the user to see the prices when it clicks and then appear the box from the AppStore ?
 

ilan

Expert
Licensed User
Is it good to show the price of the various InApp purchases inside the app, in a "purchase" page ?
Or is it better only to place the buttons and let the user to see the prices when it clicks and then appear the box from the AppStore ?

in my opinion just put a button. when the user will click on it he will first get the price of the product then he can decide if he wants to purchase.

if you put a price then what will happen when you want to change the price? will you need to upload a new build? (with the new price)
or maybe load the price from a db?? i think the proper way is just put a button and the price will be shown when the user clicks on it.
 
Top