I have a new iOS App with an auto renewing subscription feature.
I'm using the Mercato lightweight Storekit2 library.
I issue a start to the transaction listener in the AppDelegate didFinishLaunch along with a retrieveProducts(), activeSubscriptions(), and activeSubscriptionsIDs().
It all works, BUT: the validation of an active subscription does not asynchronously complete until well after the initial viewWillAppear().
Therefore it always starts off in non-valid display mode, and premium features are available to select by the time the user starts navigating.
Is there a faster way to get a validation upfront, or failing that, is there a way to post an event that a subscription test has completed, so I can display, then stop some sort of distracting, time wasting animation until validation.
Related
I have a problem with implementing multiple accounts in flutter app.
When the app is first opened, multiple network calls are made to get account related data. Those calls are usually made in initState of each widget using BLoC pattern. After await-ing on those data, UI or some other parts of app is updated.
The problem is, when user tries to switch to another account, app navigates user to the root page, so all the loading of required data for this account would happen again. But since some calls from previous account might still be ongoing and finish only after user switches to another account, I get multiple issues in application, like rendering UI with data that belongs to previous account.
I know I can dispose all those streams, so no UI is updated incorrectly regardless of the response. But, I was wondering if there is a way to kill all the ongoing requests, since app doesn't care about the response after the account is changed. In other words, I need the effect of restarting the app, but without actually restarting it. Is there any way to achieve that?
I have implemented In-App Purchase Auto-Renewable Subscription into my app but I'm not sure if I have done it correctly as the app constantly asks for iTunes login.
In the user case: I am subscribed to monthly payments and my first month is over and expect it to auto-renew.
The flow I have at the moment is as follows...
(in App Delegate) Check receipt is valid
(if receipt IS valid) check all receipts for latest expiration date
(if expired - which seems to be the case after the first month is over) call SKReceiptRefreshRequest to get latest receipts. I have put a count check on this otherwise it gets stuck in a never ending loop.
Do final check to see if latest receipt is in-fact expired.
Is this the correct way to go about this? If not could you shine some light on this?
It all seems to be working fine apart from the annoyance of iTunes login. Which I guess would only be once a month outside of the Sandbox environment which isn't too bad but just want to be sure I'm doing this correctly.
Thanks
Don't call SKReceiptRefreshRequest. This request is usually only for the "restore purchases" mechanism. This is why you're getting the sign in dialogue. StoreKit will return to you as long as you an observer to the payment queue: https://developer.apple.com/documentation/storekit/skpaymentqueue/1506042-add so you should add yourself to the payment queue on app launch. Then keep that object aline to listen for changes for the entire app lifecycle. You will receive the renewals in the updatedTransactions callback https://developer.apple.com/documentation/storekit/skpaymenttransactionobserver/1506107-paymentqueue
Secondly, you should be doing receipt validation on your own server and not on the client as it will be susceptible to a MITM attack. You can also easily control the logic there and receive Server to server notifications which is best for managing subscriptions.
In my app, I get Lync Presence of our employees through UCWA. It works fine, but I need to knock to Lync with reportMyActivity every 3-4 minute.
I don't need to get presence info at night when employees are not at work, so I stop reportingMyActivity at the end of the working day and resume at it's beginning. Then trying to extend presence subscription, and if I get 404, I create new presence subscription. But no presence updates after those manipulations.
Is it designed to work this way? How could I avoid reportingMyActivity at night?
If you don't do reportMyActivity your Application will be drained, because assumed inactive.
I think you only have two options then:
Keep doing reportMyActivity regurarly also at night, you'll just stop extending presence subscription. Very likely you'll have to manage access token expiration too, which is normally 8 hours valid
You let the App shut down, and a complete new token acquisition, Application creation, presence subscription flow will start next morning
My question is basically how to reproduce the behavior I see in other apps in the app store with regards to in-app purchases:
Immediately following the user pressing "Buy" the button is hidden and a spinner is displayed (essentially de-bouncing the Buy action).
The user pressing cancel to the StoreKit dialog (in the app or outside of it) results in the spinner going away.
I'm attempting to show and hide the spinner based on observing the state of transactions in the SKPaymentQueue.
My problem is described by this poster:
In App Purchase user cancels tx while app in background: tx state stays on purchasing
I see the same behavior as the post above regardless of if the test user is logged in first or not. The transaction is basically "stuck" in the queue with a purchasing state forever (meaning my spinner is displayed forever). When the app is completely exited and restarted (not just multi-tasked away) the transaction is no longer in the payment queue so it's clearly not really still purchasing. It's like the SKPaymentQueue "missed" the state change.
Some more detail that I've noticed is that in the typical case, immediately after adding the payment, the transaction shows up in the queue with a purchasing state. If the user presses cancel, the state of the transaction goes to failed.
In the case of tasking away immediately after adding the payment, the transaction does not show up in the queue until tasking back to the app. Instead of seeing two calls to the updatedTransactions delegate (one with a state of purchasing and one with a state of failed) there is only one call to the updatedTransactions delegate with a state of purchasing. The transaction never goes to failed.
Very occasionally, when tasking back to the app I will get a transaction removed callback (after seeing the updatedTransaction with a state of purchasing). Even in this case I never see the expected update of the transaction to the failed state.
I am not able to reproduce this behavior in apps in the app store (they always correctly show/hide the spinner regardless of tasking away or not), but it's not clear to me if that's because they are doing something tricky, or if it's only a problem in the sandbox.
How to replicate this behavior if not by monitoring the state of the transaction? Is this not a problem in production?
Thanks!
I have used MKStoreKit for all my apps.
It has a block based interface that tells you when the transaction has started (To hide the button and start animating).
It will also tell you if the transaction fails or it was competed, so you can stop the animation and restore the button (if it failed) or show something else when it is completed.
Because it uses blocks, you can handle all this behavior without writing a lot of boilerplate code.
I have to implement In App Purchase Auto-Renewal Model in my app. I have created a test user and getting the response from App Store for subscription. When I tap "Confirm" then sometimes its state becomes SKPaymentTransactionStatePurchased and sometimes it becomes SKPaymentTransactionStateRestored. My problem is that I want to prevent user to use the app if he has not subscribed the app. For that I am trying to track the state of "SKPaymentTransaction" so that I can allow or disallow the user to use the app. Such that, if the state is SKPaymentTransactionStatePurchased, only then he could be able to use the app, but I don't understand how its state changes.
One more thing, When I tap on the "Settings" to manage my Auto-Renewal, it shows me that my app will be expired on the current date i.e., today itself, but when I tapped on the "Confirm" button to subscribe my app for one month then expiry date should be after one month. I don't understand how this whole process is working.
I have read whole documentation of Auto Renewal, but didn't get any help from that.
Please help!
Not sure about your first problem. In my case, I can never get SKPaymentTransactionStateRestored called at all. I am debugging why.
Meanwhile, I was facing the second problem you described. When I decoded the receipt, it looks like they keep the subscription valid for 5 mins. Sounds like a feature for testing in sandbox. At least that's what I am assuming.