Ошибки контроллера Superwall при покупке FromGooglePlay и хранители продукты FlutterIOS

Программируем под IOS
Ответить
Anonymous
 Ошибки контроллера Superwall при покупке FromGooglePlay и хранители продукты Flutter

Сообщение Anonymous »

Я скопировал этот контроллер Superwall Superwall RevenueCat из Superwall Docs для обработки покупок и восстановления и других вещей в iOS и Android, и в одном проекте я использовал это таким, какой он есть, и он отлично справился Google Play and Store Porducts Я не знаю, что все было так же, почему в другом проекте этот контроллер имеет столько ошибок, и я не знаю, как исправить этот Beacuse в предыдущих проектах, я ничего не изменил в контроллере < /p>
контроллер Superwall < /p>

Код: Выделить всё

import 'dart:io';

import 'package:flutter/services.dart';
import 'package:purchases_flutter/purchases_flutter.dart';
import 'package:superwallkit_flutter/superwallkit_flutter.dart' hide LogLevel;

class RCPurchaseController extends PurchaseController {
// MARK: Configure and sync subscription Status
/// Makes sure that Superwall knows the customers subscription status by
/// changing `Superwall.shared.subscriptionStatus`
Future configureAndSyncSubscriptionStatus() async {
// Configure RevenueCat
await Purchases.setLogLevel(LogLevel.debug);
final configuration = Platform.isIOS
? PurchasesConfiguration('ios_rc_key')
: PurchasesConfiguration('android_rc_key');
await Purchases.configure(configuration);

// Listen for changes
Purchases.addCustomerInfoUpdateListener((customerInfo) async {
// Gets called whenever new CustomerInfo is available
final entitlements = customerInfo.entitlements.active.keys
.map((id) => Entitlement(id: id))
.toSet();

final hasActiveEntitlementOrSubscription = customerInfo
.hasActiveEntitlementOrSubscription(); // Why? -> https://www.revenuecat.com/docs/entitlements#entitlements

if (hasActiveEntitlementOrSubscription) {
await Superwall.shared.setSubscriptionStatus(
SubscriptionStatusActive(entitlements: entitlements));
} else {
await Superwall.shared
.setSubscriptionStatus(SubscriptionStatusInactive());
}
});
}

// MARK: Handle Purchases

/// Makes a purchase from App Store with RevenueCat and returns its
/// result. This gets called when someone tries to purchase a product on
/// one of your paywalls from iOS.
@override
Future purchaseFromAppStore(String productId) async {
// Find products matching productId from RevenueCat
final products = await PurchasesAdditions.getAllProducts([productId]);

// Get first product for product ID (this will properly throw if empty)
final storeProduct = products.firstOrNull;

if (storeProduct == null) {
return PurchaseResult.failed(
'Failed to find store product for $productId');
}

final purchaseResult = await _purchaseStoreProduct(storeProduct);
return purchaseResult;
}

/// Makes a purchase from Google Play with RevenueCat and returns its
/// result.  This gets called when someone tries to purchase a product on
/// one of your paywalls from Android.
@override
Future purchaseFromGooglePlay(
String productId, String? basePlanId, String? offerId) async {
// Find products matching productId from RevenueCat
List products =
await PurchasesAdditions.getAllProducts([productId]);

// Choose the product which matches the given base plan.
// If no base plan set, select first product or fail.
String storeProductId = "$productId:$basePlanId";

// Try to find the first product where the googleProduct's basePlanId matches the given basePlanId.
StoreProduct? matchingProduct;

// Loop through each product in the products list.
for (final product in products) {
// Check if the current product's basePlanId matches the given basePlanId.
if (product.identifier == storeProductId) {
// If a match is found, assign this product to matchingProduct.
matchingProduct = product;
// Break the loop as we found our matching product.
break;
}
}

// If a matching product is not found, then try to get the first product from the list.
StoreProduct? storeProduct =
matchingProduct ?? (products.isNotEmpty ? products.first : null);

// If no product is found (either matching or the first one), return a failed purchase result.
if (storeProduct == null) {
return PurchaseResult.failed("Product not found");
}

switch (storeProduct.productCategory) {
case ProductCategory.subscription:
SubscriptionOption? subscriptionOption =
await _fetchGooglePlaySubscriptionOption(
storeProduct, basePlanId, offerId);
if (subscriptionOption == null) {
return PurchaseResult.failed(
"Valid subscription option not found for product.");
}
return await _purchaseSubscriptionOption(subscriptionOption);
case ProductCategory.nonSubscription:
return await _purchaseStoreProduct(storeProduct);
case null:
return PurchaseResult.failed("Unable to determine product category");
}
}

Future _fetchGooglePlaySubscriptionOption(
StoreProduct storeProduct,
String? basePlanId,
String? offerId,
) async {
final subscriptionOptions = storeProduct.subscriptionOptions;

if (subscriptionOptions != null && subscriptionOptions.isNotEmpty) {
// Concatenate base + offer ID
final subscriptionOptionId =
_buildSubscriptionOptionId(basePlanId, offerId);

// Find first subscription option that matches the subscription option ID or use the default offer
SubscriptionOption? subscriptionOption;

// Search for the subscription option with the matching ID
for (final option in subscriptionOptions) {
if (option.id == subscriptionOptionId) {
subscriptionOption = option;
break;
}
}

// If no matching subscription option is found, use the default option
subscriptionOption ??= storeProduct.defaultOption;

// Return the subscription option
return subscriptionOption;
}

return null;
}

Future _purchaseSubscriptionOption(
SubscriptionOption subscriptionOption) async {
// Define the async perform purchase function
Future performPurchase() async {
// Attempt to purchase product
CustomerInfo customerInfo =
await Purchases.purchaseSubscriptionOption(subscriptionOption);
return customerInfo;
}

PurchaseResult purchaseResult =
await _handleSharedPurchase(performPurchase);
return purchaseResult;
}

Future _purchaseStoreProduct(
StoreProduct storeProduct) async {
// Define the async perform purchase function
Future performPurchase() async {
// Attempt to purchase product
CustomerInfo customerInfo =
await Purchases.purchaseStoreProduct(storeProduct);
return customerInfo;
}

PurchaseResult purchaseResult =
await _handleSharedPurchase(performPurchase);
return purchaseResult;
}

// MARK: Shared purchase
Future  _handleSharedPurchase(
Future Function() performPurchase) async {
try {
// Perform the purchase using the function provided
CustomerInfo customerInfo = await performPurchase();
print(customerInfo.activeSubscriptions.length);
print(customerInfo.entitlements.all.length);
print(customerInfo.entitlements.active);

// Handle the results
if (customerInfo.hasActiveEntitlementOrSubscription()) {
return PurchaseResult.purchased;
} else {
return PurchaseResult.failed("No active subscriptions found.");
}
} on PlatformException catch (e) {
var errorCode = PurchasesErrorHelper.getErrorCode(e);
if (errorCode == PurchasesErrorCode.paymentPendingError) {
return PurchaseResult.pending;
} else if (errorCode == PurchasesErrorCode.purchaseCancelledError) {
return PurchaseResult.cancelled;
} else {
return PurchaseResult.failed(
e.message ?? "Purchase failed in RCPurchaseController");
}
}
}

// MARK: Handle Restores

/// Makes a restore with RevenueCat and returns `.restored`, unless an error is thrown.
/// This gets called when someone tries to restore purchases on one of your paywalls.
@override
Future restorePurchases() async {
try {
CustomerInfo customerInfo = await Purchases.restorePurchases();
await configureAndSyncSubscriptionStatus();

Superwall.shared.setUserAttributes({
'entitlements': customerInfo.entitlements.active.keys.join(','),
'isSubscribed': customerInfo.hasActiveEntitlementOrSubscription(),
});

return RestorationResult.restored;
} on PlatformException catch (e) {
// Error restoring purchases
return RestorationResult.failed(
e.message ?? "Restore failed in RCPurchaseController");
}
}
}

