-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Description
According to the documentation, you want to initialize the stream listener first thing in your app because when it starts you get a list of purchase details sent to the purchase listener that need to be processed and marked as consumed. Because this happens, it makes it so users can't purchase more of that consumable. The apple store simply returns that the consumable has already been purchased and will be refunded for free.
To follow the documentation, I put my subscription listener at the very top of the main function. I have to do some weird things to make sure the transactions are run properly, because I need the users Id to validate the receipts on our firebase server, and the user isn't signed in yet at the top of main.
While debugging in Xcode, I see firebase analytics capturing the old purchase events and not sending them because they recognize them as duplicates. but the purchaseUpdates listener doesn't capture any of these. Here is the output in Xcode

The code I use for initializing the transaction listener is here.
void main() {
WidgetsFlutterBinding.ensureInitialized();
List<dynamic> purchaseDetails = List<dynamic>();
Stream _purchaseUpdates = InAppPurchaseConnection.instance.purchaseUpdatedStream;
_purchasesSubscription = _purchaseUpdates.listen((purchases) {
for(int i = 0; i < purchases.length; i++) {
print(purchases.status);
print(purchases.purchaseID);
}
purchaseDetails.addAll(purchases);
});
try{
StreamingSharedPreferences.instance.then((value){
});
// set up Sentry to catch Flutter errors
FlutterError.onError = (FlutterErrorDetails details) {
if (SentryHelper.isInDebugMode()) {
FlutterError.dumpErrorToConsole(details);
} else {
Zone.current.handleUncaughtError(details.exception, details.stack);
}
};
} catch(e) {
var state = AppState.getDefault()
.rebuild((b) => b..message = "in catch " + e.toString());
runHallo(state, '/login');
}
FirebaseAuth auth = FirebaseAuth.instance;
Future.wait([auth.currentUser(), loadState()])
.timeout(Duration(seconds: 5)).then((futures) {
try{
FirebaseUser user = futures[0];
AppState appState = futures[1];
var isLoggedIn = user != null;
var isAppStateLoggedIn = appState.isAuthenticated();
var message =
(isLoggedIn ? "user is logged in," : "user is not logged in,") +
(isAppStateLoggedIn
? "appState.isAuthenticated()=true"
: "appState.isAuthenticated()=false");
var state = appState.rebuild((b) => b..message = message);
if (isLoggedIn) {
message += [
(appState.auth.userId == user.uid).toString(),
appState.getAuthUser()?.needsSetup()?.toString() ?? "false"
].join(', ');
}
if (user != null &&
appState.auth.userId == user.uid &&
!appState.getAuthUser().needsSetup()) {
_setupIAP(purchaseDetails);
_purchasesSubscription.cancel();
_purchasesSubscription = _purchaseUpdates.listen((purchases) {
_setupIAP(purchases);
});
runHallo(state, '/home');
} else {
var state = appState.rebuild((b) => b..message = message);
runHallo(state, '/login');
}
} catch (e) {
var state = AppState.getDefault()
.rebuild((b) => b..message = "in catch " + e.toString());
runHallo(state, '/login');
}
});
}
I don't get any print statements from within the flutter app.