iOS In App Purchase with Rails Backend - ios

I'm having some confusions when creating in app purchase strategy for my iOS app. Some background info below;
I have an iOS app and a web app which both will work in subscription model. The backend has been developed in Ruby on Rails.
Currently I'm trying to develop the iOS auto-renewal in app purchase. I came across couple of gems which helps to verify in app purchase receipts (e.g Venice). I get that the whole point of verifying the receipts from the backend rather then the client is to make it secure and to be able to keep a copy of the receipt in your own server.
I can foresee a huge problem as explained below;
A user can create an account using the iOS app and subscribe to the service by paying X dollars monthly using x#x.com apple id. By doing this I will have the record of this user in my backend including the expiry date of his subscription which will enable for me to track if he renewed his subscription or not. The problem arises when this user logs out from the app and creates another user. Since his apple id is still x#x.com and as account email address or id doesn't matter at all when making a purchase from apple, the expiry date will still be a month ahead since he just subscribed with his previous account the new user will be identified as an already paid customer. Boom! now his friend can login with this account using the web app and enjoy it without paying a quid.
If this makes sense for you, there must be a solution for this hack. I know that Netflix uses Apple's IAP, Spotify used for a very long time.
Also gems like Venice, they don't put a thorough documentation on their github page therefore I don't know if this problem is solved by them out of the box. Just wanted to check with you guys and I'm sure many of you thought about this.

If you're attributing the auto-renewing purchase to a user in your database you will also want to attribute the original_transaction_id that is found in the receipt. Store this ID with the expires_date and ignore or error any receipts containing the same original_transaction_id the API receives that are already attributed to a different user in the database.
The original_transaction_id will never change for the iTunes user, even if they unsubscribe and re-subscribe at a later date it will remain the same. It will also remain the same if they upgrade/downgrade the duration of the subscription when the product IDs are of the same subscription family.
If you're looking for an alternative to Venice take a look at the itunes_receipt_validator gem (full disclosure: I am the author). It validates the signatures and decodes of both the deprecated transaction receipts and the newer grand unified receipts locally without connecting to Apple's API, but also provides the functionality to retrieve the updated receipt and receipt info from the Apple API.

Related

Validate iOS auto-renewable subscriptions from multiple apps

