RevenueCat / purchases-ios

In-app purchases and subscriptions made easy. Support for iOS, watchOS, tvOS, macOS, and visionOS.
https://www.revenuecat.com/
MIT License
2.2k stars 295 forks source link

"Sign in with Apple ID" modal dialog (with user already signed into App Store app) when calling `purchasePackage` #3934

Open lukehutch opened 1 month ago

lukehutch commented 1 month ago

Describe the bug

When I run the following code, a dialog pops up saying "Sign in with Apple ID", asking for the username and password. There is no indication that the app didn't manually create a spoofed login dialog to capture the user's password (personally I would never enter my password into a dialog like this). I am signed into the App Store on the device (and I'm signed into the device with my Apple ID too), which makes the pop-up dialog look even more hokey.

 Future<void> _purchase(Package package) async {
  try {
    CustomerInfo customerInfo = await Purchases.purchasePackage(package);
    if (customerInfo.entitlements.all[_entitlementName]?.isActive ?? false) {
      logger.i('Subscription purchased: ${package.packageType}');
      // TODO
      showSnackBar('Subscription purchased!');
    }
  } on PlatformException catch (e) {
    var errorCode = PurchasesErrorHelper.getErrorCode(e);
    if (errorCode != PurchasesErrorCode.purchaseCancelledError) {
      logger.e('Error purchasing package', error: e);
    }
  }
}
  1. Environment
    1. Platform: iOS
    2. SDK version:
    3. StoreKit version: purchases_flutter 6.29.2
      • [ ] StoreKit 1 -- no idea
      • [ ] StoreKit 2 (enabled with usesStoreKit2IfAvailable(true)) -- no idea
    4. OS version: 17.4
    5. Xcode version: 15.4
    6. Device and/or simulator: iPhone SE 2nd edition
      • [x] Device
      • [ ] Simulator
    7. Environment: -- no idea, I'm just launching from the VS Code debugger. Sandbox?
      • [ ] Sandbox
      • [ ] TestFight
      • [ ] Production
    8. How widespread is the issue. Percentage of devices affected. 1/1
  2. Debug logs that reproduce the issue. Complete logs with Purchases.logLevel = .verbose will help us debug this issue.

(I'm not sure why, but await Purchases.setLogLevel(LogLevel.debug) is not outputting debug logs currently...)

  1. Steps to reproduce, with a description of expected vs. actual behavior

I just set up a standard subscription project, and I get the login prompt when I try to make a purchase.

  1. Other information (e.g. stacktraces, related issues, suggestions how to fix, links for us to have context, eg. stackoverflow, etc.)

  2. Additional context

RCGitBot commented 1 month ago

👀 We've just linked this issue to our internal tracker and notified the team. Thank you for reporting, we're checking this out!

rglanz-rc commented 1 month ago

Hey Luke, I think debug logs would be helpful here. You can't get them from VS Code itself, however. You'd use Xcode (we have instructions on how to do that here).

lukehutch commented 1 month ago

A screenshot

IMG_0042

lukehutch commented 1 month ago

@rglanz-rc

Hey Luke, I think debug logs would be helpful here. You can't get them from VS Code itself, however. You'd use Xcode (we have instructions on how to do that here).

Here are the Xcode logs:

nw_path_necp_check_for_updates Failed to copy updated result (22)
DEBUG: ℹ️ Vending Offerings from memory cache
DEBUG: ℹ️ This StoreProduct represents an SK1 product, the type of product cannot be determined, the value will be undefined. Use `StoreProduct.productCategory` instead.
DEBUG: ℹ️ This StoreProduct represents an SK1 product, the type of product cannot be determined, the value will be undefined. Use `StoreProduct.productCategory` instead.
DEBUG: ℹ️ This StoreProduct represents an SK1 product, the type of product cannot be determined, the value will be undefined. Use `StoreProduct.productCategory` instead.
DEBUG: ℹ️ This StoreProduct represents an SK1 product, the type of product cannot be determined, the value will be undefined. Use `StoreProduct.productCategory` instead.
DEBUG: ℹ️ This StoreProduct represents an SK1 product, the type of product cannot be determined, the value will be undefined. Use `StoreProduct.productCategory` instead.
DEBUG: ℹ️ This StoreProduct represents an SK1 product, the type of product cannot be determined, the value will be undefined. Use `StoreProduct.productCategory` instead.
DEBUG: ℹ️ This StoreProduct represents an SK1 product, the type of product cannot be determined, the value will be undefined. Use `StoreProduct.productCategory` instead.
DEBUG: ℹ️ This StoreProduct represents an SK1 product, the type of product cannot be determined, the value will be undefined. Use `StoreProduct.productCategory` instead.
DEBUG: ℹ️ This StoreProduct represents an SK1 product, the type of product cannot be determined, the value will be undefined. Use `StoreProduct.productCategory` instead.
DEBUG: ℹ️ This StoreProduct represents an SK1 product, the type of product cannot be determined, the value will be undefined. Use `StoreProduct.productCategory` instead.
DEBUG: ℹ️ This StoreProduct represents an SK1 product, the type of product cannot be determined, the value will be undefined. Use `StoreProduct.productCategory` instead.
DEBUG: ℹ️ This StoreProduct represents an SK1 product, the type of product cannot be determined, the value will be undefined. Use `StoreProduct.productCategory` instead.
tcp_input [C26.1.1.1:3] flags=[R] seq=4229067503, ack=0, win=0 state=LAST_ACK rcv_nxt=4229067503, snd_una=2382495487
tcp_input [C26.1.1.1:3] flags=[R] seq=4229067503, ack=0, win=0 state=CLOSED rcv_nxt=4229067503, snd_una=2382495487
tcp_input [C26.1.1.1:3] flags=[R] seq=4229067503, ack=0, win=0 state=CLOSED rcv_nxt=4229067503, snd_una=2382495487
tcp_input [C26.1.1.1:3] flags=[R] seq=4229067503, ack=0, win=0 state=CLOSED rcv_nxt=4229067503, snd_una=2382495487
container_create_or_lookup_app_group_path_by_app_group_identifier: client is not entitled
container_create_or_lookup_app_group_path_by_app_group_identifier: client is not entitled
container_create_or_lookup_app_group_path_by_app_group_identifier: client is not entitled
-[GMPx_GIPPseudonymousIDStore initializeStorage]: Shared App Groups unavailable
container_create_or_lookup_app_group_path_by_app_group_identifier: client is not entitled
-[GMPx_GIPPseudonymousIDStore initializeStorage]: Shared App Groups unavailable
container_create_or_lookup_app_group_path_by_app_group_identifier: client is not entitled
-[GMPx_GIPPseudonymousIDStore initializeStorage]: Shared App Groups unavailable
container_create_or_lookup_app_group_path_by_app_group_identifier: client is not entitled
-[GMPx_GIPPseudonymousIDStore initializeStorage]: Shared App Groups unavailable
(***)
DEBUG: ℹ️ Vending Offerings from memory cache
INFO: 💰 Purchasing Product 'click_2999_1m_1799_6m' from package in Offering 'subscriber'
DEBUG: ℹ️ Adding payment for product 'click_2999_1m_1799_6m'. 0 transactions already in the queue.
DEBUG: ℹ️ StoreKit1Wrapper (0x0000000302ffcc00) updatedTransaction: click_2999_1m_1799_6m 0
quic_recovery_pto PTO fired after validation

The part of the logs after (***) is what happened when I tried to purchase a product.

rglanz-rc commented 1 month ago

@lukehutch thanks for those, that all looks normal

That login prompt is normal for Sandbox (the environment you're in) sadly. In production, the user will only be prompted to log in if they don't have an active session in App Store, in Sandbox those sessions seem to have a shorter time to live so you're more likely to see the prompt to log in. That log in prompt comes straight from iOS, though, so there isn't much we can do about it.

As I mentioned, it's won't happen in production unless the user is legitimately logged out or the session is very stale.

vegaro commented 1 month ago

To add to what @rglanz-rc mentioned, if you're using a simulator (which I think you are), you need to use StoreKit config files to get purchases to work. You can read more about them in https://www.revenuecat.com/docs/test-and-launch/sandbox/apple-app-store#ios-14-only-testing-on-the-simulator. Not using Storekit config files in a simulator would cause that login dialog to show up over and over.

lukehutch commented 4 weeks ago

To add to what @rglanz-rc mentioned, if you're using a simulator (which I think you are), you need to use StoreKit config files to get purchases to work. You can read more about them in https://www.revenuecat.com/docs/test-and-launch/sandbox/apple-app-store#ios-14-only-testing-on-the-simulator. Not using Storekit config files in a simulator would cause that login dialog to show up over and over.

I'm not using the simulator right now, I'm using a physical iPhone.

However, I still tried to use the Sandbox. When I try to create a Sandbox tester account, following the info at that link, I get a nondescript error message:

image

That login prompt is normal for Sandbox (the environment you're in) sadly. In production, the user will only be prompted to log in if they don't have an active session in App Store, in Sandbox those sessions seem to have a shorter time to live so you're more likely to see the prompt to log in. That log in prompt comes straight from iOS, though, so there isn't much we can do about it.

Thanks for the info -- although even when I log in with my Apple credentials, I get an error message. Any ideas on what causes this or how to fix it?

PlatformException(2, There was a problem with the App Store., {userCancelled: false, message: There was a problem with the App Store., readableErrorCode: STORE_PROBLEM, readable_error_code: STORE_PROBLEM, code: 2, underlyingErrorMessage: An unknown error occurred}, null)

rglanz-rc commented 3 weeks ago

Are you using the app owner account to create the sandbox user? Not sure exactly why that's occurring in ASC.

As for the STORE_PROBLEM error, is that transient? It's indicative of a network issue and shouldn't persist.

lukehutch commented 2 weeks ago

@rglanz-rc Yes, I have only one Apple ID, and I used that to create the App Store Connect account and the subscription plans on that account.

No, the STORE_PROBLEM issue is not transient. I didn't previously notice, but there is an error before that:

DEBUG: ℹ️ StoreKit1Wrapper (0x00000003003c6340) removedTransaction: click_2999_1m_1799_6m (An unknown error occurred) ["NSUnderlyingError": Error Domain=ASDErrorDomain Code=500 "(null)" UserInfo={NSUnderlyingError=0x3029212c0 {Error Domain=AMSErrorDomain Code=100 "Authentication Failed" UserInfo={NSMultipleUnderlyingErrorsKey=(
    "Error Domain=AMSErrorDomain Code=2 \"Password reuse not available for account\" UserInfo={NSLocalizedDescription=Password reuse not available for account, NSLocalizedFailureReason=The account state does not support password reuse.}",
    "Error Domain=AMSServerErrorDomain Code=-5000 \"(null)\" UserInfo={failureType=-5000, m-allowed=false, pings=(\n), cancel-purchase-batch=true, customerMessage=The Apple\U00a0ID you entered couldn\U2019t be found or your password was incorrect. Please try again.}"
), NSLocalizedDescription=Authentication Failed, NSLocalizedFailureReason=The authentication failed.}}}, "NSLocalizedDescription": An unknown error occurred] 2

I am signing in using the correct username and password, but Apple ID login is not accepting it.

lukehutch commented 2 weeks ago

OK, I figured it out. I could have sworn I have created a test user before, but there wasn't one. I couldn't create a test user with the same email address as any existing Apple ID. The following tip worked though (basically you have to add or remove periods in the email account name to create a new email address that is an alias to an existing gmail account):

https://stackoverflow.com/a/29280842/3950982

This tip should be mentioned in the RevenueCat docs, since without it, if you don't have any gmail accounts without an associated Apple ID, you have to go create a whole new Gmail account just to create a test user.