Code Monkey home page Code Monkey logo

stripe-terminal-ios's Introduction

Stripe Terminal iOS SDK

Stripe Terminal enables you to build your own in-person checkout to accept payments in the physical world. Built on Stripe's payments network, Terminal helps you unify your online and offline payment channels. With the Stripe Terminal iOS SDK, you can connect to pre-certified card readers from your iOS app and drive a customized in-store checkout flow.

Get started with our integration guides and sample integration, or browse the SDK reference documentation.

Upgrading from an older version of the SDK? See our migration guide for guidance.

Requirements

The Stripe Terminal iOS SDK is compatible with apps supporting iOS 13 and above.

Try the example app

The iOS SDK includes an open-source example app, which you can use to familiarize yourself with the SDK and reader before starting your own integration.

To build the example app from source, you'll need to:

  1. Navigate to the Example folder, and open Example.xcworkspace (make sure to open the .xcworkspace and not the .xcodeproj).
  2. Navigate to our example backend and click the button to deploy it on Heroku.
  3. In AppDelegate.swift, set the URL of the Heroku app you just deployed.
  4. Build and run the app. The SDK comes with a simple reader simulator, so you can get started without any physical hardware.

Installation

We support CocoaPods and Swift Package Manager. If you prefer to install the library manually, please use the latest version from our releases page.

Swift Package Manager

In Xcode, select File > Swift Packages > Add Package Dependency and enter https://github.com/stripe/stripe-terminal-ios

CocoaPods

  1. If you haven't already, install the latest version of CocoaPods.

  2. Add this line to your Podfile:

pod 'StripeTerminal', '~> 3.0'
  1. Run the following command:
pod install

From now on, don't forget to use the *.xcworkspace file to open your project in Xcode, instead of the .xcodeproj file.

In the future, to update to the latest compatible version of the SDK, just run:

pod update StripeTerminal

Manual

  1. Navigate to our releases page, download StripeTerminal.xcframework.zip, and unzip it.

  2. Drag StripeTerminal.xcframework to the Frameworks, Libraries, and Embedded Content section of your Xcode project’s General settings. Make sure to select "Copy items if needed".

When new versions of the SDK are released, repeat the above steps to update your installation.

Configure your app

Location services must be enabled in order to use the iOS SDK. Add the following key-value pair to your app's Info.plist file:

  • Privacy - Location When In Use Usage Description
    • Key: NSLocationWhenInUseUsageDescription
    • Value: "Location access is required in order to accept payments."

Note: Stripe needs to know where payments occur to reduce risks associated with those charges and to minimize disputes. If the SDK can’t determine the iOS device’s location, payments are disabled until location access is restored.

For your app to run in the background and remain connected to the reader, add this key-value pair to your Info.plist file:

  • Required background modes
    • Key: UIBackgroundModes
    • Value: bluetooth-central (Uses Bluetooth LE accessories)
    • Note the value is actually an array that you will need to add bluetooth-central to.

For your app to pass validation when submitting to the App Store, add the following key-value pairs as well:

  • Privacy - Bluetooth Always Usage Description
    • Key: NSBluetoothAlwaysUsageDescription
    • Value: "This app uses Bluetooth to connect to supported card readers."

Previous API References

We maintain an archive of the API reference for the previous major version.

stripe-terminal-ios's People

Contributors

aliriaz-stripe avatar bg-stripe avatar bric-stripe avatar catriona-stripe avatar corin-stripe avatar danj-stripe avatar jasonzurita avatar jil-stripe avatar ls-philippe-casgrain avatar mindy-stripe avatar mkrager-stripe avatar nk-stripe avatar scottswezey avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

stripe-terminal-ios's Issues

Xamarin binding generated from 1.0.0 ios release is giving a "unrecognized selector sent to class"

Hi,
Basically, when i was working with the 1.0.0-rc2 sdk, everything was fine.
Now that i have upgraded to the 1.0.0 release and generated a new c# binding from it, i keep getting this error when calling properties in the SCPTerminal class to set the token provider.

