Testing iOS: Calling init() the first time an app is opened triggers 2 PURCHASE_CANCELLED events - in-app-billing

The ios user account password pops up also. This doesn't happen if called again while app is still opened, but repeats if app is closed and reopened.
Thanks

Sounds like you have unfinished purchases that you need to finish.
Purchases will remain in a pending state until your application calls finish on them. This is to ensure that your application processes and verifies a purchase.
You should call InAppBilling.service.finishPurchase when you have process a purchase and either delivered the product or handled the cancellation/failure:
https://gist.github.com/marchbold/851359b9e456e1a85d65#file-distriqt-extension-inappbilling-makepurchase-as
private function purchase_cancelledHandler( event:PurchaseEvent ):void
{
// This transaction was cancelled so you should notify your user and finish the purchase
trace( "purchase cancelled" + event.errorCode );
if (event.data && event.data.length > 0)
InAppBilling.service.finishPurchase( event.data[0] );
}
At start up you can retrieve the pending purchases after the SETUP_SUCCESS event:
private function setupSuccessHandler( event:InAppBillingEvent ):void
{
var pending:Array = InAppBilling.service.getPendingPurchases();
// Iterate over and handle as required
}
http://docs.airnativeextensions.com/inappbilling/docs/com/distriqt/extension/inappbilling/InAppBilling.html#getPendingPurchases()

Related

Timer.periodic is not cancelled when the condition is true

I"m using a method that checks if the user's email is verified every 5 seconds, the checkIsEmailVerified() is asynchronous since it needs to send a request to check if the user has verified his email.
void checkEveryDurationUserVerification() {
Timer.periodic(
Duration(seconds: 5),
(timer) async {
if (isUserVerified) {
timer.cancel();
}
print("another check");
await checkIsEmailVerified();
},
);
}
so here is what happens, when this method is executing, it shows "another check" every 5 seconds as I want, and so the checkIsEmailVerified().
so what I have ? is a fully working email verification checker every 5 seconds, and the email is not verified yet.
when I open my email inbox and verify my email, In the app it works the listener I gave to the isUserVerified is working because it's true, and it navigates me to the home page as I want, but the Timer is not canceled even the isUserVerified is true
The "another check" is still printing in the debug console, even if the isUserVerified is true and so it should cancel that Timer**
what I think:
that this behavior is related to making the Timer's callback asynchronous
what I expect:
I want the when the isUserVerified is true the Timer to be canceled, so it stopped working after verifying the user

multiple INApp purchase request for different product in tableView

multiple in app purchaseI am working a music player application, the user need to purchase the albums before they start hearing it, I have attached a sample purchase screen. when the user tap it it should move to inApp purchase . The purchase type is non- consumable they need to pay only once.
I am having a table view with list of albums in it, if I purchase the first index album, it is working fine when I move to second index it was stating like already purchased.
I have used SwiftyStoreKit pod for the inappropriate purchase and everything is working as I expected. but I don't know how to handle tableview with n number of cell.
//INAPP purchase swift guy
func getinfo (purchase: RegisterPurchase) {
NetworkActivityIndicatioManager.NetworkoperationStarted()
SwiftyStoreKit.retrieveProductsInfo([bundleId + "." + purchase.rawValue]) { (result) in
NetworkActivityIndicatioManager.NetworkOperationFinished()
self.showAlert(self.alertForProductRetrievalInfo(result))
}
}
func purchase(purchase: RegisterPurchase) {
NetworkActivityIndicatioManager.NetworkoperationStarted()
SwiftyStoreKit.purchaseProduct(bundleId + "." + purchase.rawValue, atomically: true) { result in
NetworkActivityIndicatioManager.NetworkOperationFinished()
if case .success(let purchase) = result {
let downloads = purchase.transaction.downloads
if !downloads.isEmpty {
SwiftyStoreKit.start(downloads)
}
// Deliver content from server, then:
if purchase.needsFinishTransaction {
SwiftyStoreKit.finishTransaction(purchase.transaction)
}
}
if let alert = self.alertForPurchaseResult(result) {
self.showAlert(alert)
}
}
}
Issue is with your product type. If you want to make the product purchasable again, you should use consumable purchase, NOT non-consumable.
Non-consumable product can be purchased only once for an iTunes
account.
For your case, you can change the product type to consumable, then save this purchase in server and link with the user. This way, you can unlock the album if user purchased before.

Ensure processing of a REST call in flutter app in background

