iOS StoreKit multiple auto subscriptions - swift

is it possible to have multiple auto subscriptions like this:
All - every feature is unlocked -> 4.99$ per week
Feature 1 - Only feature 1 is unlocked -> 2.99$ per week
Feature 2 - Only feature 2 is unlocked -> 2.99$ per week
Feature 3 - only feature 3 is unlocked -> 2.99$ per week
PS. Price of every auto subcription is just for reference.
Users can auto subscribe to all features individually, but its cheaper to subscribe to All.
So, it is possible to subscribe to Feature 1, Feature 2, Feature 3 seperately and should not be possible to switch from subscribed feature to other feature not paying 2.99 as user could try out all features just by paying for one.
If I were to create every auto subscription in its own group then user would probably get billed for all subsriptions if user subcribed to features individually and later decided to go All route. All subcription should cancel out billing of other Features.
If I were to create every subcription inside one group then user could switch Feature subscriptions paying only 2.99?
I can't seem to solve this.

Related

How can i add premium features in my app by in app purchases?

Let's say I have a list with 5 list items and I only want to offer 3 of those as free and I want to offer the rest as premium content. Free items are adding a note , adding 3 todos and bookmarks and premium features are like no ads and audio saving in my note app.
So my question is basically how can i add This feature like if you pay few dollars the user is allowed to use those premium feature or else watch 2 ads for 24hrs of free premium services i went through a ton of youtube video they are just telling me how to integrate in app purchases ok thats right but how can i add this premium features to that so that it will unlock once the payment is done. Simply adding text is not enough i guess
You can check feature availability for free user and save how events user can perform, for example:
if (Purchase.isCompleted() || Preferences.featureLimitNotCharged()) {
doAction();
} else {
showPurchaseDialog();
}
If user watched an ads, you erase the limits from settings and user can be perform actions again, for example:
Preferences.eraseFeatureLimit();
Next time when user recharged feature limit, you show purchase dialog again.

Prevent race-condition in RESTful api in certain scenario

