Community "kickstarter" for a working IAP addon.

So many people have been asking for an IAP add-on. I don’t have an add-on specifically, but more like instructions on how to get it set up in Xcode after you export your game into there to get ready to release it on the App Store. I compiled some old code from @Zoyt and his game Stack-it and another developer, CodeMonsters, who put his code up on GitHub for community use with his game Paper Wars. I had to figure out how to get them both working together for the newer version of Xcode, iOS 8+ and Codea, which is compiled here. This is months of progress wrapped into a nice and neat comment, so hopefully it all makes sense. I’m happy to share it with everyone as I wish I would have had it when I was looking for it!

IAPs in Action from Codea & Xcode!
To see it actually working from a real Codea project, check out my game, Color Troll, on the App Store, at http://www.colortroll.com/download.

IAP Instructions for XCode and Codea
Export your code to Xcode.

Make sure it runs fine in the Simulator or on your device.

With an App Developers license, in iTunes Connect, create your product IDs. You will need to “Archive” it in Xcode and upload it to iTunes Connect (pretty sure you have to get your app uploaded to iTunes Connect in order to add IAPs). It’s good just to have this completed once so you are familiar with archiving the app and seeing it on the iTunes Connect page. Be sure you stick with the guidelines and read over the handbook for which type of product it will be. Read all of this!
Be sure to make note of your app’s BundleID, SKU and Apple ID number as you will need these for the products you create.

Create your IAP products by following Apple’s directions here. Take note of the 10 digit number that corresponds to the product you want to sell. I have three in my game, so I will work with how to do more than one IAP product.

In your project in Xcode, under “Capabilities”, add the “Store Kit” by ticking “In-App-Purchases.”

Should look like this.

Under the “ProjectName/ProjectName/Addon” group on the left-hand side of the default view, create the new group, “ExtraiAP-master”. Insert these files in there. Link

  • DefaultInitializer.h
  • DefaultInitializer.m
  • iAPManager.h
  • iAPManager.m
  • iAPProduct.h
  • iAPProduct.m

In the group, “Extra”, add these two files:[Link above]

  • IAPAddOn.h
  • IAPAddon.m [includes rating function & language differentiation if you want to use it]

Should look like this.

In the “Addons” folder, in the “AppDelegate.mm” file, at the top, add this line of code under the other #imports.

#import "IAPAddOn.h" //ADD THIS FOR IAPs

Then add this line in the @implementation just below that with all the other self.viewController’s.

[self.viewController registerAddon:[IAPAddOn sharedInstance]];

Add to Main.lua class at the very end to create functions from Obj-C to work in Lua.

    function getProductInfo(id,price)
        iapItems[id] = {
           price = price
        }
    end
    
    function productBeingPurchased(id)
        purchasePending = true
    end
    
    function restoredProducts(id)
        setProductPurchased(id)
    end
    
    function productPurchaseFailed()
        purchasePending = true
    end
    
    function productPurchaseSucceeded(id)
        purchasePending = true
        setProductPurchased(id)
    end
    
    function setProductPurchased(id)
        if id == "AppID Name, like com.YourCompany.IAPname" then
    	--code for what happens in game, like adding 50 gold to the total, or whatever purpose the IAP is supposed to do.
        elseif id == "AppID Name, like com.YourCompany.IAPname2" then
    	--what the next IAP does in app.
        end
     end

Add these to the front of the Main.lua setup() function

    iapItems={} --added this for IAP
    registerItem("AppID Name, like com.YourCompany.IAPname")
    registerItem("AppID Name, like com.YourCompany.IAPname2")
	initStore()
    purchasePending = false

Not necessary, but you might want to include an internetConnected Boolean to make sure they are connected to the internet. Something like these functions. I used them for the IAPs and for the current time in UTC for no “time-hacking” on their device.

    function getTime()
        tbl={["headers"]="heading"}
        http.request("https://www.google.com",getHttpData,httpError,tbl)
    end
    
    function httpError(error)
        --no internet connectivity
        internetConnected=false
    end
    
    function getHttpData(data,status,headers)
        --internet is connected now
        internetConnected=true
    end

I will try and make a tutorial video soon to make it easier to follow along, if there is enough demand for it. If there is anything else that needs to be added or changed, as I did this from my detailed notes I took through the whole process and then copied it over, let me know. As long as I wrote them down correctly, it should work just fine. Good luck! And happy coding!