I work for a game developing company which releases at least one game a month. For our true fans we want to start providing a subscription to our games, so they can play all our games (on any platform) without constantly having to buy them.
The idea for iOS is to use the in-app auto-renewable subscription. This results into a receipt which we store in our backend. The backend can validate this receipt and provide the apps with information about the subscription of the user.
This system will solve a lot of problems: You can take the subscription in 1 game, and play all the games as well, on any device you like.
But now we come to the problem: After a month the receipt is not valid anymore, and we need to check in the iTunes store to see if the user still has a valid subscription.
My first idea was to use the "latest_receipt_info" field, to get the latest receipt and validate this. But according the documentation this feature should only be used for iOS 6 receipts:
"Only returned for iOS 6 style transaction receipts for auto-renewable
subscriptions."
source:
https://developer.apple.com/library/content/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html#//apple_ref/doc/uid/TP40010573-
Even though I can actually still use this field with my brandnew iOS 10 receipt, I don't think it's smart to use it since it's deprecated.
(another source telling you shouldn't use it anymore: https://forums.developer.apple.com/message/156580#156580)
The advised solution of apple is to implement a SKPaymentTransactionObserver in the app. This will retrieve the latest receipt when it's available, and send this to the backend. Even though this is far from ideal, this could work... however:
This means the app has to be active to retrieve the latest receipt. And in our case it's very well possible a user takes a subscription in app1, and after a couple of days downloads app2, 3 and 4, but never uses app1 again. So in this case the latest receipt will never be fetched (because only the observer of app1 can access the receipt)
To fix this problem we should be able to fetch the receipts from this subscription from any app in our subscription group. But according the documentation on the apple site (https://developer.apple.com/app-store/subscriptions/ ) you can only access a subscription from 1 app, and you have to do the multiple app thing yourself:
You can offer auto-renewable
subscriptions to access multiple apps in your portfolio. Each app must
be approved to use auto-renewable in-app purchases and must be
published under the same developer name on the App Store.
In iTunes Connect, you’ll need to set up separate and equivalent
auto-renewable in-app purchases in each app offered in the multi-app
subscription so that users can subscribe from any app. To avoid users
paying multiple times for the same offering, you are responsible for
verifying that they are subscribers in one of the apps before showing
any subscription options. To do this, consider maintaining an account
management system in which users create an account with your business
to sign in to each app.
So is there any way to do what we want, without forcing the user to go back to the app he used to purchase the subscription every month?
On the last WWDC we went to StoreKit labs and personally asked StoreKit evangelist about this. We were told that the 'latest_receipt_info' field return by iTunes validateReceipt endpoint is exactly what we are suppose to use in order to check if the subscription was renewed or not.
This is not going to be deprecated in the near future but they do have plans for adding some server-to-server communication that solve few of the problems we ran into:
Your server will be able to get notification from Apple regarding any subscription renewal, cancellation, downgrades etc.
In the latest_receipt_info returned by the validateReceipt endpoint few fields will be added, providing information like whether the subscription will be renewed after current one is expired, whether there was a problem charging the user's credit card etc.
Sources:
WWDC 2017 Session 303 - What's new in StoreKit
WWDC 2017 Session 305 - Advanced StoreKit

How to synchronize/verify in-app recurring subscriptions with a web server (cross platform subscription)

We run a SAAS Web app and are going to be launching our app in Apple’s app store (up to now we’ve had a mobile Web app).
We want to offer the ability to purchase a subscription in app due to the ease of use for our customers. No problem, we know how to do that.
The question we have is whether there is an easy way to keep our web app's db updated with the user’s current subscription status so if they access our Web app we know whether their subscription is valid.
Ideally it would be great if Apple offered a web hook option where they would post an update to a url on our server. From what I've read this isn't an option.
We can always post the data to our server from the iPhone app when the user logs in, but if the user doesn’t log in on the iPhone for a while the subscription status recorded on our server will be out of date.
How are other people handling this? Are we missing something?
Update:
The closest I've found is this thread: https://forums.developer.apple.com/message/70707#70707
The app gets a receipt the first time it buys a subscription or
restores a subscription. The app can send that original receipt to
anyone's server. Anyone's server can then use that orignal receipt to
verify the current subscrition anytime it wants. You can't do that
with a non-renewing subscription but with a non-renewing subscription
the user must purchase the extension from the iOS device each time
period.
Followed up with this:
https://hetzel.net/2011-04-01/server-side-auto-renewable-subscription-receipt-verification/
And from Apple it sounds like they definitely do not make any provisions on their end for synchronization:
Cross-Platform Considerations
Product identifiers are associated with a single app. Apps that have
both an iOS and OS X version have separate products with separate
product identifiers on each platform. You could let users who have a
subscription in an iOS app access the content from an OS X app (or
vice versa), but implementing that functionality is your
responsibility. You would need some system for identifying users and
keeping track of what content they’ve subscribed to, similar to what
you would implement for an app that uses non-renewable subscriptions.
Late to the party, but I think this is a relevant reply to this question:
https://stackoverflow.com/a/47537279/543423
Hopefully this is helpful to someone :)

How to implement a licensing mechanism when purchasing an App Store application if the license system is on our own server?

I am looking to start selling an app on the Apple app store however currently the app uses our own servers to generate a license to the customer once they have purchased it. How can our existing licensing system which uses our own servers be implemented if a customer purchases the app from the App Store instead?
The application license will be a yearly renewable one. Therefore, so far, from what I have read, the app on the App Store could just come with an auto-renewal option (opt-out of course) so that would take care of the subscription cycle but how can our own server issue the customer the one year license which they could then renew from iTunes using the auto-renew function of the App Store?
I am sorry if this is not clear but it would go like this:
Customer downloads application from app store with a one year auto
renewal subscription.
Customer pays.
The app store verifies the
payment.
Once payment is verified it contacts our server to create a
license for that purchase and for one year.
That license is sent back
from our server to the purchased app to unlock the subscription.
Please correct me if my understanding on how this works is wrong but if anyone can point me in the right direction or give examples of how an application on the app store can successfully issue licenses from their own server then I would be very grateful.
As an example, look at "Aviation Exam". They let you buy subscriptions on-device as in-app purchases, or on their own website. In each case the details are synced to a user's account on their own server, so the same exam can be used from any device.
Look at the Apple documentation for how in-app purchase subscriptions work on iOS. Then your app can send details of a purchase to your servers, and download further information.
Edit; after discussion in comments:
If you want payment to go via Apple then it has to be via App Purchase or In-App Purchase. In-App Purchase specifically supports the idea of buying a subscription for a limited time. This is explained at the second link above.
If you want the user to create an account on your server you can either have a page in the app for them to input their details, or you can bring up a web page served from your website. Either way, the info can go to your server and it can create an account.
The key thing is, if payment went via Apple then inside the app is the only place you know this. The app can send this info to your server. You need some common identifier (i.e. a user-name) that is known to your server and to your user, then the user keys it in to your app and it can all be matched up.
There is nothing complicated here, to a decent software developer. All they need is an existence proof such as I gave at the top, and they can figure out how to link the info together.
Edit 2
Some tutorials for in-app purchase listed at: In-App purchase server model
Lots of low-level detail at: Verify receipt for in App purchase
If you prefer to handle payment yourself, not via Apple, then the situation is very different. Now, your own systems have to keep track of what has been bought, when subscriptions run out, etc. To begin with, the app won't know this at all. However, once you identify the user by having them enter credentials (username/password), you can fetch all the details from your back-end system to the app and proceed as above. Again, this is all visible in the example I gave at the beginning, which supports both Apple and non-Apple payments.
One thing to note: if you handle payment yourself then Apple isn't getting its 30% cut, which is the usual App Store commission, so they may not like this. The guidelines say:
11.1 Apps that unlock or enable additional features or functionality with mechanisms other than the App Store will be rejected
11.13 Apps that link to external mechanisms for purchases or subscriptions to be used in the App, such as a "buy" button that goes to a web site to purchase a digital book, will be rejected
That's pretty clear-cut, but since there are apps that rely on subscriptions or content purchased elsewhere, they don't seem to follow these rules in every case. Even the Amazon Kindle app was allowed back, once they took the 'buy' button off.

iOS In-App purchase subscriptions integration with a third party system

I need to build an app for a system, which already has a subscription on its website. It looks like Apple doesn't allow to use any own subscriptions and forces to integrate any app with iOS in-app subscriptions.
Is it any way to integrate two subscription systems? The main problem is that users can manage iOS subscriptions via iTunes and I can't find whether it's possible to get information about this and to stop subscription in the existing system if it's stopped via iTunes.
So is it possible to get notifications about unsubscribed iTunes users?
Using third party subscriptions
First off, it is possible to support an existing subscription system in your app, but it must be in addition to the App Store subscriptions. Also you have to be very careful about the UI you use. You can't prompt users to bypass the App Store and purchase through your server, but you can offer existing subscribers the ability to sign in with credentials they may have previously obtained through your website.
That said, Apple can be fairly capricious in their rulings on what is and isn't allowed in the App Store. I have worked on apps that have done this sort of thing, but they have been for fairly well known magazine publications. There's no guarantee that they will allow it for everyone.
Detecting unsubscribed App Store subscriptions
As for using App Store subscriptions, when a user purchases a subscription in your app, they will receive a receipt in the SKPaymentTransaction object. This receipt should be posted to your backend server to make sure it is valid before you give the user access to anything. See the In-App Purchase Programming Guide for more details.
When you setup a subscription type, you specify how long that subscription lasts. So if you log the transaction date in the SKPaymentTransaction when you receive a receipt, you can determine exactly when that subscription should expire by adding the duration of the subscription to the transaction date.
If it's an auto-renewing subscription, you will receive a new receipt when the subscription is renewed. So once you have validated that with your backend server, you can update your expiry date based on the new transaction date. If you don't receive a new receipt before the first one expires, it's likely the user has cancelled their subscription.
On the backend, your server can also tell when a particular subscription will expire based on the response from the verification server. First there is the status code which will tell you whether the subscription has already expired, but there is also an expiry date returned in the decoded receipt which will tell you when it is expected to expire if it hasn't already.
For more details, see the Auto-Renewable Subscriptions documentation.
Testing auto-renewing subscriptions
It's worth noting that when you are testing auto-renewing subscriptions in the App Store sandbox environment, the length of the various subscription types is dramatically shortened to make it easier to test. For example a 1 week subscription lasts only 3 minutes in the sandbox environment. You can see the full list of times in the iTunes Connect Developer Guide.
So you want the people that have bought the service from the website to be able to use the app, exactly like if they had purchased it from in App Purchases and in App Purchases people to be able to join the service just like people that joined through the site? As far as I know, Apple doesn't allow you to pay through other services as you said, but let's say someone buys the service from the app. What should happen would be that the money will be transferred to the company. Then after the payment you should include some code doing what the site does after a new person has payed for the service, so create his account as a paid account. Then, the app should also have a login screen where the registered users (no matter where they registered from) will be able to login into the app and use the service. Now the problem is indeed that if the subscription is stopped through iTunes you would never know, though a way around this would be to make a check in the server of this company which should monitor the income coming from one account. Then if this user has stopped paying (or stopped the subscription) you would be able to stop the service from the app. And you should recheck the server for payment after the duration of the subscription has passed, let's say a weekly subscription should be checked every week. (Sorry I would do this a comment but I haven't got enough reputation for this)

