1) I've been saving them to the ini and sadly it can be hacked relatively easily, but that said the vast majority of people don't as it hasn't affected my game much from what I can tell.
2) I use coins and have had no issues
3) No clue :)
Printable View
1) I've been saving them to the ini and sadly it can be hacked relatively easily, but that said the vast majority of people don't as it hasn't affected my game much from what I can tell.
2) I use coins and have had no issues
3) No clue :)
Ok, thanks.
1. An INI is a text file, so I guess if you have access to the file (on a jailbroken device), it can be fairly modified
2. No idea
3. It should work (never tested), I do not see any specific reason for it not to
To protect your ini data you could generate a random key at the beginning that follows some sort of rules, or have a list of pregenerated keys that it checks when it starts up.
Then use that key and a salt to hash the data (like number of coins) and then check the values at the start of the app.
This would prevent users from just setting their own values for coins and unlockables, but it wouldn't stop them from just copying the data file from another user that has purchased everything.
Also this wouldn't protect against memory modification, but it should stop script kiddies.
If there was a way to retrieve a unique ID from the iOS device that could help with security, but at the end of the day if someone wants to "steal" your virtual items bad enough they'll find a way.
I often worry about people messing with the INI through iPhone explorer on Mac, since you can edit parts of apps in there. Remember how people "unlocked" the unfinished iPad support in the Facebook app by editing the info.plist? It would be like that. Again though, pirates gonna pirate...
Someone will most certainly mess with your ini if it's there. If you have a way to detect when that happens you could just shut off online features like highscores.
I tend to just obfuscate things in the INI so it's not easily understood. Like "Unlocked true version = 0" would be easy for somebody to mess with but simple things like 36=0 or whatever, not so much. I think for protecting IAPs though .arr array files with numbered entries, much harder for a person to understand.
All someone would have to do is copy the save file from someone who bought everything, and you have yourself a crack.
I'm not really worried about it though. If the device is jailbroken then they prolly pirated the app too, and they're unlikely to purchase it to begin with.
I would however protect the online scores. It's a pain to have hacked scores because that discourages other players to try.
Even moreso if your game has online multiplayer.
You could do some simple math to make the coin counts look weird, and if the math doesn't give a true result such as someone randomly changed the string to several numbers you could give a coin error message, but somehow, somewhere, a valid buyer will get pissed off because of a rare glitch or something.
Yes glitches in the protection scheme is the only issue I can foresee with that method. Just do a lot of testing I suppose.
I think using hashes would be the best method of protecting the data. Just load the data into memory on the first frame of the app and do your security checks there.
Ok, well I think I will build my game using this technique (sub-apps for IAP store), so let's see how it goes. :)
Thanks for the correction, good to know this one.
So regarding this INI vs. Array as a method of storing consumables; I recall that at least in some other runtimes, MMF2 arrays are encrypted by default, so does this add another layer of protection also for iOS IAP implementation? In other words, array would be slightly better than INI as such, and using an array with your own hashing technique on top of the default encryption would already provide quite good protection?
If you're having problems with getting responses to your requests from the App Store for IAP, check your devices Date & Time are correct.
I was having problems waiting for the item's description and price on my old iPod touch 2G.
I Tried running the App Store only to be told there was an error and to check my Date & Time settings were correct.
Checking them in Settings revealed that they were set to the year 1970! Setting the correct Date & Time fixed the problem.
Must have been from when the battery went flat.
Has anyone else ever had problem getting their IAPs approved? I've tried submitting them twice now, with screenshots and all, and they always go to "Developer Action Needed", and the English language (the only language I have) is highlighted, but no advice is given on what's actually wrong with it. I've tried messaging Apple, but they just refer me to some technical note that tells me how to implement IAPs.
I'm kind of at a loss about it at the moment :(
Are you trying to test the IAP? You just need to create them and have them at the "Ready for Submission" stage to be able to test them.
To actually have them approved, you need to submit them along with your binary upload when you are ready to either push your first release onto the App Store, or push a new update to your live App.
I've submitted the IAPs for approval, and I did this before I uploaded the binary, but they were always set at "Waiting for review". Is this state different from "Ready for Submission"? When I tried to submit the binary as well, the IAPs were set to "Developer action needed" once reviewed, and then the app was rejected because the IAPs were not approved.
I've never set my IAPs to be reviewed separately from the game. It's much easier I find if you submit the IAPs along with the actual game.
'Waiting for Review' status is exactly that, it's waiting in a queue to be reviewed. It could be anywhere from a few days to about 2 weeks for games. For submitting IAPs on their own, it might be a bit quicker I'm not sure.
That's what I ended up doing, but it still came back as rejected :(
Had much trouble when trying do use SubApps as an elegant solution for pop-up screens (options and IAP screen). Finally removed them completely. Some SubApp bugs were fixed, but I can't remember anyone found out why they can bring down the framerate sometimes. Handle with care and do much testing. Keep in mind that they can't share files with the main app. So, if the player buys something in the SubApp and you want to store this purchase in a file, you need to pass the data to the main app via global values and save it there!
@Game_Master: a quote from Apple support: "Once an In-App purchase has been rejected, you can not reinstate it. Your next In-App purchase will need to be brand new. For more
information regarding the statues of In-App Purchases, please visit page 144 of the iTunes Connect Developer Guide."
My first game was rejected and this also put the IAP item in rejected state (though nothing was wrong with the item itself, I was just lacking a "Restore" button for IAPs). First the item had the state "Rejected", later it was set to "Developer Action Needed". Finally, I had to set up a new item. Since your IAPs have already been rejected, I'd say you have to to the same :(
I'm not sure if they were officially rejected or not; the only state that they ended up in was "Developer Action Needed". I'll probably do what you said though. Can I use the same names/identifiers for the new IAPs once I delete/re-add them? Thanks!
If an IAP is rejected, you have to delete it and create it again as a new one.
I'm working on the IAP for my game and I have a question or two: When using "Request For Payment" and "On Payment Restored," if I make the product "com.companyname.gamename.iapname" it doesn't work-- nothing happens when I make a purchase (non-consumable, just a "pro" upgrade). But if I make it just "iapname" it works. Does anyone know why? And is that OK?
[1] User Clicks Button------------------------------> Request payment for "iapname" quantity: 1
[2] On payment processed for "iapname"------------> Set PurchasedGlobalValue to 1
Do I need anything more than those two actions? The price is lised in the text on the frame, so there's no need to request that first (unless Apple requires it; do they?).
Also, when I do the Restore it asks if I want to make a purchase but then instantly it comes up with the name/password dialog, then back to the Do You Want To Purchase dialog, then to the You Already Bought This dialog. It eventually does give the user what they want, but all those pop-ups seem wrong and confusing. Here's how I have it:
[1] User Clicks Button----------------------> Restore Transactions
[2] On Payment Restored For iapname------> Set PurchasedGlobalValue to 1
See? Very simple. But it acts weird. Again, please note that it only works with "iapname" not with "com.companyname.gamename.iapname".
That should be fine - I had the same sort of thing, as did a couple others. I think you do need the price on the frame, though I'm not 100% sure, as it does tell you the price when it confirms with the user whether or not they want to buy the IAP.
Rejection warning: only show the price requested from the AppStore, do NOT put it into the text of your app!
Not sure if you have to show the price at all, but I'd do it to be on the safe side. Can't remember an app where it wasn't listed.
Thanks guys. I just checked a game (Peggle) and it does have the price listed on the "buy" button (Buy now for $0.99). JoKa, your two sentences seem to contradict each other. What did you mean?
He meant that you have to request the price when you want it, rather than having it hard coded into your app. Use the request product information action for this, and then once the information is through, set a string object or counter to display the price (you can have a price formatted version, which has the currency, or a version without formatting - use the later if you plan to use counters to display price).
Thanks! I think I have it all set now. I substituted the price text on the button with a string that displays the price gotten from the "Request Information" action.
Again though, it's fine that it all only works with "iapname" not with the full name that includes the bundle identifier (com.companyname.appname)?
Yes, I believe so - that's what worked for me and a couple of other people, too.
Just make sure to have the bundle identifier set correctly in the application properties.
Thanks again!