最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

iOS App terminating while using in_app_purchase into 18.3.1 into Flutter - Stack Overflow

programmeradmin1浏览0评论

I am learning Flutter and implemented the in_app_purchase for for Android and iOS, however it works fine into both platforms but having the below issue into iOS 18.3.1 . The version I have

in_app_purchase: ^3.1.13

I face this issue

flutter: Purchase successful!
flutter: Purchase finally :
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSNull length]: unrecognized selector sent to instance 0x20c8db910'
*** First throw call stack:
(0x1a266a5fc 0x19fbe5244 0x1a27c3174 0x1a266d5c8 0x1a266cef0 0x1a125bbf0 0x1cfc08f64 0x1cfc066a8 0x1cfc05d18 0x1cfc052f4 0x1cfc07811 0x1cfc09a29 0x1cfbe2ddd 0x1cfbe2ddd 0x1cfbe2ddd 0x1cfbde2c5 0x1cfbde419 0x1cfbde2c5 0x1adf8fe39)
libc++abi: terminating due to uncaught exception of type NSException

My source code

Future<void> purchasePlan(BasePlans basePlan, BuildContext context) async {
    try {
      isLoading.value = true;
      print("purchasePlan called : " + basePlan.id.toString());
      print("purchasePlan called : " + basePlan.productDetails!.title);

      if (basePlan.productDetails == null) {
        error.value = "Product not available for purchase.";
        print("Product not available for purchase");
        isLoading.value = false;
        return;
      }
      purchasePending.value = true;
      late PurchaseParam purchaseParam;

      if (Platform.isAndroid) {
        // Check for existing subscriptions
        final GooglePlayPurchaseDetails? oldSubscription =
            _getOldSubscription(basePlan.productDetails!, purchases);
        purchaseParam = GooglePlayPurchaseParam(
          productDetails: basePlan.productDetails!,
          changeSubscriptionParam: (oldSubscription != null)
              ? ChangeSubscriptionParam(
                  oldPurchaseDetails: oldSubscription,
                  replacementMode: ReplacementMode.withoutProration)
              : null,
        );
      } else {

        print("basePlan.productDetails id: " + basePlan.productDetails!.id);
        print("basePlan.productDetails title : " +
            basePlan.productDetails!.title);
        print("basePlan.productDetails description : " +
            basePlan.productDetails!.description);
        print("basePlan.productDetails price : " +
            basePlan.productDetails!.price);
        print("basePlan.productDetails  rawPrice: " +
            basePlan.productDetails!.rawPrice.toString());
        print("basePlan.productDetails  currencyCode: " +
            basePlan.productDetails!.currencyCode.toString());
        print("basePlan.productDetails  currencySymbol: " +
            basePlan.productDetails!.currencySymbol.toString());

        purchaseParam = PurchaseParam(
          productDetails: basePlan.productDetails!,
        );

        print("basePlan.purchaseParam : " + purchaseParam.productDetails.id);
        print("basePlan.applicationUserName : " +
            purchaseParam.applicationUserName.toString());
      }

      try {
        await _inAppPurchasePlatform.buyNonConsumable(
            purchaseParam: purchaseParam);
        print("Purchase successful!");
      } catch (e, stacktrace) {
        print("Purchase failed: $e");
        print("Stacktrace: $stacktrace");
        rethrow; // Preserve the crash for further debugging
      }
    } catch (e) {
      print("Purchase error : $e");

      error.value = "Purchase error: $e";
      purchasePending.value = false;
      isLoading.value = false;

      String errorMessage = e.toString();
      String displayMessage = '';

      // Check if the error contains the specific message
      if (errorMessage.contains('storekit_duplicate_product_object')) {
        displayMessage =
            'There is a pending transaction for the same product identifier. Please either wait for it to be finished or finish it manually using `completePurchase` to avoid edge cases.';
      } else {
        displayMessage = 'An unexpected purchase error occurred: $errorMessage';
      }

      Get.snackbar(
        "Something went wrong!",
        displayMessage,
        snackPosition: SnackPosition.BOTTOM,
      );
      return;
    } finally {
      print("Purchase finally : ");
      isPurchasing.value = false; // Set to false when purchase is done
      // isLoading.value = false;
    }
  }

I am learning Flutter and implemented the in_app_purchase for for Android and iOS, however it works fine into both platforms but having the below issue into iOS 18.3.1 . The version I have

in_app_purchase: ^3.1.13

I face this issue

flutter: Purchase successful!
flutter: Purchase finally :
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSNull length]: unrecognized selector sent to instance 0x20c8db910'
*** First throw call stack:
(0x1a266a5fc 0x19fbe5244 0x1a27c3174 0x1a266d5c8 0x1a266cef0 0x1a125bbf0 0x1cfc08f64 0x1cfc066a8 0x1cfc05d18 0x1cfc052f4 0x1cfc07811 0x1cfc09a29 0x1cfbe2ddd 0x1cfbe2ddd 0x1cfbe2ddd 0x1cfbde2c5 0x1cfbde419 0x1cfbde2c5 0x1adf8fe39)
libc++abi: terminating due to uncaught exception of type NSException