Foundation.MonoTouchException: Objective-C exception thrown. Name: NSInvalidArgumentException Reason: +[SCPTerminal hasTokenProvider]: unrecognized selector sent to class 0x109d089b0
Native stack trace:
0 CoreFoundation 0x000000018c97a9a4 + 252
1 libobjc.A.dylib 0x000000018bb539f8 objc_exception_throw + 56
2 CoreFoundation 0x000000018c89c214 + 0
3 CoreFoundation 0x000000018c9801d4 + 1408
4 CoreFoundation 0x000000018c981e6c _CF_forwarding_prep_0 + 92
5 Cirro.iOS 0x00000001080a775c _ZN7plcrash2MS5async24dwarf_cfa_state_iteratorIyxE4nextEPjPNS1_28plcrash_dwarf_cfa_reg_rule_tEPy + 89385908
6 Cirro.iOS 0x000000010809bd40 _ZN7plcrash2MS5async24dwarf_cfa_state_iteratorIyxE4nextEPjPNS1_28plcrash_dwarf_cfa_reg_rule_tEPy + 89338264
7 Cirro.iOS 0x0000000102c85d40 _ZN7plcrash2MS5async24dwarf_cfa_state_iteratorIyxE4nextEPjPNS1_28plcrash_dwarf_cfa_reg_rule_tEPy + 1167768
8 Cirro.iOS 0x0000000106688ae0 _ZN7plcrash2MS5async24dwarf_cfa_state_iteratorIyxE4nextEPjPNS1_28plcrash_dwarf_cfa_reg_rule_tEPy + 61996856
9 Cirro.iOS 0x0000000102fd084c _ZN7plcrash2MS5async24dwarf_cfa_state_iteratorIyxE4nextEPjPNS1_28plcrash_dwarf_cfa_reg_rule_tEPy + 4619428
10 Cirro.iOS 0x000000010667315c _ZN7plcrash2MS5async24dwarf_cfa_state_iteratorIyxE4nextEPjPNS1_28plcrash_dwarf_cfa_reg_rule_tEPy + 61908404
11 Cirro.iOS 0x00000001066a9d98 _ZN7plcrash2MS5async24dwarf_cfa_state_iteratorIyxE4nextEPjPNS1_28plcrash_dwarf_cfa_reg_rule_tEPy + 62132720
12 Cirro.iOS 0x0000000102fd013c _ZN7plcrash2MS5async24dwarf_cfa_state_iteratorIyxE4nextEPjPNS1_28plcrash_dwarf_cfa_reg_rule_tEPy + 4617620
13 Cirro.iOS 0x000000010667c8a4 _ZN7plcrash2MS5async24dwarf_cfa_state_iteratorIyxE4nextEPjPNS1_28plcrash_dwarf_cfa_reg_rule_tEPy + 61947132
14 Cirro.iOS 0x0000000103418b60 _ZN7plcrash2MS5async24dwarf_cfa_state_iteratorIyxE4nextEPjPNS1_28plcrash_dwarf_cfa_reg_rule_tEPy + 9109432
15 Cirro.iOS 0x0000000103418984 _ZN7plcrash2MS5async24dwarf_cfa_state_iteratorIyxE4nextEPjPNS1_28plcrash_dwarf_cfa_reg_rule_tEPy + 9108956
16 Cirro.iOS 0x00000001033f14c4 _ZN7plcrash2MS5async24dwarf_cfa_state_iteratorIyxE4nextEPjPNS1_28plcrash_dwarf_cfa_reg_rule_tEPy + 8947996
17 Cirro.iOS 0x00000001033ec4ac _ZN7plcrash2MS5async24dwarf_cfa_state_iteratorIyxE4nextEPjPNS1_28plcrash_dwarf_cfa_reg_rule_tEPy + 8927492
18 Cirro.iOS 0x0000000105ceefa8 _ZN7plcrash2MS5async24dwarf_cfa_state_iteratorIyxE4nextEPjPNS1_28plcrash_dwarf_cfa_reg_rule_tEPy + 51930112

Also please see my ApiDefinition.cs and Structs.cs here.
thanks!

Can't archive Terminal to avoid reconnect

I'm attempting to store the terminal object in NSUserDefaults by archiving and unarchiving, but since it doesn't support the NSCoding protocol, it of course can't be done.

I think this should be supported unless there's another way to keep from having to break a reader connection on a crash

-[SCPTerminal readSource:delegate:completion:] errors and then succeeds

After updating from b5 to b6, -[SCPTerminal readSource:delegate:completion:] seems to error at first, and then it succeeds. The calling function does not get called twice. I'm using it like this:

- (void)readCardWithoutCharging {
    SCPReadSourceParameters *params = [[SCPReadSourceParameters alloc] init];
    [SCPTerminal.shared readSource:params delegate:self completion:^(SCPCardPresentSource * _Nullable source, NSError * _Nullable error) {
        if (error) {
            NSLog(@"readSource error: %@", error);
        } else {
            NSLog(@"readSource stripeID: %@", source.stripeId);
        }
    }];
}

Just wondering if this is a bug in b6 or if I'm doing something wrong here.

I also see that the docs discourage the use of -[SCPTerminal readSource:delegate:completion:] in general. I need to be able to send a payment source to our backend. Should I be using collectPaymentMethod:delegate:completion: for this, and then simply leave the PaymentIntent unconfirmed?

Inconsistent error types across different parts of the SDK.

This is api feedback/request and not anything blocking…