// MARK: Helpers

String _buildSubscriptionOptionId(String? basePlanId, String? offerId) {
String result = '';

if (basePlanId != null) {
result += basePlanId;
}

if (offerId != null) {
if (basePlanId != null) {
result += ':';
}
result += offerId;
}

return result;
}

extension CustomerInfoAdditions on CustomerInfo {
bool hasActiveEntitlementOrSubscription() {
return (activeSubscriptions.isNotEmpty || entitlements.active.isNotEmpty);
}
}

extension PurchasesAdditions on Purchases {
static Future getAllProducts(
List productIdentifiers) async {
final subscriptionProducts = await Purchases.getProducts(productIdentifiers,
productCategory: ProductCategory.subscription);
final nonSubscriptionProducts = await Purchases.getProducts(
productIdentifiers,
productCategory: ProductCategory.nonSubscription);
final combinedProducts = [
...subscriptionProducts,
...nonSubscriptionProducts
];
return combinedProducts;
}
}

< /code>
Конфигурация в main.dart < /p>
 RCPurchaseController purchaseController = RCPurchaseController();
await purchaseController.configureAndSyncSubscriptionStatus();
SuperwallOptions options = SuperwallOptions();
options.logging.level = LogLevel.warn;
options.logging.scopes = {
LogScope.paywallPresentation,
LogScope.paywallEvents,
LogScope.transactions,
};

final apiKey = Platform.isAndroid
? ''
: '';

Superwall.configure(
apiKey,
purchaseController: purchaseController,
options: options,
);

final revenueApiKey = Platform.isAndroid
? ''
: '';

await Purchases.setDebugLogsEnabled(true);
await Purchases.configure(PurchasesConfiguration(revenueApiKey));

< /code>
Ошибки
при покупке у Googleplay < /p>
Тело может завершать нормально, вызывая «null», который будет возвращен, но возвращаемый тип, «Futureor», является потенциально не нулевым типом.  /> String ProductId,
String?The name 'StoreProduct' is defined in the libraries 'package:purchases_flutter/models/store_product_wrapper.dart (via package:purchases_flutter/purchases_flutter.dart)' and 'package:superwallkit_flutter/src/public/StoreProduct.dart (via package:superwallkit_flutter/superwallkit_flutter.dart)'.
Попробуйте использовать «в качестве префикса» для одного из директив импорта или скрыть имя от всех, кроме одного из импорта.>

Подробнее здесь: https://stackoverflow.com/questions/796 ... ts-flutter
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «IOS»