iOS Integration Guide

Importing DyScan

The easiest way to integrate DyScan is by using CocoaPods, which is covered in this guide.

If you would rather include DyScan directly as a framework, see the instructions here. If you use Carthage as your dependency manager, see the instructions here.

Once we add your GitHub username to our organization, open up your Podfile and above the target add this line:

source 'https://github.com/dyneti/dyscan-podspec.git'

Then, inside the target with the other dependencies, add the appropriate line below for your specific version of Swift.

Swift 5.1
Swift 5.0
Swift 4.2
pod 'DyScan/5.1'
pod 'DyScan/5.0'
pod 'DyScan/4.2'

Include use_frameworks! in your Podfile if you have not done so already (see here for a sample Podfile). Then in a terminal in the directory of your iOS project, run

$ pod install

If 2FA is set up on your GitHub account, this step may fail. To rectify this, you will need to generate a personal access token in GitHub. This can be done by logging into GitHub and following the directions by navigating to Settings > Developer settings > Personal access tokens.

If your app does not already ask for camera permissions, add the key “NSCameraUsageDescription” (Privacy - Camera Usage Description) to your app's Info.plist file. You should set the value to be the string a user sees when they are prompted for the camera permission (e.g. To scan credit cards).

If you are getting an error like dyld: Library not loaded: @rpath/DyScan.framework/DyScan CocoaPods probably has not configured the dependency properly. In Pods/Target Support Files/Pods-{Project}/Pods-{Project}-frameworks.sh add the line install_framework "${PODS_ROOT}/DyScan/Swift5_1/DyScan.framework" in both the debug and release configurations (you should see many other similar lines). In "Embed Pods Frameworks" in your project's build phases, add ${PODS_ROOT}/DyScan/Swift5_1/DyScan.framework as an input path.

If you see an error like The 'your-app' target has frameworks with conflicting names: dyscan.framework then you may have just written pod 'DyScan', forgetting to specify which version of Swift you are using. Adding the subspec, i.e. changing this to pod 'DyScan/5.1', should address the issue.

Interfacing DyScan

If your app already has card.io, see the migrating from card.io guide.

DyScan can be used in two ways:

  • As a view controller: Quick and easy. Create a view controller that is presented modally. The DyScan view controller handles all aspects of the UX. We currently support two view controllers. One is intended for when DyScan is optionally accessed from a checkout form. The other is intended for when DyScan is the default method of entering payment information, and provides an option to enter numbers manually instead.

  • As a view: More flexible. Create a DyScanView to do card scanning only and manage everything else yourself. This enables a broader range of presentations, such as in-place transitions, but requires that you handle the rest of the UI yourself.

View Controller as an Option
View Controller as the Default
View

