GLBasic forum

Codesnippets => Code Snippets => Topic started by: ampos on 2011-Aug-09

Title: iOS InApp Purchases
Post by: ampos on 2011-Aug-09
How to use InApp Purchases in Apple's iOS devices.

This code completly has been done by MATCHY, so you have to cheer him, not me  :nw: :enc: :nw: :enc: :nw: :enc:

These are the steps I have followed, as explained in a online guide (http://troybrant.net/blog/2010/01/in-app-purchases-a-full-walkthrough/). Some steps may be necesaries or not, but I have follow this.

As far as I know, it works in all iOS version and devices. In some jailbroken devices it does not work, but on others it does.

The file InApp.mm has been modified by Michael Werren, and it now works with user cancelled purchases.

Please, follow STRICTLY the following procedure to have InApp purchases working. It is known that it works if you follow it.

-Create your apple app ID as always in Apple Itunes Connect page. In this example, I will use "MyApp", with ID "com.me.myapp"

-Upload your test binary program to itunes connect. Once uploaded, reject the binary.

-Go to your app itunes connect and "create a purchase".I have not created/tested (yet) anything but non-consumable purchase...

--Reference Name: common name for the product. I used "Full version". This name is non-editable, and it will not be displayed in the App Store.

--Product ID: unique id for your app. Typically of the form com.company.appname.product, but it can be whatever you want. It does not need to have your app's App ID as a prefix. I will use "myapp.full"

--Type: You have 3 choices:

        Non-consumable: only pay once (use this if you want a free-to-pro-upgrade product)
        Consumable: pay for every download
        Subscription: recurring payment

--Price Tier: price of the product. See the price matrix for the different tiers.

--Cleared for Sale: check this now. If you don't, you will get back an invalid product ID during testing.

--Language to Add: Pick one. The following two fields will appear:

--Displayed Name: Name of your product shown to your user. I chose "Upgrade to Full".

--Description: What the product does. The text you enter here is sent along with the Displayed Name and Price when you fetch an SKProduct in code.

--Screenshot: Your feature in action. Despite the text on the screen about the screenshot submission triggering the product review process (a very sloppy design choice, IMHO), you can safely add the screenshot now without the product being submitted for review. After saving the product, just choose the "Submit with app binary" option. This will tie the product to the app binary, so when you finally submit the 100% complete app binary, the product will be submitted as well.

-Create a Test User for your program in the iTunes Connect page (manage users -> test user -> create). Before trying to check the purchase process on the iOS, you should  logoff from your itunes appstore account (settings -> store -> logoff).

Back to GLBasic and your program...

Write code for managing you InApp purchases.

On the XCode project, you have to make something:

-Add "StoreKit.framework" in the frameworks windows.

-Add in the resources window the files "inapp.mm" and "inapp.h"

Follow the GLB source code to understand how it works.

In XCode keep open the console window to see all the msgs that Apple sent to the iOSthing and the debug msgs from the source code.


GLBasic sample source code

Code (glbasic) Select
// --------------------------------- //
// Project: inapptest
// Start: Tuesday, April 26, 2011
// IDE Version: 9.077

FUNCTION main_test:

// First we have to check if iOS InApp has been cracked...

glb_inapp_buy("pirata")
local request_data$ = "NO_DATA"
REPEAT
showscreen
request_data$ = UCASE$(glb_inapp_product_request())
UNTIL request_data$="TRANSACTION_SUCCESSFUL" OR request_data$="TRANSACTION_FAILED"

IF request_data$="TRANSACTION_SUCCESSFUL"
                debug "InApp purchase is cracked!"
SLEEP 3000
RETURN
ENDIF

LOCAL id_list$ = "myapp.full,myapp.extras"  // product id, myapp.extras does not exist in our example
request_data$ = "NO_DATA"

LOCAL is_online$ = glb_inapp_is_online()
CLEARSCREEN 0xffffff
PRINT "Is online: " + is_online$, 10, 10, TRUE
SHOWSCREEN
MOUSEWAIT

CLEARSCREEN 0xffffff
glb_inapp_init(id_list$)
WHILE request_data$ = "NO_DATA"
PRINT PLATFORMINFO$("TIME"), 0, 0, TRUE
PRINT "Requesting product listing...", 10, 10, TRUE
SHOWSCREEN
request_data$ = glb_inapp_product_request()
WEND

debu("[LISTING]:" + request_data$)

LOCAL item$[]
LOCAL item_count = SPLITSTR(request_data$, item$[], "##")
LOCAL i

CLEARSCREEN 0xffffff
PRINT "Products retreived", 10, 10, TRUE
PRINT "Tap screen to BUY first product (upgrade)", 10, 30, TRUE
IF item_count > 3
FOR i = 0 TO item_count - 1 STEP 4
PRINT i + ". " + item$[i + 1], 10, 50 + (i * 14)
PRINT item$[i + 2], 20, 60 + (i * 14)
PRINT item$[i + 3], 20, 70 + (i * 14)
NEXT
ELSE
PRINT 0 + ". " + "NO PRODUCTS or ERROR.", 20, 50 + (i * 14)
ENDIF
SHOWSCREEN
MOUSEWAIT
SHOWSCREEN

CLEARSCREEN 0xffffff
glb_inapp_buy("myapp.full")
request_data$ = "NO_DATA"
WHILE request_data$ <> "TRANSACTION_SUCCESSFUL" OR request_data$ <> "TRANSACTION_FAILED"
PRINT PLATFORMINFO$("TIME"), 0, 0, TRUE
PRINT "Transacting purchase...", 10, 10, TRUE
SHOWSCREEN
request_data$ = glb_inapp_product_request()   //I changed this to =UCASE$(glb...())
WEND
debu("[TRANSACTION]:" + request_data$)
IF request_data$ = "TRANSACTION_SUCCESSFULL"
debu("Product flagged locally") // eg. dat file store local purchased flag for product (upgrade)
ELSEIF request_data$ = "TRANSACTION_FAILED"
debu("User probably cancled or no funds") // eg. dat file ignore
ENDIF

END
ENDFUNCTION

SUB GLB_ON_PAUSE:
pausado = 1
debu("MAIN PAUSE")
ENDSUB

SUB GLB_ON_RESUME:
pausado = 0
debu("MAIN RESUME")
ENDSUB

SUB GLB_ON_QUIT:
pausado = -1
debu("MAIN QUIT")
ENDSUB

FUNCTION debu: data_in$
?IFDEF IPHONE
STDOUT "[GLB]->" + data_in$ + "\n"
?ELSE
DEBUG "[GLB]->" + data_in$ + "\n"
?ENDIF
ENDFUNCTION

?IFDEF IPHONE
IMPORT "C" char* glb_inapp_is_online()
IMPORT "C" int glb_inapp_can_pay()
IMPORT "C" void glb_inapp_init(const char* id_list)
IMPORT "C" char* glb_inapp_product_request()
IMPORT "C" void glb_inapp_buy(const char* product_id)
?ELSE
FUNCTION glb_inapp_is_online:
ENDFUNCTION

FUNCTION glb_inapp_can_pay:
ENDFUNCTION

FUNCTION glb_inapp_init: id_list
ENDFUNCTION

FUNCTION glb_inapp_product_request:
ENDFUNCTION

FUNCTION glb_inapp_buy: product_id
ENDFUNCTION
?ENDIF


NOTE: In iTunes connect, when you are ready to sent your app to review, on the page where you upload the graphics, at the bottom, there is a paragraph titled "In App purchases". Edit it and enable the InApp purchases that you want Apple's review team to review, or your app will not have InApp purchases availables.


[attachment deleted by admin]
Title: Re: iOS InApp Purchases
Post by: ampos on 2011-Aug-09

And here is the code used on my current source code:

Code (glbasic) Select
FUNCTION compra:
LOCAL ys=110*appzoom

debu("Comprando...")

LOCAL id_list$ = "glowingsky.full"  // product id
LOCAL request_data$ = "NO_DATA"

glb_inapp_init(id_list$)
WHILE request_data$ = "NO_DATA"
PRINT PLATFORMINFO$("TIME"), 0, ys, TRUE
PRINT "Getting into AppStore", 0, ys+(30*appzoom), TRUE
SHOWSCREEN
request_data$ = glb_inapp_product_request()
WEND
debu("[LISTING]:" + request_data$+" [END]")

LOCAL item$[]
LOCAL item_count = SPLITSTR(request_data$, item$[], "##")
LOCAL i

IF item_count > 3
PRINT "Access granted", 10, ys, TRUE
PRINT "Tap to upgrade", 10, ys+(30*appzoom), TRUE
FOR i = 0 TO item_count - 1 STEP 4
PRINT i+" ID:"+item$[i],0,ys+(180*appzoom);debu(i+" ID:"+item$[i])
PRINT "Short:"+item$[i+1],0,ys+(90*appzoom);debu("Short:"+item$[i+1])
PRINT "Price:"+item$[i+2],0,ys+(120*appzoom);debu("Price:"+item$[i+2])
PRINT "Longg:"+item$[i+3],0,ys+(150*appzoom);debu("Longg:"+item$[i+3])
NEXT
ELSE
PRINT "NO ACCESS or ERROR.", 0,ys
ENDIF
SHOWSCREEN
MOUSEWAIT

glb_inapp_buy("glowingsky.full")
request_data$ = "NO_DATA"
REPEAT    // THIS IS THE LOOP THAT DOES NOT DETECT THE USER CANCELLATION
PRINT PLATFORMINFO$("TIME"), 0, 0, TRUE
PRINT "Transacting purchase...", 0, 30, TRUE
SHOWSCREEN
request_data$ = UCASE$(glb_inapp_product_request())
IF request_data$<>"NO_DATA" THEN debu("[MSG]->"+request_data$+"<-")
UNTIL request_data$="TRANSACTION_SUCCESSFUL" OR request_data$="TRANSACTION_FAILED"

debu("[TRANSACTION]:" + request_data$)
IF request_data$ = "TRANSACTION_SUCCESSFUL"
debu("DONE") // eg. dat file store local purchased flag for product (upgrade)
ELSEIF request_data$ = "TRANSACTION_FAILED"
debu("ERROR!") // eg. dat file ignore
ENDIF

END
ENDFUNCTION
Title: Re: iOS InApp Purchases
Post by: ampos on 2011-Aug-09
Just checked with "consumable" purchases and it works, also.
Title: Re: iOS InApp Purchases
Post by: ampos on 2011-Aug-10
My app with InApp purchases in action...

[attachment deleted by admin]
Title: Re: iOS InApp Purchases
Post by: ampos on 2011-Aug-10
More screenshots.


[attachment deleted by admin]
Title: Re: iOS InApp Purchases
Post by: matchy on 2011-Aug-10
Well done! I'm glad you got around to using my uncredited wrapper.  :P

I had issues with the app store, so I'll be keen to see it working live.
Title: Re: iOS InApp Purchases
Post by: spicypixel on 2011-Aug-10
Just glanced at this but it uses TRANSACTION_SUCCESSFUL and TRANSACTION_SUCCESSFULL ??
Title: Re: iOS InApp Purchases
Post by: Crivens on 2011-Aug-10
Nice one guys, this looks brilliant.

A couple of questions though:-
1. When you say it doesn't work for cancellations, does that mean if they cancel they still get the upgrade or what?

2. What happens if the user re-installs the app, or installs on another machine? How do they keep their purchases (ie. do we have to handle this like keep a flag on a website)? And if they don't then is this just a standard Apple thing?

3. For an upgrade from free to pro, for example, then does this method mean we store a local flag or is there an alternative method where apple can overwrite the free binary with a different binary? I'm just thinking that if it's just a flag then a free one is basically a full version without a flag and is open more to piracy, and also you have to include all extra data (eg. extra levels) in the free game. Or do we have to handle that? Eg. store extra level data on our own site.

For example my original game is much smaller than the full version because I don't include all the higher def pictures for the additional levels. If it's just a flag then a free one would still be 4 or 5 times the size. Then again, I guess it's easier this way and space is less important.

Cheers

Title: Re: iOS InApp Purchases
Post by: ampos on 2011-Aug-10
LOL, sorry Matchy, I wrote this post with my wife yelling "work and don't lost your time!" at my back... I will fix it.

It is SUCESFUL with 1 L, but Matchy's original code had 2 LL, forgot to fix it.

1.- No, if he cancels the purchase, the program will not detect it and will not go outside the loop. It is just looking for an OK or ERROR, not CANCEL. This CANCEL msg is not sent back by the xcode source.

2.- If you reinstall the app and press the BUY button, iTunes just say "you had bought this item previously, press OK to download it again" and GLB just get a OK msg. In fact, you can not know if it is a new or old purchase.

3.- In any case you have to store somewhere the "upgrade" flag. When I get the OK msg I do this:

Code (glbasic) Select
iniopen "prefs.txt"
iniput "main","full",encrypt("password",platforminfo$("ID"))
full=true


and at the start I set this

Code (glbasic) Select
iniopen "prefs.txt"
a$=iniget("main","full")
a$=decrypt("password",a$)
if a$=platforminfo("ID")
   full=true
else
   full=false
endif


Perhaps you have to download the extra gfx once it is bought.
Title: Re: iOS InApp Purchases
Post by: Crivens on 2011-Aug-10
Ah ok, so there isn't a way to query iTunes to see what you have previously bought? Bummer if installing on a second device I guess. Still better for us when you look at it that way :)

I take it though that all info will be remembered in iTunes, so if the device needs a wipe and restore then all your old created files will be still there, including things like upgrade flags and the like.

Unless of course iTunes remembers the purchases (at least Non-consumable) like it now does with normal purchases, and then if you do select to purchase on a 2nd device (or re-installed one) then it will go through the process but not actually charge you.

Cheers
Title: Re: iOS InApp Purchases
Post by: ampos on 2011-Aug-10
The upgrade flag is not saved, as it is writing by your program. The user has to bought it again, but itunes will return OK/BOUGHT although there was not really a bought.

Also, any itunes email account can be used upto 5 iOS devices, so a user can bought 1 app/InApp and use/install it in his iphone, his wife's, his ipad and in the children iPod at no extra cost.
Title: Re: iOS InApp Purchases
Post by: Crivens on 2011-Aug-10
I get that with a whole application (I do it between my iPods and my iPhone), but not with in-app purchases.

This article sounds interesting:-
http://www.tuaw.com/2011/03/08/dear-aunt-tuaw-do-i-have-to-re-buy-apps-for-all-my-devices/ (http://www.tuaw.com/2011/03/08/dear-aunt-tuaw-do-i-have-to-re-buy-apps-for-all-my-devices/)

Particularly this paragraph:-
QuoteAs for in-app purchases, it depends. Non-consumable purchases, i.e. buy once, use-forever purchases are good for all devices registered to an account. Examples of nonconsumable purchases include adding game levels, enabling ad-removal, and unlocking features. Once unlocked, they remain available for all devices. Application developers are able to check for prior purchase and apply that purchase to new devices through a process known as restoring purchases.
And especially the last line about restoring purchases.

Cheers
Title: Re: iOS InApp Purchases
Post by: ampos on 2011-Aug-10
As I said, once you press BUY, iOS will tell you it was already bought, asking to press OK for a free download. In fact, you can see the (spanish) advise in capture 6.jpg of my previous post.
Title: Re: iOS InApp Purchases
Post by: Crivens on 2011-Aug-10
Ah ok, sorry I didn't understand what you said. I thought you meant just on the main purchases from the app store.

So basically any non-consumable in-app purchases then if you install on another device, attempting to purchase the in-app purchase again will just tell you have done this already and to download for nothing (I assume this is what the Spanish text says), but for consumable purchases (eg. extra ammo) then tough you have to buy again? (fair enough as is a different device).

Cheers
Title: Re: iOS InApp Purchases
Post by: ampos on 2011-Aug-10
Yes, consumables purchases have to be bought any time.

-Non-consumable: buy a new fish for your aquarium.

-Consumable: buy food for your fish.

-Suscription: each month, receive 10 liters of fresh water!

Actually, there are 2 suscription modes avaiable: auto and manual. Quoted from Apple:

QuoteConsumable

A consumable In-App Purchase must be purchased every time the user downloads it. One-time services, such as fish food in a fishing app, are usually implemented as consumables.

Non-Consumable

A non-consumable In-App Purchase only needs to be purchased once by the user. Services that do not expire or decrease with use, such as a new race track for a game app, are usually implemented as non-consumables.

Auto-Renewable Subscriptions

An auto-renewable In-App Purchase subscription allows the user to purchase in-app content for a set duration of time. At the end of that duration the subscription will renew itself, unless the user opts out. An example of an auto-renewable subscription would be a magazine or newspaper that takes advantage of the auto-renewing functionality built into iOS.

Auto-renewable subscriptions will be delivered to all devices associated with the user's Apple ID. When you create an auto-renewable subscription in iTunes Connect, you begin by selecting the duration(s) that you will offer. When a duration ends, the App Store will automatically renew the subscription. Note that if the user has opted out of this functionality, the subscription will expire at the end of that duration. You must make sure that your app can determine whether a subscription is currently active and renewable.

Non-Renewing Subscription

In the past, a non-renewing In-App Purchase subscription has been used for services with a limited duration. An example of this would be a magazine or newspaper that requires users to renew their own subscriptions. Non-renewing subscriptions can still be offered, but auto-renewable subscriptions are now preferred for the following reasons:

    When creating an auto-renewable subscription, you can easily set up the various durations that you want to offer. Non-renewing subscriptions do not have this feature, so you must provide the information some other way. As this is often done in the display name, you end up with a separate listing for every possible duration. By contrast, auto-renewable subscriptions allow you to have a single listing where the user simply chooses one of the durations that you offer.

    Because a non-renewing subscription requires a user to renew each time, your app must contain code that recognizes when the subscription is due to expire. It must also prompt the user to purchase a new subscription. An auto-renewable subscription eliminates these steps.

    As part of iOS, an auto-renewable subscription will automatically be delivered to all devices associated with the user's Apple ID. To make device-syncing available for a non-renewing subscription, you would have to create your own delivery system.

Title: Re: iOS InApp Purchases
Post by: matchy on 2011-Aug-10
I'm not sure, but I think Apple returns the incorrect spelling of "SUCCESSFULL or is it my typo?  ;/

:good:
Anyhow, I am keen to see the first glb app with it running on the app store.
Title: Re: iOS InApp Purchases
Post by: Omadan on 2011-Aug-10
Same here. Let us know Ampos when its live
Title: Re: iOS InApp Purchases
Post by: msx on 2011-Aug-10
+2  :whistle:
Title: Re: iOS InApp Purchases
Post by: Millerszone on 2011-Aug-10
Excellent work Ampos!
:good: :good: :good: :good: :good: :good:
Title: Re: iOS InApp Purchases
Post by: blackway on 2011-Aug-10
Ampos, you said that this wrapper doesn't work under IOS 4.2.1 .  Is this a problem related with JB or it doesn't work in any device under IOS 4.2.1  ??
Thanks!!!

Title: Re: iOS InApp Purchases
Post by: ampos on 2011-Aug-10
I have just tested it with 1 device with iOS 4.2, I am updating one of my 3G-NoJB to 4.2.1 for testings. I dont think it is related to JB as one of the devices is JB and working.

Matchy, the part that fails is the list request. On this machine, it answer "no listed product", you knwo, the very first step.

Note that previous iAD wrapper by Matchy didnt work in iOS 4.2+, as the iOS call was changed from "display_320x50" to "display_horizontal", so we changed the routine to check first iOS version, and call one or the other. Could be this similar?

I just need to add iAD to the same app and it will be ready to be sent to Apple.
Title: Re: iOS InApp Purchases
Post by: blackway on 2011-Aug-10
Quote from: ampos on 2011-Aug-10
I have just tested it with 1 device with iOS 4.2, I am updating one of my 3G-NoJB to 4.2.1 for testings. I dont think it is related to JB as one of the devices is JB and working.

Matchy, the part that fails is the list request. On this machine, it answer "no listed product", you knwo, the very first step.

Note that previous iAD wrapper by Matchy didnt work in iOS 4.2+, as the iOS call was changed from "display_320x50" to "display_horizontal", so we changed the routine to check first iOS version, and call one or the other. Could be this similar?

I just need to add iAD to the same app and it will be ready to be sent to Apple.
Thanks Ampos for your reply!

I guess that isn't a good idea to submit any app with this InApp purchases wrapper until Matchy fix this problem with IOS 4.2+

Bye!


Title: Re: iOS InApp Purchases
Post by: ampos on 2011-Aug-10
It is not (yet) a problem with 4.2+, it is just 1 4.2 unit tested and failing. More test are needed before saying it does not work on 4.2+  :)
Title: Re: iOS InApp Purchases
Post by: okee on 2011-Aug-10
Are you still liable to get pursued by Lodsys for using InApp purchasing ?
Title: Re: iOS InApp Purchases
Post by: matchy on 2011-Aug-11
Quote from: blackway on 2011-Aug-10
Quote from: ampos on 2011-Aug-10
I have just tested it with 1 device with iOS 4.2, I am updating one of my 3G-NoJB to 4.2.1 for testings. I dont think it is related to JB as one of the devices is JB and working.