My source code

Future<void> purchasePlan(BasePlans basePlan, BuildContext context) async {
    try {
      isLoading.value = true;
      print("purchasePlan called : " + basePlan.id.toString());
      print("purchasePlan called : " + basePlan.productDetails!.title);

      if (basePlan.productDetails == null) {
        error.value = "Product not available for purchase.";
        print("Product not available for purchase");
        isLoading.value = false;
        return;
      }
      purchasePending.value = true;
      late PurchaseParam purchaseParam;

      if (Platform.isAndroid) {
        // Check for existing subscriptions
        final GooglePlayPurchaseDetails? oldSubscription =
            _getOldSubscription(basePlan.productDetails!, purchases);
        purchaseParam = GooglePlayPurchaseParam(
          productDetails: basePlan.productDetails!,
          changeSubscriptionParam: (oldSubscription != null)
              ? ChangeSubscriptionParam(
                  oldPurchaseDetails: oldSubscription,
                  replacementMode: ReplacementMode.withoutProration)
              : null,
        );
      } else {

        print("basePlan.productDetails id: " + basePlan.productDetails!.id);
        print("basePlan.productDetails title : " +
            basePlan.productDetails!.title);
        print("basePlan.productDetails description : " +
            basePlan.productDetails!.description);
        print("basePlan.productDetails price : " +
            basePlan.productDetails!.price);
        print("basePlan.productDetails  rawPrice: " +
            basePlan.productDetails!.rawPrice.toString());
        print("basePlan.productDetails  currencyCode: " +
            basePlan.productDetails!.currencyCode.toString());
        print("basePlan.productDetails  currencySymbol: " +
            basePlan.productDetails!.currencySymbol.toString());

        purchaseParam = PurchaseParam(
          productDetails: basePlan.productDetails!,
        );

        print("basePlan.purchaseParam : " + purchaseParam.productDetails.id);
        print("basePlan.applicationUserName : " +
            purchaseParam.applicationUserName.toString());
      }

      try {
        await _inAppPurchasePlatform.buyNonConsumable(
            purchaseParam: purchaseParam);
        print("Purchase successful!");
      } catch (e, stacktrace) {
        print("Purchase failed: $e");
        print("Stacktrace: $stacktrace");
        rethrow; // Preserve the crash for further debugging
      }
    } catch (e) {
      print("Purchase error : $e");

      error.value = "Purchase error: $e";
      purchasePending.value = false;
      isLoading.value = false;

      String errorMessage = e.toString();
      String displayMessage = '';

      // Check if the error contains the specific message
      if (errorMessage.contains('storekit_duplicate_product_object')) {
        displayMessage =
            'There is a pending transaction for the same product identifier. Please either wait for it to be finished or finish it manually using `completePurchase` to avoid edge cases.';
      } else {
        displayMessage = 'An unexpected purchase error occurred: $errorMessage';
      }

      Get.snackbar(
        "Something went wrong!",
        displayMessage,
        snackPosition: SnackPosition.BOTTOM,
      );
      return;
    } finally {
      print("Purchase finally : ");
      isPurchasing.value = false; // Set to false when purchase is done
      // isLoading.value = false;
    }
  }
Share Improve this question edited Mar 30 at 10:35 Vy Do 52.9k69 gold badges255 silver badges387 bronze badges asked Mar 30 at 6:01 Hindi Stories 686Hindi Stories 686 1 2
  • That exception says that the Length method was invoked on NSNull; most likely something that you think is a string, isn't. You need to symbolicate your stack trace or perhaps try running under the Xcode debugger – Paulw11 Commented Mar 30 at 8:06
  • will upgrading the flutter and dart work? – Hindi Stories 686 Commented Mar 30 at 8:41
Add a comment  | 

1 Answer 1

Reset to default 1

It usually occurs when you don't configure your product in your app store to connect correctly. The issue is due to multiple reasons, like your product has some missing info and it's still on pending for approval.

Check this:

  • The product exists in App Store Connect.

  • The product is correctly added in Xcode under App Store -> Subscriptions/In-App Purchases.

  • You are using the correct product identifier in your Flutter app.

  • The product is marked as "Ready to Submit".

  • You are logged into a sandbox account when testing purchases.

Also, try to update the package if you are using the old version.

flutter pub upgrade in_app_purchase

You can also handle the null check error in your app.

print("basePlan.productDetails id: " + (basePlan.productDetails?.id ?? "N/A")); print("basePlan.productDetails title: " + (basePlan.productDetails?.title ?? "N/A")); print("basePlan.productDetails description: " + (basePlan.productDetails?.description ?? "N/A")); print("basePlan.productDetails price: " + (basePlan.productDetails?.price ?? "N/A")); print("basePlan.productDetails rawPrice: " + (basePlan.productDetails?.rawPrice.toString() ?? "N/A")); print("basePlan.productDetails currencyCode: " + (basePlan.productDetails?.currencyCode ?? "N/A")); print("basePlan.productDetails currencySymbol: " + (basePlan.productDetails?.currencySymbol ?? "N/A"));
发布评论

评论列表(0)

  1. 暂无评论