I need to ensure that a certain HTTP request was send successfully. Therefore, I'm wondering if a simple way exists to move such a request into a background service task.
The background of my question is the following:
We're developing a survey application using flutter. Unfortunately, the app is intended to be used in an environment where no mobile internet connection can be guaranteed. Therefore, I’m not able to simply post the result of the survey one time but I have to retry it if it fails due to network problems. My current code looks like the following. The problem with my current solution is that it only works while the app is active all the time. If the user minimizes or closes the app, the data I want to upload is lost.
Therefore, I’m looking for a solution to wrap the upload process in a background service task so that it will be processed even when the user closes the app. I found several posts and plugins (namely https://medium.com/flutter-io/executing-dart-in-the-background-with-flutter-plugins-and-geofencing-2b3e40a1a124 and https://pub.dartlang.org/packages/background_fetch) but they don’t help in my particular use case. The first describes a way how the app could be notified when a certain event (namely the geofence occurred) and the second only works every 15 minutes and focuses a different scenario as well.
Does somebody knows a simple way how I can ensure that a request was processed even when there is a bad internet connection (or even none at the moment) while allowing the users to minimize or even close the app?
Future _processUploadQueue() async {
int retryCounter = 0;
Future.doWhile(() {
if(retryCounter == 10){
print('Abborted after 10 tries');
return false;
}
if (_request.uploaded) {
print('Upload ready');
return false;
}
if(! _request.uploaded) {
_networkService.sendRequest(request: _request.entry)
.then((id){
print(id);
setState(() {
_request.uploaded = true;
});
}).catchError((e) {
retryCounter++;
print(e);
});
}
// e ^ retryCounter, min 0 Sec, max 10 minutes
int waitTime = min(max(0, exp(retryCounter)).round(), 600);
print('Waiting $waitTime seconds till next try');
return new Future.delayed(new Duration(seconds: waitTime), () {
print('waited $waitTime seconds');
return true;
});
})
.then(print)
.catchError(print);
}
You can use the plugin shared_preferences to save each HTTP response to the device until the upload completes successfully. Like this:
requests: [
{
id: 8eh1gc,
request: "..."
},
...
],
Then whenever the app is launched, check if any requests are in the list, retry them, and delete them if they complete. You could also use the background_fetch to do this every 15 minutes.

Ionic Native - InAppPurchase2 - When calling store.when().approved() it runs the callback before the confirmation is complete

I'm setting up in app purchases in my Ionic app and I've been having some trouble getting the test purchases working correctly. It would seem that as soon as I execute this particular function, it automatically runs the code as if it was approved, even though the confirmation to get the subscription hasn't occurred yet:
this.platform.ready().then(() => {
// Register the products for consumption
this.products.forEach(product => {
this.store.register({
id: product.id,
alias: product.alias,
type: product.type
});
// When a purchase is approved, see what we get here
this.store.when(product.id).approved((order) => {
// Purchase was successful, setup the appropriate subscription
this._subscriptions.updateSubscription(this.user.id, this.selectedPlan.amount, 'activate').then(() => {
if(this.selectedPlan.amount === 1) {
this.subscriptionGrammar = 'month';
} else if(this.selectedPlan.amount > 1) {
this.subscriptionGrammar = 'months';
}
order.finish();
});
});
});
});
I was under the impression that utilizing the .when().approved() would only fire once the payment "goes through". Since I'm using test transactions, I'm not sure how that would affect it, but I would suspect it should only do that once I hit "Confirm" on the Google dialog that pops up in my app?
Is there something I'm missing here?

On subscription run a "callback" function once

I'm working with cordova's BLE (bluetooth low energy)
After I subscribe to notifications of BLE (which returns Observable), I want to send some message to the ble device, what is the best way to perform this, basically I need to run a function once after the subscription is made so that once device responds back to me, the code in the subscription is run.
ble.startNotification(deviceId, uuid1, uuid2).subscribe(bufferData=> {
//do something with bufferData
})
now after this, I want to run something like a callback,
.then(()=> {
//send message to device (only once), after the message is sent, the device will respond back and the `do something with bufferData` code will be run
})
I could easily do a setTimeout and send a message to the device after few seconds, and of course it works, but I want to do it cleanly, after I'm sure the subscription happened (subscription to the Observable of course)
You can wrap existing method using create operator and add custom code that will be executed on every new subscription.
See the example:
// emulate cordova with "dummy" bluetooth interface
const BLE = {
startNotification: () => Rx.Observable.interval(1000)
}
const wrappedBLE = (...params) =>
Rx.Observable.create(observer => {
// constructor fn will be executed on every new subscribtion
const disposable = BLE.startNotification(...params).subscribe(observer);
// place code to send notification here, instead of console log
console.log('New subscriber for BLE with params: ', params);
return disposable;
});
wrappedBLE("param1", "param2", "param3")
.subscribe(e => console.log("received notification: ", e));
<script src="https://unpkg.com/rxjs#5.4.3/bundles/Rx.min.js"></script>