Matchy, the part that fails is the list request. On this machine, it answer "no listed product", you knwo, the very first step.

Note that previous iAD wrapper by Matchy didnt work in iOS 4.2+, as the iOS call was changed from "display_320x50" to "display_horizontal", so we changed the routine to check first iOS version, and call one or the other. Could be this similar?

I just need to add iAD to the same app and it will be ready to be sent to Apple.
Thanks Ampos for your reply!

I guess that isn't a good idea to submit any app with this InApp purchases wrapper until Matchy fix this problem with IOS 4.2+

Bye!

Please note, I am unable to use or support InApp wrapper for quite some time.  :noggin: Besides, I only run the latest official iOS version updates only.
Title: Re: iOS InApp Purchases
Post by: ampos on 2011-Aug-11
Matchy, in fact, it is the inverse.

Your previous iAD wrapper didnt work on 4.2+ iOS, only in earlier ones.

And InApp work on all my machines (-4.2) but not on my only 4.2 machine. I have sooo many apps on my machine that I dont want to upgrade to 4.3.5, the latest.

Also, my wife iPhone is 4.1, and I dont want to upgrade her yet.

I hope to have tomorrow a different 4.2 working machine, even a 4.3.4 one.
Title: Re: iOS InApp Purchases
Post by: matchy on 2011-Aug-11
How about iOS 5 beta?
Title: Re: iOS InApp Purchases
Post by: ampos on 2011-Aug-11
Tested on 3G 4.2.1...