There are inconsistencies in the error types used by the SDK. Things like SCPAttachSourceError, SCPReadSourceError, SCPConfirmError all subclass NSObject. Many of the callback blocks (SCPActivationTokenCompletionBlock, SCPCardSourceCompletionBlock, etc…) pass NSError instead. This requires a fair bit of type coercion on our end to bubble errors up to our application layer for display to the user.

If possible, I'd request that all error types use NSError or Swift Error types. Again, not a major issue but would make the SDK interface more consistent.

Module compiled with Swift 5.0.1 cannot be imported by the Swift 5.1 compiler

I am trying to implement Stripe terminal in my project which is compiled in Xcode 11.1.
I have downloaded the example application and getting the following error :
Module compiled with Swift 5.0.1 cannot be imported by the Swift 5.1 compiler
on Import static framework

please provide the support for the latest swift version.

Card reader does not accept swipe method when using insert method failed at first time

I faced with an issue when collect payment on stripe terminal example app. This is these steps to reproduce that:

  • Assumed that application already connected with card reader successfully
  • Go to: Collect card payment
  • Leave default amount value and tap collect payment button
  • The log is waiting for collect payment method: Swipe / Insert / Tap
  • Insert test card into card reader make sure that is using wrong slide => The log should request user "Try another read method" -> Swipe / Insert
  • From now, i Swipe the test card many times but card reader could not detect that method
  • Insert test card as correct way again, then the collect payment is success

The thing I'm confusing here is the Try another read method request user using Swipe / Insert method but actually Swipe method could not use any more. Could we please fix that by provide another request payment method "Insert" only or keep that request message but allow user Swipe test card?

The legacy build system does not support building projects with Swift when SWIFT_ENABLE_LIBRARY_EVOLUTION is enabled.

Summary

Can't compile Example code on macOS Mojave 10.14.6 with XCode Version 11.3.1 (11C504). Overcame some of the issue I was having by using Legacy Build System. But now I'm getting

The legacy build system does not support building projects with Swift when SWIFT_ENABLE_LIBRARY_EVOLUTION is enabled.

Code to reproduce

iOS version

macOS Mojave 10.14.6

Installation method

Downloaded Zip file from this repository and extracted it.

SDK version

PODS:

  • StripeTerminal (1.0.3)

DEPENDENCIES:

  • StripeTerminal (= 1.0.3)

SPEC REPOS:
trunk:
- StripeTerminal

SPEC CHECKSUMS:
StripeTerminal: ec7ecf250d87c6a8218234db6d35f9c46b81c237

PODFILE CHECKSUM: c8d53a9588adde36100270e617a5658e3669ec4c

COCOAPODS: 1.8.4

Other information

This is my first time using XCode/Swift. Usually use Python with stripe but need a mobile solution.

DiscoverReaders always return a list of one device

Info: im using a xamarin binding generated from release 1.0.0
Basically, the DiscoverReader method always returns a list of one device even though i have two perfectly working devices up and running and ready to be paired.
I know both of these devices are perfectly fine because of i have been reading and processing test payments on them without any major difficulty.