This does not include the exact code for a “restore purchase” option, but the function is included and could be implemented easily.

oh this looks wonderful… can’t wait to try it! A BIG thank you for these clear instructions @pelicantacos!

I already have some questions :slight_smile:

  1. Where exactly do you put the 10 digit code given by Apple when you create your IAP?

  2. When following the instructions and trying to run the app, I get an error in codea’s console on my ipad: “attempt to call a nil value (global ‘registrationItem’)”. I did copy the files you provided by draging and droping them to xcode’s extra folders (and by choosing “add as reference” first, then “add as group”). Any idea what could be wrong, in your experience?

@Rodolphe, the 10 digit IAP code isn’t used in the code itself, just hang on to it and know where to find it in case you do, along with the IAP official name, like “com.pelicantacos.bagOfGold,” or something similar (the backwards domain naming system Apple recommends when you create your IAPs).

So is there error in Xcode or in Codea? I don’t have “registrationItem” in the code, only “registerItem.” Is that what you meant?

@pelicantacos Oops, indeed, it’s registerItem(). The error is in Codea and also happens with initStore()

My folders look like this: https://dl.dropboxusercontent.com/u/73950/Capture%20d%E2%80%99%C3%A9cran%202016-02-09%20%C3%A0%2008.19.29.png

Thanks for the precisions on the IAP code!

It’s odd, the error suggest IAPAddon.m and IAPAddon.h aren’t even copied to the folder… strange…

Weird. If you right click and check the folder location of these two files, are they in the right spot in Finder? Can you throw the error in Codea here please? Thanks!

Yes, all the files actually are at their supposed place in Finder. In codea, I simply get “attempt to call a nil value(global ‘registerItem’)”.

iapItems={} --added this for IAP
registerItem("com.Boucastral.mode2")
initStore()
purchasePending = false

should be placed right after setup(), right?

and the other functions: getProductInfo(), productBeingPurchased(), restoredProducts(), productPurchaseFailed(), productPurchaseSucceed(), and setProductPurchased() should go at the very end of main.lua, outside of the setup() function?

Thanks!

Yeah, hmmm. So the “registerItem()” function is created in Xcode in Obj-C and registered there to run in Lua via calling it in Codea’s code in Xcode. You aren’t running the app now in Codea on the iPad are you? You need to make sure you are using Cmd+Shft+K to clean the code and then Cmd+R to run thru the Simulator or installing it on the device. Once you start messing with IAPs, you can’t work in Codea any more. Does that make sense?

It makes a lot of sense, thanks! I’m running it on my iphone from xcode (Cmd+R), what I meant is that I get the error on the iphone, not in xcode. I also tried cleaning the project, but no success yet. I’ll wait a bit and try again later…

Ok :frowning: Sorry we couldn’t figure it out! I will poke around more tomorrow to see if I can find an error in my instructions.

sure no worries, I really appreciate your help. I’m sure it’s something stupid on my part. I’ll let it rest, it sometimes help :slight_smile:

(fixed)

@pelicantacos So, I now hope it works… And I, of course, have another bunch of questions, among them:

  1. How do I retrieve the price of the app to display it in my little store? As I’m guessing the price is different from one country to another… Should I get it with getProductInfo(id,price)? If so, is “id” the IAP name?, what about “price”?

  2. more generally, let’s say a user presses on the “buy” button, which functions should be invoked?

  3. Do I need to submit my app including IAPs to Apple before I can test it?

Ok, I think I figured it out. I left a step out. In “AppDelegate.mm” in the “Addons” foldder, add

#import "IAPAddOn.h" //ADD THIS FOR IAPs

at the top. I forgot to add that reference to call recognize the .h files there. Let me know if this helps. I’ve added that step in the original instructions now so to cover this issue.

Cool i’ll try it hopefully in an hour or so. Thanks a lot!

It still didn’t work, until I added : “[self.viewController registerAddon:[IAPAddOn sharedInstance]];” in “AppDelegate.mm”

Was that the right thing to do?

@cmingo I just updated the links as I didn’t realize I had moved the files a while ago. Hopefully those are the right files I referred to a year ago (It’s been a while :slight_smile: )

Yes, I forgot to add that as well :slight_smile: Good catch! It’s been about 6 months since I did all the IAP stuff so I may have (and did) forget a few things. Thanks for the help in getting it right!