It runs and fail.

It request the list of current in-app purchases and it is received correctly (here it was were my 4G-4.2.0 fails), but when requesting the payment, there is no answer. Perhaps is a tremporary fail on Apple side.

Im going to test on a unJB 4G-4.3.5, the latest one.
Title: Re: iOS InApp Purchases
Post by: ampos on 2011-Sep-04
To help you to implement InApp purchases, here is the full source code of my app InApp Purchase routines:

Code (glbasic) Select
FUNCTION check_free: // this one is called at the first run of the app to check if it was fully registered previously
LOCAL a$

dpat$=PLATFORMINFO$("Documents")

INIOPEN dpat$+"/prefs.txt"

a$=INIGET$("Main","Full")
a$=DECRYPT$("---",a$)
IF a$=PLATFORMINFO$("ID") THEN free=0

ENDFUNCTION

FUNCTION compra_ok:  /this one is called after a sucesfull purchase, to set the app as registered.
LOCAL a$

INIOPEN dpat$+"/prefs.txt"

INIPUT "Main","Full",ENCRYPT$("Dimas",PLATFORMINFO$("ID"))
INIOPEN dpat$+"/cccc"

ENDFUNCTION


FUNCTION compra:   // this is called to start the inapp purchases
?IFDEF IPHONE
compra_ios()
?ENDIF