Accessing StoreKit receipts directly from a server

I'm building an iOS app, which provides a service which our website already provides. It's a subscription based service, where all features are enabled when you're subscribed. To get people to sign up for regular payments on the app, it seems like I'll have to go through Apple's in app purchasing API, with auto-renewing subscriptions. That's fine, but the problem is the service users will purchase through the app must also be available on the site. But reading through walkthroughs and the developer guide, it looks like the only way to process transactions is through the app itself, which then can be set up to pass the info to the server. But then I'm imagining this scenario:
User purchases a subscription on the iOS app, goes back and forth between using the site and the iOS app. On the day the user is to be charged, and the days after, they're using just the website, for whatever reason. The server doesn't know they've been billed though, and so features are disabled. In order for the server to find out the user has been billed by Apple, the user has to open the app on their iphone or ipad and sync it with both Apple and my server.
Is there any way for my server to ping Apple directly and get information about the purchases made for my app for a given user? I haven't been able to find anything; the two suggested layouts, with or without server, both use the iOS app as the sole communicator with Apple, aside from having the server verify that information is valid. If it's not possible for the server to get this information first hand, what other possible solution could there be?
Try to not use Apple's built in payment system, and risk getting rejected (with the app duplicating a service that's been available for years online, do we no longer have to use their in app purchasing system anyway?)
If a user is paying through Apple, have the server give them a generous buffer between expected payment dates and when features are disabled (makes the problem happen less frequently but doesn't solve it)
When their account seems expired to the server but it doesn't expect that, email the user a message saying they have to open the app or else their account will not be credited for time purchased (seems like a strange and not really great thing to have to ask a user to do in order to use the service)
This is about all I've been able to think up so far. Anyone have any advice on these solutions, or know of others, or know who I could talk to to try and figure this out?
Yes, you can check on the status of a user's account from your server. There are a few caveats:
First and foremost, Auto-Renewing Subscriptions are reserved for periodicals such as magazines and newspapers. If your app doesn't resemble those, Apple may reject it (as they did mine) and request that you use Non-Renewing Subscriptions (read: Manually-Renewing Subscriptions).
Second: This scenario would require you to store all receipts that you receive on the app, on your server.
Finally: I don't know how your username/password system works, but the user would have to login with the same credentials on your app as they do on your website.
Here's how you check the status of a user's account: Store at least one receipt per user on your server. When you want to check the status, follow Apple's procedure for Verifying App Store Receipts. Send them that one receipt and they'll respond with the latest receipt and the expiration date. Now you'll know, at any given moment, if a person's account is current or not.

Resources