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:

ilan

Expert
Licensed User
Longtime User
Erel , does Sub MyStore_PurchaseCompleted trggered only after a successful payment or it is always triggered ? I mean do i have to add" if sucess then unlock all levels" under purchase completed ?


yes you will need to tell your app what happen when the purchase was successful

in this sub:

B4X:
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)

     if success = true then purchasedstuff(Product.ProductIdentifier)
End Sub

sub purchasedstuff (p as string)

if p = "alllevels" then 'alllevels is your product id for unlocking all levels...
   level4.enable = true
   '....
   'save a file that tells your app that all levels are unlocked
end if

end sub

and because this product is a non-consumable product (you will need only once to unlock all levels, right?!)
so you better save a file that tells you user has purchased all levels and on app start just ask for this file and if exists then
unlock all levels again... because you cannot ask on every app start to check if product has been purchased because this will ask user to enter his passwod to get to the app store and thats not a good way..

you may also add a button: Restore Purchases that will check if user has purchased any product (thats for someone that has uninstall your app after he has purchased a product from you and he wants to restore again the old purchases...)
 
Last edited:

tufanv

Expert
Licensed User
Longtime User
Yes Ilan Thank you. I was trying it and saw that altough user was canceling the transaction it was unlocking all levels :) what a mess

Now i added if success . Works perfectly :)

Thank you
 

Eumel

Active Member
Licensed User
Longtime User
If i store a file (or other way) that a user has buyed some in-app products, and check this first.
What is, if an user cancel a transaction after buying it ?

-------------
Eumel
 

ilan

Expert
Licensed User
Longtime User
If i store a file (or other way) that a user has buyed some in-app products, and check this first.
What is, if an user cancel a transaction after buying it ?

-------------
Eumel

create the file only if purchase was successfully...

(i dont think its possible to cancel a purchase after it was successfull...)
 

Eumel

Active Member
Licensed User
Longtime User
An user must have an option to refund his sell, i think.

"The iTunes App store sales policy clearly says that you cannot cancel a purchase or receive a refund for a purchase but they are known to make exceptions if you have a valid reason."

So it is possible to refund, and i need a way to check this ?

-----------------
Eumel
 

Eumel

Active Member
Licensed User
Longtime User
so, an user can buy a "pro" version, refund later (1-2 days), and can use the pro until he uninstall the app.
Or i call the productlist every start, but this is unconfortable for the user ..

Apple-RuleZ :mad::D
 

ilan

Expert
Licensed User
Longtime User
i put a new purchase for my app (Noadd) so a non-consumable purchase

i also put a button to restore old purchases, everything is ok but the TransactionsRestored event is not fired

i get in the logs the purchase complete was successful but after that the TransactionsRestored will not called
am i doing something wrong??


B4X:
    Sub MyStore_TransactionsRestored (Success As Boolean)
        Log(Success)
        If File.Exists(File.DirDocuments, "noads.txt") = False Then
            File.WriteString(File.DirDocuments, "noads.txt","1") 'save file
        End If
        Log("called")
    End Sub
 

ilan

Expert
Licensed User
Longtime User
i have one more question if i try to make a purchase without any internet connection should i get an error?
because i tried it and nothing happens, the app keep trying to make the purchase ...
 

ilan

Expert
Licensed User
Longtime User
The "purchasecomplete" event is raised and i get success = true thats it

For me its enough just wanna let you know that the trans. Restore event is not raised
 

jai

Active Member
Licensed User
Longtime User
How do you consume a consumable purchase?

In B4A it is manager.ConsumeProduct(ProductName), what is its equivalent in B4i?
 

tufanv

Expert
Licensed User
Longtime User
I have a problem here. in the app when i click buy button payment request which asks for password or confirms the purchase is not shown but in logs i see success and transaction complete ? what am i doing wrong

edit: Solved: Becuase I had logged in from the settings.
 
Last edited:

tufanv

Expert
Licensed User
Longtime User
I have the same problem Ilan Has. TransactionsRestored event is not firing. Is there any solution for this ?
 
Top