?IFDEF WEBOS
compra_webos()
?ENDIF

?IFDEF WIN32
compra_win()
?ENDIF

?IFDEF ANDROID
compra_win()
?ENDIF


ENDFUNCTION

FUNCTION compra_win:  //just a call to a external paypal pay-me button or the full app
IF free=0
NETWEBEND "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=KYU26B8XLMVAN&custom="+"W("+PLATFORMINFO$("ID")+")"
ELSE
NETWEBEND "http://developer.palm.com/appredirect/?packageid=com.diniplay.glowingsky"
ENDIF

REPEAT;UNTIL MOUSEAXIS(3)=0

ENDFUNCTION

FUNCTION compra_webos:
IF free=0
NETWEBEND "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=KYU26B8XLMVAN&custom="+"W("+PLATFORMINFO$("ID")+")"
ELSE
NETWEBEND "http://developer.palm.com/appredirect/?packageid=com.diniplay.glowingsky"
ENDIF

REPEAT;UNTIL MOUSEAXIS(3)=0
ENDFUNCTION

FUNCTION compra_ios:   //the real iOS purchase procedure
LOCAL ys=120*appzoom,z=1,n=1,p

debu("Comprando...")

LOCAL id_list$ = "glowingsky.full,glowingsky.don1,glowingsky.don2,glowingsky.don5,glowingsky.dona1,glowingsky.dona2,glowingsky.dona5"  // product id
//notice I am asking for the purchases of the free version (...donX) and full version (...donaX). So I have not to change anything from compiling one or other version.
//iTunes will answer with the rights inApp purchases

