In-app Billing


The idea is to provide common In App Billing interface for most of available iap frameworks, so users could use in app purchases across platforms and iap frameworks with completely same or similar interface.

What IAB Interface provides:

  • Same API through all supported In-app billing frameworks on all platforms
  • Completely same workflow for all In-app Billing frameworks
  • Can dynamically detect which stores are installed on device and return the list to you in prioritized order, so you can have one single binary for all stores
  • Provides internal product ID usage through all In-app Billing frameworks, which might use different product IDs
  • Provides unique Receipt ID even if In-app Billing does not support it
  • Manages all the confirmation and consumption internally

Methods

Methods that are separate for each store are marked as red

  • IAB.detectStores(priority1, priority2, ... priorityN) -- returns table with store names, that are available on device in provided priority order
  • IAB.new(iabframework) -- initialize specified IAB framework
  • IAB:setUp(value1, value2, ..., valueN) -- provide all the keys/devids/appids/etc needed for the framework, which you will get in same order on Native part in Map object
  • IAB:setProducts({internalId1 = "storeId1", internalId2 = "storeId2", ..., internalIdn = "storeIdn"}) -- provide list of products you will be using (key is your internal products id, value is store specific product id)
  • IAB:setConsumables({"internalId1", "internalId2", ..., "internalIdn"}) -- which of your products are consumables, that people can buy many times (provide internal product ids)
  • IAB:isAvailable() --check if IAB is available, raises event:
    • Event.AVAILABLE --iab is available
  • IAB:requestProducts() --request information for products provided in setProducts method
    • Event.PRODUCT_COMPLETE
      • event.productId
      • event.title
      • event.description
      • event.price
    • Event.PRODUCT_ERROR
      • event.error
  • IAB:purchase(prodId) --purchase product by providing your internal product id, raises two events:
    • Event.PURCHASE_COMPLETE
      • event.productId
      • event.receiptId
    • Event.PURCHASE_ERROR
      • event.error
  • iab:restore() --raise purchase events for each previously purchases entitled (not consumed) items, raises two events:
    • Event.RESTORE_COMPLETE
    • Event.RESTORE_COMPLETE
      • event.error
  new setUp
Amazon
amazon = IAB.new("amazon")
does nothing
Fortumo
fortumo = IAB.new("fortumo")
fortumo:setUp("SERVICE_ID", "APP_SECRET")
GoogleBilling v3
google = IAB.new("google")
google:setUp("google billing key")
IOS
ios = IAB.new("ios")
does nothing
Nokia
nokia = IAB.new("nokia")
does nothing
OUYA
ouya = IAB.new("ouya")
--read in ouya key
local file = io.open("key.der", "rb")
local appKey = file:read( "*a" )
io.close( file )

ouya:setUp("ouya dev key", appKey)
Samsung
samsung = IAB.new("samsung")
samsung:setUp("itemGroupId")

Legend:

Alpha
Beta
Stable

Choose the frameworks you will use and delete all the unneeded based on file dependency table for each framework below

Copy libs folder into your exported project

Copy src folder into your exported project

Add System.loadLibrary("iab"); to your main activity

Add "com.giderosmobile.android.plugins.iab.Iab" as external class in your main activity

Remove default Google Billing v2 plugin from exported project, as it may conflict with Google Billing v3 plugin

Modify AndroidManifest application tag based on the frameworks you want to use using table below

Modify AndroidManifest permissions based on the frameworks you want to use using table below

  Application Permission Files
Amazon
<receiver android:name = "com.amazon.inapp.purchasing.ResponseReceiver" >
    <intent-filter>
       	<action android:name = "com.amazon.inapp.purchasing.NOTIFY" android:permission = "com.amazon.inapp.purchasing.Permission.NOTIFY" />
    </intent-filter>
</receiver>
 
  • libs\in-app-purchasing-1.0.3.jar
  • src\com\giderosmobile\android\plugins\iab\IabAmazon.java
Fortumo
<receiver android:name="com.fortumo.android.BillingSMSReceiver">
    	<intent-filter>
        	<action android:name= "android.provider.Telephony.SMS_RECEIVED"/>
    	</intent-filter>
</receiver>
<service android:name="com.fortumo.android.FortumoService" />
<service android:name="com.fortumo.android.StatusUpdateService" />
<activity android:name="com.fortumo.android.FortumoActivity" android:theme="@android:style/Theme.Translucent.NoTitleBar" />
<activity android:configChanges="orientation|keyboardHidden|screenSize" android:name="com.fortumo.android.FortumoActivity" android:theme="@android:style/Theme.Translucent.NoTitleBar"></activity>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.SEND_SMS" />
	
<uses-feature android:name="android.hardware.telephony" android:required="false"></uses-feature>
  • libs\FortumoInApp-android-9.0.41.jar
  • src\com\giderosmobile\android\plugins\iab\fortumo folder
  • src\com\giderosmobile\android\plugins\iab\IabFortumo.java