I'm currently developing an online course system where students can choose any course and enroll to it. The course will be held one-to-one principle so student will choose a certain date for the course and on that date, there will be an online video meeting with the instructor. Only one instructor and one student for each course session.
Typical use-case flow is:
Student press "Enroll" button and proceeds to the next page.
On this page, student chooses the course date from the calendar (only from available dates) and proceeds to checkout page.
On checkout page, student enters his/her card details and certain amount charged from student.
A race condition may occur in this scenario (let's say there are only 2 users and 1 instructor):
User1 chooses date from the calendar and proceeds to the checkout page.
Meanwhile User2 also chooses exactly same date and proceeds to checkout page.
User2 enters card details faster that User1 and reserves that date.
User1 enters card details and system charges both students and BINGO (there are two students for the same date).
I don't want to check date availability before payment so I think It'll give a bad user experience so the User must go to the previous step again and choose another date. Even this could happen infinitely :)
Any ideas will be welcomed.
Also, I can change the current enrollment flow to protect security.
The reference you want to review is Pat Helland 2007: Memories, Guesses and Apologies
You've got a distributed system, and remote clients are looking at local copies of your data that may be out of date. So your protocol needs to recognize that you will be receiving messages about decisions based on stale data, and have explicit handling for the contingency that the desired outcome of the decision is not currently available.
The REST part is "just" providing the correct affordances for your protocol.
One possible change to your protocol that may help is to introduce the idea of a provisional hold; Alice has a provisional hold on the time slot, and therefore when Bob asks the slot is unavailable, but it might become available later if Alice declines to exercise the option.
(This doesn't eliminate the race condition, of course, it just moves it around).
A common protocol solution here is overbooking - you accept both claims on the time slot, and then clean up the mess later.
Commercial airlines do this sort of thing all the time; they want to maximize their profit per flight, which means selling more tickets than there are seats on the plane. They can do this, because enough travelers change their plans later that there is an effective surplus.
But sometimes, too many paying customers show up for the same flight, and then the contingency plans come out -- standby passengers are deferred, ticketed customers are offered compensation packages for changing their plans, and so on.
You probably need contingency protocols anyway (what happens if the instructor has to cancel the appointment, for example because of illness); the race condition during booking is just one more contingency protocol to add to the run book.
Having established what the contingency protocol should be, you then have a second question to explore: what parts of that protocol should be automated. If conflicts are rare, it may make sense to escalate the problem to a human being to solve, rather than doing so in code. Sometimes the right answer is for the machine to stay out of the way.
I want to implement double-check mechanism so:
When User1 proceeds to calendar page it will create a persistent connection with the server (SSE or WebSocket). And available dates will be shown on real-time. So when User1 selects any date and proceeds to checkout an event will be published and that date will be marked as BLOCKED until the payment done.
When User1 enters his card details and clicks Pay button the system will check again if that date is really reserved by User1.
If payment is successful this date will be updated from BLOCKED to RESERVED.
BUT taking into account that this is a REST API with React client, all of the endpoints will be visible to anyone. So an attacker could make a simple brute-force to BLOCK all available dates for the course.

How do I distinguish between for consumeable products and for products that aren't consumed?

I used 'com.android.billingclient: billing: 2.0.3'.
How do I distinguish between for consumable products and for products that aren't consumed?
Consumables are approved for purchase with consumeAsync() and non-consumable products are approved for purchase with acknowledgePurchase().
It seems like consumable products and non-consumable products are classified through whether consumeAsync() is called or not.
1. Are there other methods of classification?
(https://developer.android.com/google/play/billing/billing_library_overview#acknowledge/)
2. acknowledgePurchase () is directed to apis for non-consumable products. Shouldn't it be used for consumable products?
I can add a developer paylaod this way:
For consumable products, consumeAsync() takes a ConsumeParams object that includes a developer payload field, as shown in the following example:
BillingClient client = ...
ConsumeResponseListener listener = ...
ConsumeParams consumeParams =
ConsumeParams.newBuilder()
.setPurchaseToken(/* token */)
.setDeveloperPayload(/* payload */)
.build();
client.consumeAsync(consumeParams, listener);
For products that aren't consumed, acknowledgePurchase() takes an AcknowledgePurchaseParams object that includes a developer payload field, as shown in the following example:
BillingClient client = ...
AcknowledgePurchaseResponseListener listener = ...
AcknowledgePurchaseParams acknowledgePurchaseParams =
AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(/* token */)
.setDeveloperPayload(/* payload */)
.build();
client.acknowledgePurchase(acknowledgePurchaseParams, listener);
(https://developer.android.com/google/play/billing/billing_library_overview#attach_a_developer_payload)
3. Do you plan to add management type for consumable and non-consumable products in the future?
4. Could the call be restricted for mistyped functions?
Google Play doesn't have the knowledge of consumable SKUs vs non-consumable SKUs. Only developers have this knowledge.
If you would like users to repeated purchase one SKU (like coins, gems), then you can call consumeAsync() to remove it from user's library. Google Play won't allow users to repurchase a SKU if it is already in his library. Therefore, you have to consume it (remove it from his library).
For some other SKU, such as subscription or ads free, premium content unlock, limited item, if you want users only buy once then don't consume it. Instead, use acknowledgePurchase API. Google Play introduced this as a contract to make sure that you have granted the products to users.
Therefore, I would say keep a catalog of consumable, non-consumable SKUs on your side. And based on the type, call the correct Google's API.
For what I understand so far,
non-consumable product call acknowledgePurchase() is to set the purchase record to acknowledged in Google side, so when u trying to trigger queryPurchase(), it will show the product is purchased with acknowledged (parse the json data to view the data)
consumable product call consumeAsync() is to remove the data in Google side. So when trigger queryPurchase() should be no record for that.
Why consumable product can purchase again?
Because the record ady removed from the record. When trigger purchase again will not return error code 7 (BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED)
both consumeAsync() and acknowledgePurchase() also will set the payment to done. If didn't trigger anyone of them, then it will auto refund after 3 days. Both of the action also work as acknowledge the payment.
So for your question
1. Are there other methods of classification?
Those acknowledged one should be non-consumable product, since consumable product record should be removed after success record to our side. Or if want to classify, maybe can set developer payload for the acknowledgement(can't changed after set)
2. acknowledgePurchase () is directed to apis for non-consumable products. Shouldn't it be used for consumable products?
no, use it separately based on your requirement
The answer maybe incorrect. Just some sharing about it.
welcome to answer my question also related to this, acknowledgement perform at server side
Server side can do something similar to mobile side comsumeAsync() in Google Billing Library?

Removing autorenewable subscriptions from iPhone App

I have an iPhone app that also features autorenewable products as an in-app purchase. The products are subscriptions to our service for up to 1 year in the future. We wanted to remove the whole in-app-purchase and autorenewable product from our app in the next version.
To accomplish this, we removed the signup option inside our app, so no new user should be able to sign up. Now we would like to disable the automatic renewal for all existing users.
How can I accomplish this? Is it sufficient to remove the in-app-products for our app inside iTunes Connect? Do the users get notified about this?
According to Apple (see WWDC 2011 Session 510, In App Purchases for iOS and OS X, at the 48:55 mark), the only things you can do as a developer to prevent subscriptions from auto-renewing are:
Raise the price.
Remove the auto-renewing IAP product from iTunes connect.
In both cases, notification emails are sent to subscribers, though not immediately. The talk says Apple checks 10 days before a (yearly) subscription renewal and sends email at that time. It's not documented anywhere, though, so I'd treat that as an implementation detail.
I've done the latter (removing the product) several times with my own (monthly) apps, and it seems to work as advertised.
One important note: if your app is a Newsstand app, it must have at least one auto-renewing subscription available. If you remove the last one, the app will be removed form the App Store. Users who have already purchased it will still be able to use it, and will be able to download copies from the "previously purchased" section of the app store, but no new copies will show up for purchase in the App Store proper.
It will depend on how you've implemented your system. Do you check receipts (and provide data/service) from your own server, or do it all within the app directly with Apple's servers?
In iTunes Connect you can remove a product from sale, effective immediately or at a future date. I suspect that's enough to stop a renewing subscription. (Remember you can test this with shortened timescales in the Sandbox.) But if not:
If you use your own server to validate receipts, go and give it an incorrect shared secret so that the verification step fails. That means the subscription validity will return as false (although for the 'wrong' reason) so your customers won't be able to renew.
If you do it within the app, generate a new shared secret so the one within your existing structures is incorrect. Then, as above.
If you can, I suggest sending a notification to your current users notifying them of the change, suggesting that they change, and letting them know it will 'fail' in the future but that's ok.

Switching from a paid app to a free app with auto-renewing subscription

I have an app which costs $5. I'd like to change this so that the app is free and that users must purchase an auto-renewing subscription to use it. I know how to implement the auto-renewing subscription, but the problem is dealing with users who have already bought the app for $5; I'd like to continue letting these users use my app without a subscription.
The rub is that for privacy reasons I can't store any identifying information on my server which link an account for my app to a specific person (not even UIDID). What I can do is maintain a separate database table which links UIDIDs to subscription purchase receipts which will allow me to know if a user has a subscription.
So my question is, how can I identify users who got my app when it cost $5? I know there's a way to restore in-app purchase receipts, but is there a way to to retrieve a receipt for the initial purchase of the $5 app which I could store on my server?
The poor man's solution is just to mark all current UIDIDs (i.e. the UIDIDs of people who have paid $5) in my server as paid, but then they would have to buy a subscription if they ever wanted to use my app from a different device.
The previously selected answer is outdated. The new answer is that it is possible today with the new receipts that were standardized this year (2013).
The receipt now has two additional fields: original_application_version and original_purchase_date which can be used to detect when a user purchased and therefore be used to guide logic around what users should get what features.
You can see more about 10 minutes in here: http://devstreaming.apple.com/videos/wwdc/2013/308xex4x6ybggtlw4ztv0sg5btp/308/308-SD.mov?dl=1
or if that link dies here: https://developer.apple.com/wwdc/videos/ and search for Using Receipts to Protect Your Digital Sales.
Chaning your business model like this is not very well supported by the App Store.
Your "poor mans" solution is probably one of the best of a poor set of options.
Another one would be to switch to a new app entirely (just a different bundle ID in practice). Anyone using your old app would have paid, regardless of which device they use. Anyone using the "new" app would need a subscription. Obviously you'd lose any reviews and possibly external links that you currently have.