LOCAL request_data$ = "NO_DATA"

glb_inapp_init(id_list$)
WHILE request_data$ = "NO_DATA"
main(3);ALPHAMODE -1  //main() is the background/main drawer routine
DRAWSPRITE 7,xoff,0 //it is just a banner on the top
cprint("Contacting AppStore...",xres/2,yres/2)
sc()
request_data$ = glb_inapp_product_request()
WEND  //waiting for iTunes answering if my InApp purchases list request is ok
debu("[LISTING]:" + request_data$+" [END]")

?IFDEF WIN32
request_data$="glowingsky.don1##Donation 1##0.79##Donate some money to the programmer for encouraging him for more proyects.##glowingsky.don2##Donation 2##1.59##Donate some money##glowingsky.don5##Donation 5##3.99##Donate some money##glowingsky.full##Version completa##0.79##Actualiza la app a la version completa.##"
//this is the exact string itunes will answer, used for testing on windows the rest of the code
?ENDIF

LOCAL item$[]
LOCAL item_count = SPLITSTR(request_data$, item$[], "##")   //split the previous string
LOCAL i   

FreeZones()

IF item_count > 3  //if the answer is less than 3 strings, there was an error
REPEAT
ys=120*appzoom;n=1
main(3);ALPHAMODE -1
ADRAWSPRITE 7,xoff,0
DRAWSPRITE 3,(xres-(640*appzoom))/2,ys  //draw a button
cprint("CHOOSE YOUR OPTION",xres/2,ys+(20*appzoom));INC ys,100*appzoom
FOR i = 0 TO item_count - 1 STEP 4
IF item$[i]="glowingsky.full" AND free=0  //if free=1 then is is the full app, instead it is the lite. Not sure now about this IF
// Oh, I remember, was to remove the FULL button, in case it was registered and the user just want to donate me extra money
ELSE
DRAWSPRITE 8,(xres-boton)/2,ys  //draw a button
PRINT UCASE$(item$[i+1]),(xres-boton)/2+(20*appzoom),ys+(40*appzoom),1
PRINT item$[i+2],((xres-boton)/2)+boton-(24*appzoom)-LEN(item$[i+2],1),ys+(44*appzoom),1
CreateZone(n,0,ys,xres,124*appzoom);INC n
INC ys,120*appzoom
ENDIF
NEXT

