Flutter iOS: прослушиватель покупок в приложении, отражающий старые покупки при инициализации
Привет всем!
Я интегрирую покупки в приложении в свое приложение Flutter с помощью пакета in_app_purchase . Я успешно настроил все как для Google Play Store, так и для Apple App Store в тестовой среде.
Текущая настройка
Покупки работают нормально на обеих платформах. Я могу совершить покупку по подписке, и это правильно отображается в Google Play и в песочнице iOS.
Я создал контроллер Getx, в котором инициализирую прослушиватель покупок и информацию о магазине. Ниже приведен соответствующий код:
Listener Initialization in onInit:
late InAppPurchasePlatform _inAppPurchasePlatform;
@override
Future onInit() async {
_inAppPurchasePlatform = InAppPurchasePlatform.instance;
final Stream purchaseUpdated =
_inAppPurchasePlatform.purchaseStream;
_subscription0 =
purchaseUpdated.listen((List purchaseDetailsList) {
_handlePurchaseUpdates(purchaseDetailsList);
}, onDone: () {
_subscription0.cancel();
print("purchase listener onDone :");
}, onError: (Object error) {
print("purchase listener erro :" + error.toString());
});
initStoreInfo();
super.onInit();
}
< /code>
initstoreinfo реализация: < /p>
Future initStoreInfo() async {
print("initStoreInfo called:");
try {
final bool isAvailable = await _inAppPurchasePlatform.isAvailable();
if (!isAvailable) {
error.value = 'Store is unavailable. Please try again later.';
return;
}
print("Store is available.");
final List fetchedPlans = await fetchIAPPlanModel();
plans.addAll(fetchedPlans);
_kProductIds.addAll(fetchedPlans
.map((plan) => plan.productId ?? '')
.where((id) => id.isNotEmpty));
final ProductDetailsResponse productDetailResponse =
await _inAppPurchasePlatform
.queryProductDetails(_kProductIds.toSet());
if (productDetailResponse.error != null) {
error.value = productDetailResponse.error!.message!;
return;
}
if (productDetailResponse.productDetails.isEmpty) {
error.value = 'No products available at the moment.';
return;
}
// print(
// "Product Details Fetched: ${productDetailResponse.productDetails.map((e) =>
e.rawPrice).toList()}");
_linkPlansWithProductDetails(productDetailResponse.productDetails);
if (GetPlatform.isAndroid) {
// Set user choice billing
final InAppPurchaseAndroidPlatformAddition addition =
InAppPurchasePlatformAddition.instance!
as InAppPurchaseAndroidPlatformAddition;
unawaited(
addition.setBillingChoice(BillingChoiceMode.userChoiceBilling));
} else if (Platform.isIOS) {
//write code for ios
}
} catch (e) {
print("Error initializing store: $e");
error.value = "Error initializing store: $e";
isLoading.value = false;
return;
}
}
< /code>
Функция _handlepurchaseupdates < /p>
void _handlePurchaseUpdates(List purchaseDetailsList) async {
print("purchaseDetailsList : " + purchaseDetailsList.length.toString());
final list = _plansController.subscriptionsList
.map((e) => e.transactionIds)
.toList();
list.map((e) => print("listitems : " + e.toString()));
print("list : " + list.toString());
print("list : " + list.length.toString());
for (final PurchaseDetails details in purchaseDetailsList) {
purchases[details.productID] = details;
var purchaseID = details.purchaseID;
print(" purchaseID:" + purchaseID.toString());
print("PurchaseDetails.status :" + details.status.toString());
if (details.pendingCompletePurchase) {
try {
await _inAppPurchasePlatform.completePurchase(details);
} catch (e) {
print("Error completing purchase: $e");
}
}
if (details.status == PurchaseStatus.canceled) {
purchasePending.value = false;
isLoading.value = false;
isButtonClicked.value = false;
return;
}
// Print error details if the purchase failed
if (details.status == PurchaseStatus.error) {
error.value = details.error?.message ?? "Unknown error occurred.";
purchasePending.value = false;
isLoading.value = false;
isButtonClicked.value = false;
Get.snackbar(
'Purchase Error',
'',
backgroundColor: Colors.red,
snackPosition: SnackPosition.BOTTOM,
duration: const Duration(seconds: 3),
);
// Check if the error is due to "itemAlreadyOwned"
if (details.error?.message == "BillingResponse.itemAlreadyOwned") {
// Show dialog to the user
_showAlreadyOwnedDialog();
}
print("PurchaseStatus.error " + details.error!.message.toString());
return;
}
isLoading.value = true;
if (details.status == PurchaseStatus.pending) {
purchasePending.value = true;
return;
} else if (details.status == PurchaseStatus.error) {
error.value = details.error?.message ?? "Unknown error occurred.";
purchasePending.value = false;
await _sendPurchaseToBackend(details, false);
} else if (details.status == PurchaseStatus.restored) {
error.value = details.error?.message ?? "Subscription restored";
isButtonClicked.value = false;
return;
} else if (details.status == PurchaseStatus.purchased) {
// final bool isValid = await _verifyPurchase(details);
activePlanId.value = details.productID;
purchasePending.value = true;
// Notify backend about the successful transaction
await _sendPurchaseToBackend(details, true);
_processedPurchases.add(details.productID);
}
if (details.pendingCompletePurchase) {
await _inAppPurchasePlatform.completePurchase(details);
await fetchUserActivePlan();
}
}
}
Проблема
В iOS, как только приложение запускается и инициализируется контроллер Getx, покупка в приложении прослушиватель (purchaseStream) также инициализируется. Однако прослушиватель немедленно предоставляет список PurchaseDetailsList, содержащий предыдущие покупки, даже если новый платеж не был совершен.
Например, при запуске он отражает следующий статус:
PurchaseStatus.purchased
Такое поведение проблематично, поскольку я не могу отличить старые покупки (из предыдущих сеансов) от новых покупок.
Что я пробовал
Я запускаю всплывающее окно биллинга через кнопку после запуска, которое работает нормально. Но эта проблема возникает до совершения новой покупки.
Мой вопрос
Почему прослушиватель PurchaseStream возвращает предыдущие покупки на iOS во время инициализации?
Как отличить старые покупки от новых?
Существует ли рекомендуемый подход для обработки таких сценариев, гарантирующий, что старые покупки не будут повторно обработаны?
Будем очень признательны за любую помощь или альтернативные идеи реализации!
Результат для
Flutter iOS: прослушиватель покупок в приложении, отражающий старые покупки при инициализации Привет всем! Я интегрирую покупки в приложении в свое приложение Flutter с помощью пакета in_app_purchase . Я успешно настроил все как для Google Play Store, так и для Apple App Store в тестовой среде. Текущая настройка Покупки работают нормально на обеих платформах. Я могу совершить покупку по подписке, и это правильно отображается в Google Play и в песочнице iOS. Я создал контроллер Getx, в котором инициализирую прослушиватель покупок и информацию о магазине. Ниже приведен соответствующий код: [code] Listener Initialization in onInit: late InAppPurchasePlatform _inAppPurchasePlatform;
if (details.pendingCompletePurchase) { await _inAppPurchasePlatform.completePurchase(details); await fetchUserActivePlan(); } } [/code] } Проблема В iOS, как только приложение запускается и инициализируется контроллер Getx, покупка в приложении прослушиватель (purchaseStream) также инициализируется. Однако прослушиватель немедленно предоставляет список PurchaseDetailsList, содержащий предыдущие покупки, даже если новый платеж не был совершен. Например, при запуске он отражает следующий статус: PurchaseStatus.purchased Такое поведение проблематично, поскольку я не могу отличить старые покупки (из предыдущих сеансов) от новых покупок. Что я пробовал Я запускаю всплывающее окно биллинга через кнопку после запуска, которое работает нормально. Но эта проблема возникает до совершения новой покупки. Мой вопрос Почему прослушиватель PurchaseStream возвращает предыдущие покупки на iOS во время инициализации? Как отличить старые покупки от новых? Существует ли рекомендуемый подход для обработки таких сценариев, гарантирующий, что старые покупки не будут повторно обработаны? Будем очень признательны за любую помощь или альтернативные идеи реализации! Результат для [code] print("old originalT :" +
Flutter iOS: прослушиватель покупок в приложении, отражающий старые покупки при инициализации
Привет всем!
Я интегрирую покупки в приложении в свое приложение Flutter с помощью пакета in_app_purchase . Я успешно настроил все как для Google Play...
Flutter iOS: прослушиватель покупок в приложении, отражающий старые покупки при инициализации
Привет всем!
Я интегрирую покупки в приложении в свое приложение Flutter с помощью пакета in_app_purchase . Я успешно настроил все как для Google Play...
Flutter iOS: прослушиватель покупок в приложении, отражающий старые покупки при инициализации
Привет всем!
Я интегрирую покупки в приложении в свое приложение Flutter с помощью пакета in_app_purchase . Я успешно настроил все как для Google Play...
Итак, я пытался сделать игру, чтобы выучить какой -то Javascript, но всякий раз, когда я пытаюсь создать нового слушателя событий с помощью функции, затем изменяя целевой аргумент, просто переопределяет любые другие слушатели событий, созданные с...