import Dyscan in the file that contains the view controller that will instantiate DyScan. In your app, create an extension for your view controller that conforms to DyScanViewControllerDelegate. This will require you to implement two functions, userDidCancel, and userDidProvide. userDidCancel is called whenever a scan event is unsuccessful (even if that means the user didn't explicitly cancel).

extension ExampleViewController: DyScanViewControllerDelegate{
func userDidCancel(_ paymentViewController: DyScanViewController!) {
paymentViewController.dismiss(animated: true, completion: nil)
// Implement functionality after user cancels
}
func userDidProvide(_ cardInfo: DyScanCreditCardInfo!, in paymentViewController: DyScanViewController!) {
paymentViewController.dismiss(animated: true, completion: nil)
// Implement functionality after card is read (information is stored in cardInfo)
}
}

If you are using Stripe, see this guide for how to implement these functions.

DyScanCreditCardInfo has the following fields:

Output

Description

cardNumber:String

The card number read, as a string.

nullableExpiryMonth:NSNumber?

If read, the expiration month of the card, otherwise nil. The value is accessed asnullableExpiryMonth.uintValue.

nullableExpiryYear:NSNumber?

If read, the expiration year of the card, otherwise nil. The value is accessed asnullableExpiryYear.uintValue.

nullableIsFraud:NSNumber?

Currently always nil.

cardNumberX:NSNumber?

The x position of the card number, as a fraction of the scan region width. The value is accessed ascardNumberX.doubleValue.

cardNumberY:NSNumber?

The y position of the card number, as a fraction of the scan region height. The value is accessed ascardNumberY.doubleValue.

expiryX:NSNumber?

The x position of the expiration date, as a fraction of the scan region width. The value is accessed asexpiryX.doubleValue.

expiryY:NSNumber?

The y position of the expiration date, as a fraction of the scan region width. The value is accessed asexpiryY.doubleValue.

expiryMonth:UInt

If read, the expiration month of the card, otherwise 0. To maintain good style, we recommend using nullableExpiryMonth if writing in Swift.

expiryYear:UInt

If read, the expiration year of the card, otherwise 0. To maintain good style, we recommend using nullableExpiryYear if writing in Swift.

isFraud:Bool

Currently always false.

To instantiate DyScan, create an instance of DyScanViewController, and set the paymentDelegate attribute of it to your view controller (using self). Then, present the view controller.

let viewController = DyScanViewController()
viewController.paymentDelegate = self
viewController.apiKey = "{YOUR API KEY}"
let navigationController = UINavigationController(rootViewController: viewController)
present(navigationController, animated: true, completion: nil)

import Dyscan in the file that contains the view controller that will instantiate DyScan. In your app, create an extension for your view controller that conforms to DyScanDefaultViewControllerDelegate. This will require you to implement three functions, userDidCancel, userDidProvide , and userChoseManual. userDidCancel is called whenever a scan event is unsuccessful (even if that means the user didn't explicitly cancel).

extension ExampleViewController: DyScanViewControllerDelegate{
func userDidCancel(_ paymentViewController: DyScanViewController!) {
paymentViewController.dismiss(animated: true, completion: nil)
// Implement functionality after user cancels
}
func userDidProvide(_ cardInfo: DyScanCreditCardInfo!, in paymentViewController: DyScanViewController!) {
paymentViewController.dismiss(animated: true, completion: nil)
// Implement functionality after card is read (information is stored in cardInfo)
}
func userChoseManual(_ paymentViewController: DyScanDefaultViewController!){
paymentViewController.dismiss(animated: true, completion: nil)
// Implement functionality for transitioning manual entry
}
}

If you are using Stripe, see this guide for what functions to implement here.

DyScanCreditCardInfo has the following fields:

Output

Description

cardNumber:String

The card number read, as a string.

nullableExpiryMonth:NSNumber?

If read, the expiration month of the card, otherwise nil. The value is accessed asnullableExpiryMonth.uintValue.

nullableExpiryYear:NSNumber?

If read, the expiration year of the card, otherwise nil. The value is accessed asnullableExpiryYear.uintValue.

nullableIsFraud:NSNumber?

Currently always nil.

cardNumberX:NSNumber?

The x position of the card number, as a fraction of the scan region width. The value is accessed ascardNumberX.doubleValue.

cardNumberY:NSNumber?

The y position of the card number, as a fraction of the scan region height. The value is accessed ascardNumberY.doubleValue.

expiryX:NSNumber?

The x position of the expiration date, as a fraction of the scan region width. The value is accessed asexpiryX.doubleValue.

expiryY:NSNumber?

The y position of the expiration date, as a fraction of the scan region width. The value is accessed asexpiryY.doubleValue.

expiryMonth:UInt

If read, the expiration month of the card, otherwise 0. To maintain good style, we recommend using nullableExpiryMonth if writing in Swift.

expiryYear:UInt

If read, the expiration year of the card, otherwise 0. To maintain good style, we recommend using nullableExpiryYear if writing in Swift.

isFraud:Bool

Currently always false.

To instantiate DyScan, create an instance of DyScanDefaultViewController, and set the paymentDelegate attribute of it to your view controller (using self). Then, present the view controller.

let viewController = DyScanDefaultViewController()
viewController.paymentDelegate = self
viewController.apiKey = "{YOUR API KEY}"
let navigationController = UINavigationController(rootViewController: viewController)
present(navigationController, animated: true, completion: nil)

If you would like to disable the manual entry option, you can do so by setting the key viewController.allowManualEntry=false.

import Dyscan in the file that contains the view controller that will instantiate DyScan. In your app, create an extension for your view that conforms to DyScanViewDelegate. This will require you to implement two functions, noCameraPermission, and dyScanView.

extension ExampleViewController: DyScanViewDelegate{
func noCameraPermission(_ dyScanView: DyScanView!) {
//Implement functionality when camera permissions are not given
}
func dyScanView(_ dyScanView: DyScanView!, didScanCard cardInfo: DyScanCreditCardInfo?) {
//Implement functionality when scanning completes (information is stored in cardInfo, will be nil if scan failed)
}
}

If you are using Stripe, see this guide for what functions to implement here.

DyScanCreditCardInfo has the following fields:

Output

Description

cardNumber:String

The card number read, as a string.

nullableExpiryMonth:NSNumber?

If read, the expiration month of the card, otherwise nil. The value is accessed asnullableExpiryMonth.uintValue.

nullableExpiryYear:NSNumber?

If read, the expiration year of the card, otherwise nil. The value is accessed asnullableExpiryYear.uintValue.

nullableIsFraud:NSNumber?

Currently always nil.

cardNumberX:NSNumber?

The x position of the card number, as a fraction of the scan region width. The value is accessed ascardNumberX.doubleValue.

cardNumberY:NSNumber?

The y position of the card number, as a fraction of the scan region height. The value is accessed ascardNumberY.doubleValue.

expiryX:NSNumber?

The x position of the expiration date, as a fraction of the scan region width. The value is accessed asexpiryX.doubleValue.

expiryY:NSNumber?

The y position of the expiration date, as a fraction of the scan region width. The value is accessed asexpiryY.doubleValue.

expiryMonth:UInt

If read, the expiration month of the card, otherwise 0. To maintain good style, we recommend using nullableExpiryMonth if writing in Swift.

expiryYear:UInt

If read, the expiration year of the card, otherwise 0. To maintain good style, we recommend using nullableExpiryYear if writing in Swift.

isFraud:Bool

Currently always false.

To instantiate DyScan, create an instance of DyScanView, and set the delegate attribute of it to your view controller (using self). You will need to call the prepare() function to fully initialize the view before adding it as a subview. For example, DyScanView could be added like this:

dyScanView = DyScanView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.width))
dyScanView?.apiKey = "{YOUR API KEY}"
dyScanView?.delegate = self
dyScanView?.prepare()
self.view.addSubview(dyScanView!)