INC ys,20*appzoom
DRAWSPRITE 3,(xres-(640*appzoom))/2,ys
cprint ("CANCEL",xres/2,ys+(24*appzoom))
CreateZone(100,0,ys,xres,124*appzoom)  //the cancel button

IF free=1
INC ys,90*appzoom
cprint("Any purchase will",xres/2,ys)
cprint("unlock full program",xres/2,ys+(40*appzoom))
ENDIF

MOUSESTATE mx,my,b1,b2
z=Zone(mx,my)

sc()  //bassically, a showscreen()
UNTIL b1=1 AND z<>0
ELSE  //I said if it has no answer...
REPEAT;UNTIL MOUSEAXIS(3)=0
REPEAT
main(3);ALPHAMODE -1
cprint ("NO ACCESS or ERROR.",xres/2,yres/2)
sc()
UNTIL MOUSEAXIS(3)<>0
RETURN
ENDIF

IF z=100 THEN RETURN  //Zone 100 was a cancel button

debu("COSA:"+item$[(z-1)*4])  //debu is my debug routine

glb_inapp_buy(item$[(z-1)*4])
request_data$ = "NO_DATA"

REPEAT  //user choose a purchase. Wait for itunes to validate (or not) it
main(3);ALPHAMODE -1
ys=120*appzoom;n=1
DRAWSPRITE 3,(xres-(640*appzoom))/2,ys
cprint("REQUESTING PURCHASE",xres/2,ys+(20*appzoom));INC ys,100*appzoom