Now i'm trying to build a Pairing UI so that if my user has two devices, they can choose which device to connect to. And the problem is I can only receive one device from the scanning. please see my discoverreader code.

        public void DiscoverBBPOSReaders()
        {
            dialogcount = 0;
            try
            {
                if (aConnectedReaderStatus == SCPConnectionStatus.NotConnected)
                {
                    var config = new SCPDiscoveryConfiguration(SCPDeviceType.SCPDeviceTypeChipper2X, SCPDiscoveryMethod.Proximity, false);
                    discoverCancelable = SCPTerminal.Shared.DiscoverReaders(config, this, HandleConnectTerminalError);
                }
                else if (aConnectedReaderStatus == SCPConnectionStatus.Connected)
                {
                    SCPTerminal.Shared.DisconnectReader(HandleDisconnectTerminalError);
                }
                else
                {
                    var dialogService = Core.ViewModels.Base.ViewModelLocator.Instance.Resolve<IDialogService>();
                    dialogService.ShowToast("Reader is connecting. Please wait");
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

I have tried setting SCPDiscoveryMethod to be both Proximity and Scan, but i still get a list of one device.
Do we know if this is a common issue and that it has been fixed in 1.0.1 or 1.0.2 releases?

Adding "stripeAccount" param for direct charges fails the transaction

When I try to create a direct charge on behalf of a connected (stripe connect) account, I recieve an error.

I added to the paymentParams the following param (after initialization of the params with amount and currency) :

paymentParams.stripeAccount = "[some_stripe_connect_acct_id]"

I recieve :

Confirm PaymentIntent Failed
No such paymentIntent: [some_payment_intent_id]

  • btw, destination charges for the same account are working

screenshots :

screen shot 2018-10-30 at 10 50 50 pm

screen shot 2018-10-30 at 10 51 08 pm

Connecting to a reader from didUpdateDiscoveredReaders puts the SDK in an unrecoverable state

We found a scenario that causes the SDK to go into an unrecoverable state and therefore requires our app to be force-quit in order to connect to a reader.

For context, we're currently only using one reader, so we've been calling connectReader once a reader is returned in didUpdateDiscoveredReaders.

To reproduce:

  1. Move the device out of proximity from the Chipper 2X (~4ft).
  2. Invoke discoverReaders on the terminal using .bluetoothProximity while the device is out of proximity.
  3. Wait 4-5 seconds.
  4. Move the device next to the Chipper 2X.

Calling connectReader in didUpdateDiscoveredReaders will then cause the connection to fail with the following error:

Failed to connect to reader: Error Domain=com.stripe-terminal Code=302 "An incompatible reader was detected, see the docs for a list of supported devices." UserInfo={NSLocalizedDescription=An incompatible reader was detected, see the docs for a list of supported devices., com.stripe-terminal:Message=An incompatible reader was detected, see the docs for a list of supported devices.}

Canceling the discovery and then attempting to re-discover will consistently fail with the same error. It's worth noting that didUpdateDiscoveredReaders is never invoked again and that subsequent errors occur from the discoverReaders completion block. At this point the only way the app can connect to a reader is by force-quitting and restarting (thereby creating a new instance of the terminal).

Also worth noting that this connection failure happens regardless of if connectReaders is called on the first or second invocation of didUpdateDiscoveredReaders. This error doesn't appear to occur when the device is within proximity when the initial discovery begins.

Workarounds for the moment appear to be:

  1. Wrap the connectReaders call in DispatchQueue.main.async { ... }.
  2. Select the reader from a list, even though there's always only one possible reader.

We will likely go with the recommended approach of selecting the reader from the list, but I still think this issue should be fixed considering we couldn't find an obvious way to recover. Thanks!

Add support for Mac Catalyst

It appears that this framework will not build for Mac Catalyst. It would be nice if this was possible. I am currently building an iOS application that consumes this framework and it would be nice to port to Mac with Catalyst.

error: Building for Mac Catalyst, but the linked and embedded framework 'StripeTerminal.framework' was built for iOS + iOS Simulator. You may need to restrict the platforms for which this framework should be linked and embedded in the target editor, or replace it with an XCFramework that supports both platforms.

Possibly related:

stripe/stripe-ios#1404

Thank you for considering this!

Software caused connection abort since b6 upgrade

Since upgrading to b6, I've noticed that I receive this error message intermittently "The operation couldn’t be completed. Software caused connection abort", but, on previous version (b5) I do no. Could a change in code from b5 to b6 be directly related to: https://github.com/AFNetworking/AFNetworking/issues/4279

If so, can one of the work-arounds be implemented as it's causing a lot of pain points resulting in a lot of orphan payment intents. For context, I have a hybrid app that has a WKWebView that communicates through a bridge. I connect to the terminal natively, I receive a payment intent secret from the web via bridge and restore it natively, I then process the payment intent natively (collectPaymentMethod then confirmPaymentIntent), then send payment intent id to the web via bridge to capture. I believe during or after successfully processing, this is above error is causing some network hangups causing things happening on the web to fail, such as capturing, resulting to orphans. This context is just meant to help identify the problem and obviously leaves out X factors on why I need to capture on the web. Let's just say for the sake of this ticket, that's not an option, yet.

Thank you!

Commands fail when triggered from completion block

Steps

  1. create a payment intent
  2. call collectPaymentMethod(paymentIntent:delegate:completion:)
  3. call cancel(completion:) on the returned Cancelable
  4. inside the completion block, call cancelPaymentIntent(_:completion:)

Expected

  • No errors thrown in the cancelPaymentIntent completion block
  • Payment intent is canceled

Actual

  • cancelPaymentIntent completion block is called with error:
Could not execute createRefund because the SDK is busy with another command: collectPaymentMethod
  • Payment intent is not canceled

Workaround

Delay calling cancelPaymentIntent(_:completion:) (step 4) by 5 seconds

Xamarin Binding Library

Attempting to generate a Xamarin binding library using the PublicHeaders alone auto-generates a binding file that does not build without significant work. With the release of the Android SDK, cross-platform is a use case that we are very much interested in and it would be great if it was a supported option going forward.

For example, Objective Sharpie generates the following amount of warnings in attempting to create a binding.
107 instances to verify for ConstantsInterfaceAssociation
127 Instanced of MethodToProperty
23 instances of StronglyTypedNSArray
2490 Instances of PlatformInvoke

Unzipped version of framework

We manage our dependencies using submodules and link 3rd party frameworks directly from that using the hash to control exactly what we link into our app.

Because the framework is committed zipped in the repo we can't use it as it. Having a pre-build phase that unzips the file makes it really impractical as it'll invalidate the linking phase if when we rebuild our app with no changes.

I'm not sure why it is zipped in the first as the example folder contains another copy that isn't zipped. If space is the concern I'd suggest zipping the example folder and keeping the "real" framework unzipped.

requestLocation fails

Working on getting the iOS side complete for our Xamarin app. I can discover readers, connect, check status, see my terminal token client being called, all of that is working. When I try to call ProcessPayment I never get a call back to my method.

I enabled verbose logging, after calling ProcessPayment these lines are emitted. Removed the IDs from the events even though this was all the test keys and simulated reader. I can see the Payment Intent is set to a Requires Confirmation, but I don't see the /confirm call in the dashboard like I would for the Android side to know it was able to process the payment.

command=processPayment event=processPayment_completion_start intent_status=requires_confirmation last_request_id=req_XXXXXXXXXXXX
command_in_progress=processPayment event=state_change last_request_id=req_XXXXXXXXXX
event=state_change last_request_id=req_XXXXXXXX logpoint_level=info payment_intent=pi_XXXXXXXXX payment_status=Processing
event=processPayment_completion last_request_id=req_XXXXXXX logpoint_level=info payment_intent=pi_XXXXXXXXX payment_intent_status=requires_confirmation reader=rdr_XXXXXXXXXXXXXXXXX scope=SCPPaymentSession sdk_version=1.0.0
event=requestLocation last_request_id=req_XXXXXXXXXXXX

The Payment Intent ID and Request ID match up to what I see in the Stripe dashboard. Location services is enabled for the simulator, Location access is enabled for the app, and Location When In Use is in the Info.plist. I looked into location since that was the last call. Nothing else is emitted from the logs after the event=requestLocation event.

Ability to disable EMV payments for readSource

If you are trying to store a users card for later use by using the readSource method you can only convert the token from a card_present to card source if it is not a contactless EMV payment. The difficult part being that with the Chipper 2X it's so sensitive that it will many times pickup the contactless before the chip if you are fiddling to get it in. Would be nice to have a way to disable EMV if you are expecting to store the source so as to avoid this issue in the field.

"Store information missing" error during terminal.connect can leave reader is stuck in "SDK is busy executing another command" state, unable to cancel

We had our backend misconfigured on the activate token request. The backend request received a token, but when passing that token to the terminal it left the device stuck in a "busy executing another command" state.

The error is returned from a call to terminal.connect's SCPReaderCompletionBlock with localizedDescription :Store information missing. Please pass the required store_name and address params when creating a an activation token via v1/pos_activation_token. Subsequent attempts to re-rediscover or do anything else with the SDK, including cancelling the initial discoverReaders SCPCancelable, receives a response of The SDK is busy executing another command.

I'm not sure this will happen much in practice once our backend issue is resolved, but this required restarting the app to make the reader able to be communicated with again. It would be preferable if the initial call to v1/pos_activation_token could fail if the store info isn't provided rather than waiting for it to be used by the terminal.

Example app (and SDK) using Chipper2X requires NSBluetoothAlwaysUsageDescription for iOS 13

From a fresh pull of the latest Example app on Xcode 11 running iOS 13, if I launch and tap Discover Readers, I get the following log output:

2019-11-08 09:48:11.608186-0800 Example[4208:1396193] [access] This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSBluetoothAlwaysUsageDescription key with a string value explaining to the user how the app uses this data.

If looks like the SDK doesn't only require the NSLocationWhenInUseUsageDescription key, but also the NSBluetoothAlwaysUsageDescription key for iOS 13 deployments. When I add the NSBluetoothAlwaysUsageDescription key to my Info.plist, everything works fine.

<key>NSBluetoothAlwaysUsageDescription</key>
	<string>Bluetooth access is required in order to connect to supported bluetooth card readers.</string>
	<key>NSBluetoothPeripheralUsageDescription</key>
	<string>Bluetooth access is required in order to connect to supported bluetooth card readers.</string>

Looks like the example and documentation needs updating to reflect this.

Cannot reconnect to a reader after disconnecting

We're unable to reconnect to a reader after disconnecting.

To reproduce:

  1. Discover readers (we're using .bluetoothProximity).
  2. Connect to a reader.
  3. Disconnect from the reader by calling disconnectReader on the terminal instance.
  4. Discover readers again and try to re-connect to the reader (we only have one reader so we're connecting to the same one again).

The first time we try to reconnect, it fails with:

Error connecting to reader: Error Domain=com.stripe-terminal Code=151 "There was an error communicating with the ConnectionTokenProvider." UserInfo={NSLocalizedDescription=There was an error communicating with the ConnectionTokenProvider., com.stripe-terminal:Message=There was an error communicating with the ConnectionTokenProvider.}

All subsequent attempts to discover and reconnect fail with a different error:

Error connecting to reader: Error Domain=com.stripe-terminal Code=302 "An incompatible reader was detected, see the docs for a list of supported devices." UserInfo={NSLocalizedDescription=An incompatible reader was detected, see the docs for a list of supported devices., com.stripe-terminal:Message=An incompatible reader was detected, see the docs for a list of supported devices.}

The only way we're able to reconnect after calling disconnectReader is by force-quitting the app and restarting (thereby creating a new terminal instance).

BUG: reconnect issue when Bluetooth toggled on/off

Bug: reconnect fails to persist when bluetooth toggled on/off

Workflow to reproduce:

  1. Discover Readers
  2. Selected Reader and Connect (Connected)
  3. Check Connection Status (Connected)

Up to this point all is fine. I have a background process that periodically checks the connection status as a hack solution to keep the device on and connected when not in use due to customer feedback of always having to reconnect after a period of time. Device remains connected when here.

If the device is put to sleep and the connection closes, I have a modal view which prompts the user to turn the reader on and bring near the device.

  1. Check Connection on Device Wakeup (Not Connected)
  2. Show Modal
  3. Discover Readers (opens on modal show)
  4. Reconnect to Previous Reader (auto connects on finding device using saved serial number: Connected)
  5. Repeat background process to keep reader on (Connected)

Here is where the issue arises.

  1. Connect to Device and Initiate background process
  2. Turn off bluetooth
  3. Check Status (background, Not Connected, Bluetooth Error)
  4. Show Modal to prompt user to turn bluetooth on and retry connection via user confirmation
  5. Show Reconnection modal as per previous scenario
  6. Discover Reader (auto on modal show)
  7. Reconnect to Reader (auto connects on finding device using saved serial number: Connected)
  8. Repeat background process (Not Connected)

In this step 8 in the background process, the Terminal.shared.connectedReader is nil.

I have attempted wrapping the connection in DispatchQueue.main.async { ... } but still end up with the same issue. The Terminal instance does not save the connected reader and no disconnect events get fired.

Crashing at collectPaymentMethod

After upgrading to V1 the app is now crashing when calling collectPaymentMethod
Payment intent is created ok, but as soon as I call collectPaymentMethod the app crashes with error "terminating with uncaught exception of type NSException"

Trying to get further detail through try catch but so far haven't been able to get the underlying error.

Nb. This is a react-native app with the framework manually installed.

Add "stripeAccount" param for retrievePaymentIntent

I believe this issue is similar to this issue: #10

I am trying to retrieve a payment intent that I have created on my server for a connected account. I am unable to retrieve the payment intent because it needs the stripeAccount option to find it.

I have verified that with the Node SDK I can do the following and find the payment intent.
try { const found = await stripe.paymentIntents.retrieve(paymentIntent.id, { stripe_account: stripeAcctId }) console.log('<><><><>: found', found) } catch (error) { console.log('<><><><>: error', error) }

If I do leave off the stripe_account though I receive the same error as with the terminal.

Thanks!

Version
stripe-terminal-ios: '1.0.0-rc1'

Microphone access - is it an absolute must?

Hi!

I understand that the README states:

Note: Although we do not currently support any audio-jack card readers, you'll still need to add a Microphone Usage Description to your Info.plist to pass App Store validation, as our underlying hardware SDK accesses these APIs. Since the SDK never actually uses microphone access, your users will never see a prompt for the microphone permission.

My question is, is there any possibility to not use these APIs? It's strange to have to explain this to people, and potentially to Apple in the future.

If we can, splitting out the part of the library where we do use the microphone into its own framework (subspecs etc.) would be ideal, so clients can opt in if they choose to.

Screen locks during reader update

The update interface suggests that you should not leave the update screen while the chipper 2x device is being updated, and that you should keep the device powered on and in range.

While this all makes sense, I found that the screen timed out and my device locked itself while installing the update. Should the app should keep the screen on and prevent automatic device locking during the update period? Would you accept a pull request to keep to prevent idle timeouts while an update is being installed?

"This application does not have the required permissions for this endpoint"

I'm getting this error when trying to use -[SCPTerminal readReusableCard:delegate:completion:]:

This application does not have the required permissions for this endpoint on account 'acct_abcd1234'. The required permissions are not available for use by Connect applications.

This used to work, so it seems like something changed.

Verifone P400 Support

** FEATURE REQUEST **
Is it possible to have the iOS SDK also work with the Verifone P400?

Tipping feature

Hey guys, any news on supporting tipping when capturing a payment intent?

feature request: adjust amount

In the flow of creating payment intent and capture the intent, there is no way to make adjust to the amount. In real cases of dining in restaurant, we need to allow customers to add tip (adjust the amount) before capturing. Is there a way to do it?

Timeout not working

When discovering readers, no matter what I set for a timeout value on the discovery config, the scan never calls the completion handler. I've tested numerous timeout values in the low single and double digit values without a reader turned on and the scanning never completes. Turning on a reader after more than a minute still provides results in didUpdateDiscoveredReaders, showing the scan is still active.

Direct creation of PaymentMethods for type 'card_present' is disallowed

I've worked through the rc1 release doc, but now I'm getting this error when running -[SCPTerminal processPayment:completion:]:

Direct creation of PaymentMethods for type 'card_present' is disallowed

The error object looks like this:

<SCPProcessPaymentError: 0x2825ea040; requestId = req_F8aJfHnf2qPCws; code = 6000; paymentIntent = <SCPPaymentIntent: 0x2814424c0; amount = 100; currency = usd; created = 2019-04-24 17:38:06 +0000; charges = (
); metadata = {
}; status = requires_payment_method; stripeId = xxxxx>; requestError = Error Domain=com.stripe-terminal Code=9020 "Direct creation of PaymentMethods for type 'card_present' is disallowed." UserInfo={com.stripe-terminal:Message=Direct creation of PaymentMethods for type 'card_present' is disallowed., com.stripe-terminal:StripeAPIRequestId=req_F8aJfHnf2qPCws, com.stripe-terminal:StripeAPIPaymentIntent=<SCPPaymentIntent: 0x2814424c0; amount = 100; currency = usd; created = 2019-04-24 17:38:06 +0000; charges = (
); metadata = {
}; status = requires_payment_method; stripeId = xxxxx>, com.stripe-terminal:StripeAPIErrorType=invalid_request_error, com.stripe-terminal:HttpStatusCode=400, NSLocalizedDescription=Direct creation of PaymentMethods for type 'card_present' is disallowed.}>

I'm using the Stripe Point of Sale test card fwiw.

Allow exporting logs with support for CocoaLumberjack

The existing device logging prints to console. This helps while debugging but will be harder to get the logs on a live device with app in release mode. It would be better if we can have some logger like CocoaLumberjack integrated in the SDK. This gives more flexibility of handling logs and differentiating these with our app logs.

stuck on "Could not execute discoverReaders because the SDK is busy with another command: discoverReaders."

There seems to be a scenario where the SDK is stuck on this error and its not recoverable.

Steps to replicate is:

  1. Do a discoverReader
  2. on terminal:didUpdateDiscoveredReaders do connectReader:
  3. If during this connection process something happen that causes it to fail (easiest is to turn off the device during the connection process), subsequent discoverReader: calls will fail. and the initial discoverReader cancelable object can not be cancelled because it is already completed.

POS Charge object is not compatible with existing charge objects

Some fields in the source of a charge object using the chipper have been moved to a different location than charges made with other methods. Instead of being within source they are now nested in source.charge_present. This complicates processing both types of charges and breaks existing implementations.

Fields that were previously existing in source should remain in source. New fields related to card_present should appear in card present.
eg. Charge created from a regular magnetic stripe reader (API 2016-07-06) :

{
  ...
"source": {
    "id": "card_1CxQ1YH4tO2ryinzlvUYBsbd",
    "object": "card",
    "address_city": null,
    "address_country": null,
    "address_line1": null,
    "address_line1_check": null,
    "address_line2": null,
    "address_state": null,
    "address_zip": null,
    "address_zip_check": null,
    "brand": "Visa",
    "country": "US",
    "customer": null,
    "cvc_check": null,
    "dynamic_last4": null,
    "exp_month": 6,
    "exp_year": 2021,
    "fingerprint": "oERpmQ2WiWUFGrdF",
    "funding": "credit",
    "last4": "0077",
    "metadata": {},
    "name": "TEST/TEST",
    "tokenization_method": null
  }
...
}

eg. Charge created from a Stripe POS Chipper (API 2016-07-06) :

{
  ...
  "source": {
    "id": "src_1CwtsVH4tO2ryinz5O9GhSWg",
    "object": "source",
    "amount": null,
    "card_present": {
      "pos_device_id": "pos_vendor_id_AC9EAD1C-3AF4-4042-942D-44C91E85AD67",
      "read_method": "magnetic_stripe_track2",
      "reader": "rdr_1Cu4i0H4tO2ryinz18FHjBn1",
      "brand": "Visa",
      "card_automatically_updated": false,
      "country": "US",
      "exp_month": 12,
      "exp_year": 2022,
      "fingerprint": "NICxl5nErmOalW7G",
      "funding": "credit",
      "last4": "9969",
      "data_type": null,
      "evidence_transaction_certificate": null,
      "evidence_customer_signature": null
    },
    "client_secret": "src_client_secret_DNfC2NPqATZj2oHgjw3CY7Zl",
    "created": 1533743235,
    "currency": null,
    "flow": "none",
    "livemode": false,
    "metadata": {
    },
    "owner": {
      "address": null,
      "email": null,
      "name": null,
      "phone": null,
      "verified_address": null,
      "verified_email": null,
      "verified_name": null,
      "verified_phone": null
    },
    "statement_descriptor": null,
    "status": "consumed",
    "type": "card_present",
    "usage": "single_use"
  }
  ...
}

Fields that should be moved from card_present back to source include:

  • brand
  • exp_month
  • exp_year
  • fingerprint
  • country
  • last4
  • funding

Thanks.
=Blair.

Add cardholder name to card_present info

FEATURE REQUEST
It would be useful to have the cardholder's name add the to the card_present data. This information is available when using other readers such as Magtek.

beta to v1 issue? (terminal must be used on main thread)

I'm running into an issue migrating to processPayment, I've followed the instructions as per https://stripe.com/docs/terminal/payments#create-client-ios however keep running into "processPayment was called with an unknown or invalid PaymentIntent"

[SCPTerminal.shared createPaymentIntent:params completion:^(SCPPaymentIntent *createResult, NSError *createError) {
    if (createError) {
      RCTLog(@"createPaymentIntent failed: %@", createError);
    } else {
      RCTLog(@"createPaymentIntent succeeded");
      
      //Notify the client the reader is ready for payment
      if (hasCardReaderListeners) {
        [self sendEventWithName:@"StripePayPresentCard" body:[self PaymentIntentToDictionary:createResult]];
      }
      
      self -> collectCancelable = [SCPTerminal.shared collectPaymentMethod:createResult delegate:self completion:^(SCPPaymentIntent * _Nullable collectResult, NSError * _Nullable collectError) {
          if (collectError) {
            RCTLog(@"collectPaymentMethod failed: %@", collectError);
          } else {
            RCTLog(@"collectPaymentMethod succeeded");
            
            //Notify the client the to remove card
            if (hasCardReaderListeners) {
              [self sendEventWithName:@"StripePayRemoveCard" body:[self PaymentIntentToDictionary:createResult]];
            }
            
            //Process payment
            [SCPTerminal.shared processPayment:createResult completion:^(SCPPaymentIntent *processResult, SCPProcessPaymentError *processError) {
              if (processError) {
                RCTLog(@"processPayment failed: %@", processError);
                reject(@"", processError.localizedDescription, nil);
              } else {
                RCTLog(@"processPayment succeeded");
                if (processResult != nil) {
                  NSMutableDictionary* response = [self PaymentIntentToDictionary: processResult];
                  resolve(response);
                } else {
                  resolve(nil);
                }
              }
            }];
            
          }
        }];
    }
  }];

2019-07-06 12:04:54.833 [info][tid:main][CardReader.m:377] Display message resolve: Remove the presented card.
2019-07-06 12:04:55.835 [info][tid:main][CardReader.m:167] collectPaymentMethod succeeded
2019-07-06 12:04:55.837 [warn][tid:com.facebook.react.JavaScript] {"status":0,"stripeId":"pi_xxxxxxxxxxxxxxxxxxx","created":null,"amount":1125,"currency":"usd"}
2019-07-06 12:04:55.889 [info][tid:main][CardReader.m:177] processPayment failed: <SCPProcessPaymentError: 0x2811d2dc0; requestId = (null); code = 1530; paymentIntent = <SCPPaymentIntent: 0x282d90ae0; amount = 1125; currency = usd; created = 2019-07-06 16:04:35 +0000; charges = (
); metadata = {
}; status = requires_payment_method; stripeId = pi_1EtGNLLR511MwE0vwRxLNI8K>; requestError = (null)>
2019-07-06 12:04:56.109 [info][tid:main][CardReader.m:377] Display message resolve: Remove the presented card.

integrate_framework.sh: No such file or directory on build

I have followed the manual instruction steps to the letter and I get the following error when trying to build:

StripeTerminal.framework/integrate_framework.sh: No such file or directory
Command PhaseScriptExecution failed with a nonzero exit code

Note:

I have to check "Run script only when installing" under the Run Script build page in order to get it to build with no errors. Is this correct?

Simulator: "Access to location services is currently disabled"

I am getting the following error when running processPayment on an iOS simulator.

Access to location services is currently disabled. Location access is required to connect to a reader and create payments.

I have NSLocationWhenInUseUsageDescription in the Info.plist and I gave the app location permission when it asked.

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

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?

Does the SDK work in offline mode? (no internet connection)

I can't find any relevant information through Stripe Terminal Docs if this is possible or not. I assumed that if I have the option to "Store card for further use" I could just store that and when my internet connection resumes I'll process the payment.

I'm getting the "The SDK is not connected to the Internet." error almost doing anything through the SDK, even connecting to a reader (assuming I previously fetched a connection token).

My questions are:

  • Does the SDK require an active internet connection in order to work?
  • If not, how exactly I create a PaymentIntent from a Source?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.