As for your questions,

  1. I made a table at the beginning of the app that had all the prices and languages that tested which language the region of the device was in and therefore changed it accordingly. I programmed it in Obj-c and then pushed the variables over in Lua to figure it out in Codea. My table looked like this in Lua

    listOfCountries={
    [1]={“United States”,“USD”,“US”,english,“$0.99”,“$2.99”,“$9.99”},
    [2]={“Canada”,“CAD”,“CA”,english,“$1.39”,“$3.99”,“$13.99”},
    [3]={“Mexico”,“MXN”,“MX”,spanish,“$17.00”,“$49.00”,“$169.00”},
    [4]={“Australia”,“AUD”,“AU”,english,“$1.49”,“$4.49”,“$14.99”},
    [5]={“New Zealand”,“NZD”,“NZ”,english,“$1.49”,“$4.49”,“$14.99”},
    [6]={“Japan”,“JPY”,“JP”,japanese,“¥120”,“¥360”,“¥1,200”},
    [7]={“China”,“CNY”,“CN”,chinese,“¥6.00”,“¥18.00”,“¥68.00”},
    [8]={“Singapore”,“SGD”,“SG”,english,“S$1.48”,“S$4.48”,“S$14.98”},
    [9]={“Hong Kong”,“HKD”,“HK”,chinese,“HK$8.00”,“HK$23.00”,“HK$78.00”},
    [10]={“Taiwan”,“TWD”,“TW”,chinese,“NT$30”,“NT$90”,“NT$300”},
    [11]={“India”,“INR”,“IN”,hindi,“Rs60”,“Rs190”,“Rs620”},
    [12]={“Russia”,“RUB”,“RU”,russian,“75p.”,“229p.”,“749p.”}, --“p.” goes after the amount
    [13]={“South Africa”,“ZAR”,“ZA”,english,“R18.99”,“R59.99”,“R199.99”},
    [14]={“Saudi Arabia”,“SAR”,“SA”,arabic,“SR3.69”,“SR10.99”,“SR36.99”},
    [15]={“United Arab Emirates”,“AED”,“AE”,arabic,“AED3.69”,“AED10.99”,“AED36.99”},
    [16]={“United Kingdom”,“GBP”,“GB”,english,“£0.79”,“£2.29”,“£7.99”},
    [17]={“Sweden”,“SEK”,“SE”,swedish,“10,00kr”,“30,00kr”,“109,000kr”}, --“kr” goes after amount
    [18]={“Switzerland”,“CHF”,“CH”,french,“CHF1.00”,“CHF3.00”,“CHF10.00”},
    [19]={“Norway”,“NOK”,“NO”,norwegian,“9,00kr”,“29,00kr”,“95,00kr”},
    [20]={“Luxembourg”,“EUR”,“LU”,german,“0,99€”,“2,99€”,“9,99€”},
    [21]={“Malta”,“EUR”,“MT”,english,“0,99€”,“2,99€”,“9,99€”},
    [22]={“Germany”,“EUR”,“DE”,german,“0,99€”,“2,99€”,“9,99€”},
    [23]={“France”,“EUR”,“FR”,french,“0,99€”,“2,99€”,“9,99€”},
    [24]={“Austria”,“EUR”,“AT”,german,“0,99€”,“2,99€”,“9,99€”},
    [25]={“Belgium”,“EUR”,“BE”,german,“0,99€”,“2,99€”,“9,99€”},
    [26]={“Netherlands”,“EUR”,“NL”,dutch,“0,99€”,“2,99€”,“9,99€”},
    [27]={“Spain”,“EUR”,“ES”,spanish,“0,99€”,“2,99€”,“9,99€”},
    [28]={“Ireland”,“EUR”,“IE”,english,“0,99€”,“2,99€”,“9,99€”},
    [29]={“Portugal”,“EUR”,“PT”,portuguese,“0,99€”,“2,99€”,“9,99€”},
    [30]={“Finland”,“EUR”,“FI”,swedish,“0,99€”,“2,99€”,“9,99€”}
    }

You already have the code buried in my Obj-c as I left it in there. The Lua variable is called “countryCode” and the Obj-c variable is called “countryCodeStr.” See if you can figure it out–seems like you know more Obj-c than I do :slight_smile:

  1. The purchaseItem() function and then in that function, add your code of what you want it to do if it comes back true that everything went through successful.

  2. Yes, you will create “dummy” accounts that allow you to buy whatever you want in your app. I created several email accounts, pelicantacos+ca@… pelicantacos+uk@… and so forth to test the countries.