FOR i = 0 TO item_count - 1 STEP 4  //draw the butttons while waiting
IF item$[i]="glowingsky.full" AND free=0
//
ELSE
IF n=z   //the choosen one is brighter
ALPHAMODE -1
ELSE
ALPHAMODE -.5
ENDIF
INC n
DRAWSPRITE 8,(xres-boton)/2,ys
PRINT UCASE$(item$[i+1]),(xres-boton)/2+(20*appzoom),ys+(40*appzoom),1
PRINT item$[i+2],((xres-boton)/2)+boton-(24*appzoom)-LEN(item$[i+2],1),ys+(44*appzoom),1
INC ys,120*appzoom
ENDIF
NEXT
ALPHAMODE -1
sc()
request_data$ = UCASE$(glb_inapp_product_request())
UNTIL request_data$="TRANSACTION_SUCCESSFUL" OR request_data$="TRANSACTION_FAILED"  //what is the "TRANSACTION_CANCELED" text?

IF request_data$ = "TRANSACTION_SUCCESSFUL" THEN compra_ok()  //yeah, it works!!! muahahaha!!!!

FOR p=0 TO 10*60   //just a delay
cuadrao();main(3);ALPHAMODE -1
ys=120*appzoom;n=1
DRAWSPRITE 3,(xres-(640*appzoom))/2,ys
IF request_data$ = "TRANSACTION_SUCCESSFUL"
cprint("PURCHASE SUCESSFUL",xres/2,ys+(20*appzoom));INC ys,100*appzoom
free=0
ELSEIF request_data$ = "TRANSACTION_FAILED"
cprint("PURCHASE FAILED",xres/2,ys+(20*appzoom));INC ys,100*appzoom
ENDIF

FOR i = 0 TO item_count - 1 STEP 4
IF item$[i]="glowingsky.full" AND free=0
//
ELSE
IF n=z
ALPHAMODE -1
ELSE
ALPHAMODE -.5
ENDIF
INC n
DRAWSPRITE 8,(xres-boton)/2,ys
PRINT UCASE$(item$[i+1]),(xres-boton)/2+(20*appzoom),ys+(40*appzoom),1
PRINT item$[i+2],((xres-boton)/2)+boton-(24*appzoom)-LEN(item$[i+2],1),ys+(44*appzoom),1
INC ys,120*appzoom
ENDIF
NEXT
ALPHAMODE -1
IF MOUSEAXIS(3)<>0 THEN BREAK
sc()
NEXT
cargas()

ENDFUNCTION
Title: Re: iOS InApp Purchases
Post by: matchy on 2011-Sep-05
 :good:  :coke:
