Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't check the connection status of SCPTerminal unless it's already initialized #26

Closed
jacobrharris opened this issue Jan 31, 2019 · 13 comments
Assignees
Labels
integration Integration help

Comments

@jacobrharris
Copy link

Our app crashes and gives this error:

[StripeTerminal] ⚠️ An integration error was detected in your app. You can only set a token provider before requesting the shared Terminal instance for the first time. If you are trying to switch accounts in your app, refer to the documentation for the clearCachedCredentials method.

We're not trying to switch accounts. We want to re-use the existing SCPTerminal connection. The problem is that we have no way of knowing if SCPTerminal is already initialized. If we knew that it was already initialized, we wouldn't pass it the token provider.

This is how we start Terminal:

- (void)startStripeTerminal {
    self.stripeAPIClient = [[StripeAPIClient alloc] init];
    [SCPTerminal setTokenProvider:self.stripeAPIClient];
    SCPTerminal.shared.delegate = self;
    [self discoverReaders];
}

If I call [self startStripeTerminal] again, the app crashes with the above message. But I have to call it again because there's no way to check if SCPTerminal is already initialized without using SCPTerminal.shared, and if it's not initialized, accessing that property causes a crash.

Does that make sense? Am I caught in a chicken-and-the-egg cycle?

@bg-stripe
Copy link
Contributor

Hi @jacobrharris ,

We'll try to make the docs here clearer! In your app, you can either:

  1. Call [SCPTerminal setTokenProvider: earlier, e.g. when your app launches, in your AppDelegate's didFinishLaunchingWithOptions.
  2. Use dispatch_once to make sure setTokenProvider is only called once:
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    [SCPTerminal setTokenProvider:self.stripeAPIClient];
});

Hope that helps!

Ben

@jacobrharris
Copy link
Author

That does help. Thanks!

@jacobrharris
Copy link
Author

@bg-stripe
Ok, I'm back to thinking that this pattern is problematic. Above, I said we're not trying to switch accounts, but now that's exactly what we need to do. Putting the +[SCPTerminal setTokenProvider:] call in the AppDelegate means I can never change the token provider. So I thought about putting the call in our root view controller in -[UIViewController viewDidAppear:] and simply calling [SCPTerminal.shared clearCachedCredentials] first, but there's the problem again: I can't check to see if I'm already connected before accessing the .shared property or the app will crash. I really think there needs to be a way to do this.

@bg-stripe
Copy link
Contributor

Hi @jacobrharris !

You can't change the tokenProvider once you've set it. You should call Terminal.setTokenProvider once, and we recommend doing so early on (e.g. in your AppDelegate, when your app launches).

To switch accounts, you'll need to re-configure the same tokenProvider reference that you initially passed to the Terminal singleton. (e.g., so that it tells your backend to return a different key).

Hope that clears things up! We'll think about how to make the interface and documentation here clearer.

Best,
Ben

@bg-stripe
Copy link
Contributor

bg-stripe commented Feb 7, 2019

Another note (from the docs)

image

You should call clearCachedCredentials after configuring your tokenProvider to return a token for the new account. (Looks like you're calling clearCachedCredentials first).

So I thought about putting the call in our root view controller in -[UIViewController viewDidAppear:] and simply calling [SCPTerminal.shared clearCachedCredentials] first

@bg-stripe bg-stripe self-assigned this Feb 7, 2019
@bg-stripe bg-stripe added the integration Integration help label Feb 7, 2019
@troypayne
Copy link

@bg-stripe I'm having the same problem. My "StripeAPIClient" requires authentication to access my backend, which occurs after successfully logging in. I also do a check on launch of my application to see if the user is authenticated or not. Authentication is cached. If they aren't, it returns unauthorized. If they are, it returns authorized. As you can imagine, sometimes on launch they'll be unauthorized so the order of operation can get really screwed up without the ability to check if the Terminal.shared is set or not, so that I can properly clear it if it is.

@troypayne
Copy link

@bg-stripe any update here?

@bg-stripe
Copy link
Contributor

@troypayne – it sounds like you should:

  1. Call setTokenProvider at launch with your StripeAPIClient.
  2. Before a user logs in / your API client is authorized, your implementation of fetchConnectionToken can either return an error, or return a dummy connection token.
  3. After a user logs in, call clearCachedCredentials (this is important if you choose to return a dummy token in 2).

Hope that helps!

Note that for integration questions like this one, you can always email support-terminal@stripe.com, and they'll usually be able to respond much faster.

@troypayne
Copy link

@bg-stripe this results in a Locations prompt immediately on launch of my app, which is a poor experience. Can this be more contextual and prompt only at the very point it is needed (as suggested by Apple), certainly after there's confirmation of a valid token

@bg-stripe
Copy link
Contributor

That's good feedback! We'll think about changing the request location prompt to be more contextual (e.g. when you take your first payment) in the next SDK release.

@kenny-evitt
Copy link

kenny-evitt commented Apr 16, 2019

@bg-stripe Based on some tests, if the initial 'fetch connection token' call fails, trying to access the shared terminal singleton will fail (and, at least in my case, cause my app to crash).

(Interestingly, the crash doesn't happen immediately after accessing the singleton. It seems to occur sometime after the fetch-token call fails. I just emailed the Terminal support address about this too.)

I discovered that the problem was that my code wasn't passing a valid error object to the completion block in the fetch-connection method.

@loganthompson
Copy link

loganthompson commented Apr 22, 2019

That's good feedback! We'll think about changing the request location prompt to be more contextual (e.g. when you take your first payment) in the next SDK release.

This would be fantastic. The prompt itself is our biggest issue as well, and we would love to see that reconsidered. Thanks!

Update: Just saw that rc1 does this. Fantastic! Thanks, guys.

@bg-stripe
Copy link
Contributor

Hey folks! If you've had trouble checking whether a ConnectionToken provider has been set, you can now use the hasTokenProvider method, available in rc1.

https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPTerminal.html#/c:objc(cs)SCPTerminal(cm)hasTokenProvider

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
integration Integration help
Projects
None yet
Development

No branches or pull requests

6 participants