I do the tutorial from CodeLab his project with all steps are here Github. Codelab helped me lot, Thanks! I do the steps and deleted all IAP products from tutorial and added only subscribable products. i have two purchase product "Normal" and "Ultimate" in the same Family in Appstoreconnect. Its working well, but I found a problem:
Situation A:
When the user subscribed one from them its working all fine, but when the user want to subscribe the other like from "Normal" to "Ultimate" or "Ultimate" to "Normal" in his Validate activ time, then Firebase Cloud don't update his Purchase (Produkt ID and Order ID Is still the old ID's). When Firebase don't update, then get the user not his upgrade to other subscribe instantly. He get there upgrade to the other purchase after a year.
Situation B:
The same Problem, but Outside from the App. User subscribed one product, then he go outside from app in his Appstore settings and change his subscribe product. Firebase get a info from Apple, but Firebase Cloud don't update the subscription information from User. can u or have u solve this problem?
my changes from Codelab ->
const cloudRegion = 'europe-west1';
const subscriptionList = ["kunde_1_fahrzeug", "kunde_3_fahrzeug"];
//storeKeySubscription
const subscription_kunde_1_fahrzeug = 'kunde_1_fahrzeug';
const subscription_kunde_3_fahrzeug = 'kunde_3_fahrzeug';
void updatePurchases() {
// omitted
// hasActiveSubscription = purchases.any((element) => element.productId == subscription_kunde_1_fahrzeug && element.status != Status.expired);
//hasActiveSubscription = purchases.any((element) => element.productId == subscriptionList && element.status != Status.expired);
hasActiveSubscription = purchases.any((element) => subscriptionList.any((x) => x == element.productId) && element.status != Status.expired);
for(PastPurchase x in purchases){
print("Gelb hasActiveSubscription IAP-REPO : ${x.productId} - ${x.status}");
};
hasUpgrade = purchases.any(
(element) => subscriptionList.any((x) => x == element.productId),
);
/*
hasUpgrade = purchases.any(
(element) => element.productId == storeKeyUpgrade,
);
*/
notifyListeners();
// omitted
}
void purchasesUpdate() {
// omitted
if (products.isNotEmpty) {
// subscriptions = products .where((element) => element.productDetails.id == subscription_kunde_1_fahrzeug) .toList();
subscriptions = products
.where((element) => subscriptionList.any((x) => x == element.productDetails.id))
.toList();
upgrades = products
.where((element) => subscriptionList.any((x) => x == element.productDetails.id))
.toList();
}
// omitted
}
Future<void> loadPurchases() async {
// omitted
const ids = <String>{
subscription_kunde_1_fahrzeug,
subscription_kunde_3_fahrzeug,
//storeKeyUpgrade,
};
// omitted
}
Future<void> buy(PurchasableProduct product) async {
// omitted
// case storeKeyConsumable:
// await iapConnection.buyConsumable(purchaseParam: purchaseParam);
// break;
case subscription_kunde_1_fahrzeug:
await iapConnection.buyNonConsumable(purchaseParam: purchaseParam);
break;
case subscription_kunde_3_fahrzeug:
//case storeKeyUpgrade:
await iapConnection.buyNonConsumable(purchaseParam: purchaseParam);
break;
// omitted
}
Future<void> _handlePurchase(PurchaseDetails purchaseDetails) async {
// omitted
if (validPurchase) {
// Apply changes locally
switch (purchaseDetails.productID) {
case subscription_kunde_1_fahrzeug:
print("Orange: ID Produkt: ${purchaseDetails.productID}, ${purchaseDetails.transactionDate}, ${purchaseDetails.verificationData}, ${purchaseDetails.status}, ${purchaseDetails.purchaseID}, ${purchaseDetails.pendingCompletePurchase}, switch (purchaseDetails.productID) case: subscription_kunde_1_fahrzeug");
counter.applyPaidMultiplier_kunde_1_fahrzeug();
break;
case subscription_kunde_3_fahrzeug:
print("Orange: ID Produkt: ${purchaseDetails.productID}, ${purchaseDetails.transactionDate}, ${purchaseDetails.verificationData}, ${purchaseDetails.status}, ${purchaseDetails.purchaseID}, ${purchaseDetails.pendingCompletePurchase}, switch (purchaseDetails.productID) case: subscription_kunde_3_fahrzeug");
counter.applyPaidMultiplier_kunde_3_fahrzeug();
break;
// case storeKeyConsumable:
// counter.addBoughtDashes(2000);
// break;
/* case storeKeyUpgrade:
_beautifiedDashUpgrade = true;
break;
*/
// omitted
}
@immutable
class PastPurchase {
// omitted
String get title {
switch (productId) {
case subscription_kunde_1_fahrzeug:
return 'Subscription';
case subscription_kunde_3_fahrzeug:
return 'Subscription';
default:
return productId;
}
}
// omitted
}
export interface ProductData {
productId: string;
type: "SUBSCRIPTION" | "NON_SUBSCRIPTION";
}
export const productDataMap: { [productId: string]: ProductData } = {
"kunde_1_fahrzeug": {
productId: "kunde_1_fahrzeug",
type: "SUBSCRIPTION",
},
"kunde_3_fahrzeug": {
productId: "kunde_3_fahrzeug",
type: "SUBSCRIPTION",
},
};