Title: Re: iOS InApp Purchases
Post by: Kitty Hello on 2011-Sep-19
I earned my first $0.49 from in app purchases.
Thanks so much!
Title: Re: iOS InApp Purchases
Post by: matchy on 2011-Sep-19
Too early to get thirsty?
Title: Re: iOS InApp Purchases
Post by: Kitty Hello on 2011-Sep-20
Bobble Heads - the sale was on day 1.
Title: Re: iOS InApp Purchases
Post by: Omadan on 2011-Dec-01
Can we say that IAP is working properly now? I intend on using it for my next App.

Thanks Ampos
Title: Re: iOS InApp Purchases
Post by: ampos on 2011-Dec-02
Just tested in iOS 5.0 and it works.

Damm, I bought my own app!  :doubt:
Title: Re: iOS InApp Purchases
Post by: Kitty Hello on 2011-Dec-02
buy your own pushes the sales -> app store ranking ;)
Title: Re: iOS InApp Purchases
Post by: ampos on 2012-Feb-06
Additional info:

-iOS InApp purchases has been cracked: you can buy "for free". Although some programs fails, our InApp system is vulnerable: you can buy any InApp purchase.

-We can detect if the iOS has the InApp hack installed: before going to the real InApp function, just try a fake purchase. If it returned "true", the iOS InApp system is hacked. I returned a msg that says "Sorry, InApp purchases can not be processed. Your device is hacked".

-In the last loop, the user has 2 options, PURCHASE and CANCEL. Once he presses PURCHASE, iOS will return to our app PURCHASE SUCESFULL or FAILED. But we can not detect if the user CANCELled it, so our app will be in an infinite loop waiting for the SUSC or FAIL msg. What I am doing is counting mouse clicks (screen touchs) on this loop: if the user cancelled the purchase, he will be waiting for the app to return to main game/loop. As the app it is not returning, he will kick (touch!) the screen saying "hey, what are you waiting for?". If the mouse counter reaches 2 or 3, I assume it was cancelled (also, not tested right now, but I think also that GL apps can not detect screen touchs while a iOS (purchase) window is open.)
Title: Re: iOS InApp Purchases
Post by: spacefractal on 2012-Feb-06
There was workaround snippet code how to do that to detect those cheaters.

It's proterty got trashed by the backup. Would been nice to update the first post which checking that too.

Title: Re: iOS InApp Purchases
Post by: ampos on 2012-Feb-11
The file InApp.mm has been modified by Michael Werren, and it now works with user cancelled purchases.

Also I have modified the GLBasic code to support detection of cracked InApp routines.

NOTE: In iTunes Connect, when you are ready to sent your app to review, on the page where you upload the graphics, at the bottom, there is a paragraph titled "In App purchases". Edit it and enable the InApp purchases that you want Apple's review team to review, or your app will not have InApp purchases availables.
Title: Re: iOS InApp Purchases
Post by: spicypixel on 2012-Feb-11
Is the code for this in the very first post Ampos or has it been replaced with the backup, just checking to ensure I have everything I need before implementing, thank you :)
Title: Re: iOS InApp Purchases
Post by: trucidare on 2012-Feb-11
Could anyone add a simple call for write permissions in /tmp - if this works the device is jailbroken
Title: Re: iOS InApp Purchases
Post by: ampos on 2012-Feb-11
Quote from: spicypixel on 2012-Feb-11
Is the code for this in the very first post Ampos or has it been replaced with the backup, just checking to ensure I have everything I need before implementing, thank you :)

Yes, it has latest & working code and files.

QuoteCould anyone add a simple call for write permissions in /tmp - if this works the device is jailbroken

A Jailbroken device is not a "pirate" device. In fact, JB is great (I have installed on my iPhone a hack to has cards as WebOS)
Title: Re: iOS InApp Purchases
Post by: spacefractal on 2012-Feb-11
But that could prevent GameCenter cheating and such ting. example I don't want users  to use GameCenter for JailBroken device at all, which is simply just because its too easy to cheat the system Recently you can unlock archivements (as well hiscore) you want. Cheats like that is simply something coword when people does that.

The same for InApp purchases for hacked devices, which of course piracy, so nice that thing can been stopped (until the app got fully cracked of course, even I do some drm thing in my game as well).
Title: Re: iOS InApp Purchases
Post by: Kitty Hello on 2012-Feb-14
Quote from: ampos on 2012-Feb-11
A Jailbroken device is not a "pirate" device. In fact, JB is great (I have installed on my iPhone a hack to has cards as WebOS)
Got a link to that extension? Also, how's the battery use after applying this?