GoogleBilling v3  
<uses-permission android:name="com.android.vending.BILLING" />
  • src\com\android\vending\billing folder
  • src\com\giderosmobile\android\plugins\iab\google folder
  • src\com\giderosmobile\android\plugins\iab\IabGoogle.java
Nokia  
<uses-permission android:name="com.nokia.payment.BILLING"/>
  • src\com\nokia\payment\iap\aidl folder
  • src\com\giderosmobile\android\plugins\iab\IabNokia.java
OUYA
Add 
<category android:name="tv.ouya.intent.category.GAME"/> 
inside main activity intent-filter
 
  • libs\commons-lang-2.6.jar
  • libs\guava-r09.jar
  • libs\jackson-core-asl-1.8.4.jar
  • libs\jackson-mapper-asl-1.8.4.jar
  • libs\ouya-sdk.jar
  • src\com\giderosmobile\android\plugins\iab\IabOuya.java
Samsung  
<uses-permission android:name="com.sec.android.iap.permission.BILLING"/>
  • src\com\sec\android folder
  • src\com\giderosmobile\android\plugins\iab\samsung folder
  • src\com\giderosmobile\android\plugins\iab\IabSamsung.java

Legend:

Alpha
Beta
Stable

Choose the frameworks you will use and delete all the unneeded based on file dependency table for each framework below

Copy contents of Plugins directory into your exported project's Plugins directory

Add copied files to your Xcode project (Check create groups for added folders)

Add IOS frameworks that is required by your selected In-app Billing provider from table below

  1. In the project navigator, select your project
  2. Select your target
  3. Select the 'Build Phases' tab
  4. Open 'Link Binaries With Libraries' expander
  5. Click the '+' button
  6. Select framework
  7. Click Add
  Frameworks Files
IOS
  • StoreKit
  • Plugins/iab/iab.h
  • Plugins/iab/iab.mm
  • Plugins/iab/iabbinder.cpp
  • Plugins/iab/IabIos.h
  • Plugins/iab/IabIos.mm

Legend:

Alpha
Beta
Stable

--require plugin
require "iab"

--create iab instance based on store you want to use

if application:getDeviceInfo == "Android" then
	iab = IAB.new("google")

	--provide key(s) needed for the store
	iab:setUp("google billing key")

	--provide list of products you will be using 
	--(key is your internal products id, value is store specific product id)
	iab:setProducts({p1 = "android.test.purchased", p2 = "android.test.purchased", p3 = "android.test.purchased"})

else --its ios
	iab = IAB.new("ios")

	--provide list of products you will be using 
	--(key is your internal products id, value is store specific product id)
	iab:setProducts({p1 = "com.app.p1", p2 = "com.app.p2", p3 = "com.app.p3"})
end

--which of your products are consumables, 
--that people can buy many times (provide internal product ids)
iab:setConsumables({"p1", "p2"})

--[[ CHECKING IF STORE IS AVAILABLE ]]--
iab:addEventListener(Event.AVAILABLE, function(e)
	print("is available")
	--usually here we would set a flag that it is possible to make purchases
	--basically you can allow doing all the iap stuff after this event is called
	
	--[[ REQUESTING PRODUCTS ]]--
	--if this event is called, we received the list of products and information about them
	iab:addEventListener(Event.PRODUCTS_COMPLETE, function(e)
		for i = 1, #e.products do
			local p = e.products[i]
			--id, title, description and price
			print(p.productId, p.title, p.description, p.price)
		end
	end)
	
	--else we could not retrieve information about products now
	iab:addEventListener(Event.PRODUCTS_ERROR, function(e)
		print(e:getType(), e.error)
	end)
	
	--requesting products
	iab:requestProducts()
	
	--[[ PURCHASING ]]--
	
	iab:addEventListener(Event.PURCHASE_COMPLETE, function(e)
		--purchases successfully completed 
		--here you need to check if receiptId was not already saved previously
		--as in if purchase was not already made
		--then you can unlock the item here
		--and store receiptId presistently to know 
		--that you have already provided this item to user
		print(e:getType(), e.productId, e.receiptId)
	end)
	iab:addEventListener(Event.PURCHASE_ERROR, function(e)
		--it was not possible to complete the purchase, 
		--inform user
		print(e:getType(), e.error)
	end)
	
	--lets purchase something
	stage:addEventListener(Event.MOUSE_DOWN, function()
		print("purchasing")
		iab:purchase("p1")
	end)
	
	--[[ RESTORING PURCHASES ]]--
	-- we can either provide button to restore purchases or launch it on every app start
	-- this will simply launch purchase event for every unconsumable item
	iab:restore()

end)
--this function will call Event.AVAILABLE if purchases are available
--until then you must assume that it is not available
iab:isAvailable()