If you would like to allow for the user to switch to a vertical card scanning experience, use the DyScanView.rotate function.

Customizing the Appearance

The DyScan UI is customizable through the following options

Option

Description

Default Value

language:String

The language to display

NSLocale.current.languageCode

showNumberOnCompletion:Bool

Whether to display the credit card number to the user after the card has been read.

false

showNumberOverlay:Bool

Whether to show the number overlay.

true

numberOverlayColor:UIColor

The color of the number overlay text.

UIColor.white

numberOverlayOpacity:CGFloat

The opacity of the number overlay text.

0.3

defaultCardNumberText:String

The card number shown in the number overlay text.

"4242 4242 4242 4242"

defaultExpirationDate:String

The expiration shown in the number overlay text.

"11/11"

showCorners:Bool

Whether to show the corners found by the scanner or not.

true

cornerThickness:int

The thickness of lines that show the corners.

5

cornerInactiveColor:UIColor

The color of the corner in its normal, no corner found state.

UIColor.gray

cornerActiveColor:UIColor

The color of the corner when it has found a corner.

UIColor.cyan

cornerCompletedColor:UIColor

The color of the corner when scanning is completed.

UIColor.green

bgColor:UIColor

The color of the background.

UIColor.gray

bgOpacity:CGFloat

The opacity of the background.

0.8

lightTorchWhenDark:Bool

Whether to use the torch automatically in dark environments.

true

vibrateOnCompletion:Bool

Whether to cause the phone to vibrate on a successful scan.

true

The following fields can only be used in the view controller:

Option

Description

Default Value

showHelperText:Bool

Whether to show the helper text.

true

helperTextString:String?

The text displayed in helper text. If this is set, it will override the set language.

nil

helperTextColor:UIColor

The color of the helper text.

UIColor.white

helperTextVerticalOffset:Float

As a fraction of the height of the screen, how far down the helper text should be.

0.45

showRotateButton:Bool

Whether to show a rotate button to support vertical cards better.

false

scanRegionVerticalOffset:Float

As a fraction of the height of the screen, how far down the scanning region should be.

0.15