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.
If you use Swift Package Manager, see the instructions here.
Follow the instructions below corresponding with your DyScan version to access the necessary repositories.
After getting the access token for Dyneti's repo access, open up your Podfile and above the target add this line:
Then, inside the target with the other dependencies, add the appropriate line below for your specific version of Swift. If you are unsure what Swift version you are using, use Universal variant.
pod 'DyScan'
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
$podinstall
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.
Initializing DyScan (only for version 1.1.1 and up)
In your AppDelegate add import DyScan and the following line to configure DyScan.
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.
Regardless of which methodology you use, the failure callback will provide a reason for why scanning was not successful. You do not have to use this value (for example you could always go to manual entry on any failure), but this gives you the opportunity to react differently based on the reason, for example by requesting the user to enable the permissions. The possible values are:
Reason
Description
AuthError
There was an issue with the API key. Make sure that the API key has been set prior to calling prepare.
CameraError
The camera setup has failed. For example, there might not be any cameras available for use at the time.
NoPermissions
The user has not granted the app permissions to open the camera, so we have no way of proceeding with the scan.
UserCancelled
The user chose to exit.
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, onFailure, and onSuccess. onFailure is called whenever a scan event is unsuccessful (for any reason, including the user choosing to cancel).
Optionally, you can implement the function onProgressUpdate to access information about the card being scanned while the scan is ongoing (available for version 1.2.9 of DyScan and up). The DyScanProgressUpdate class has two attributes (both of string type): lastFourDigits and network, which correspond to the last four digits and network of the credit card (e.g., Visa or Mastercard) being scanned, respectively. You may choose to surface this information to your users to give them more feedback as they are waiting for their card to scan.
extensionExampleViewController:DyScanViewControllerDelegate{funconFailure(_paymentViewController: DyScanViewController!, reason: DyScanExitReason) { paymentViewController.dismiss(animated:true, completion:nil)// Implement functionality for failure cases }funconSuccess(_cardInfo: DyScanCreditCardInfo!, inpaymentViewController: DyScanViewController!) { paymentViewController.dismiss(animated:true, completion:nil)// Implement functionality after card is read (information is stored in cardInfo) }funconProgressUpdate(_progressUpdate: DyScanProgressUpdate, inpaymentViewController: DyScanViewController!){let network = progressUpdate.networklet lastFourDigits = progressUpdate.lastFourDigits// Implement functionality to use this info mid-scan }}
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
For the OCR-only version of DyScan, isFraud is always false.
cardOrientation:String
Whether the card scanned was vertical or horizontal.
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 = selfviewController.apiKey ="{YOUR API KEY}"// for version lower than 1.1.1let navigationController =UINavigationController(rootViewController: viewController)navigationController.modalPresentationStyle = .fullScreenpresent(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, onFailure, onSuccess , and userChoseManual. onFailure is called whenever a scan event is unsuccessful (for any reason, even if the user chose to cancel).
Optionally, you can implement the function onProgressUpdate to access information about the card being scanned while the scan is ongoing (available for version 1.2.9 of DyScan and up). The DyScanProgressUpdate class has two attributes (both of string type): lastFourDigits and network, which correspond to the last four digits and network of the credit card (e.g., Visa or Mastercard) being scanned, respectively. You may choose to surface this information to your users to give them more feedback as they are waiting for their card to scan.
extensionExampleViewController:DyScanViewControllerDelegate{funconFailure(_paymentViewController: DyScanViewController!, reason: DyScanExitReason) { paymentViewController.dismiss(animated:true, completion:nil)// Implement functionality after user cancels }funconSuccess(_cardInfo: DyScanCreditCardInfo!, inpaymentViewController: DyScanViewController!) { paymentViewController.dismiss(animated:true, completion:nil)// Implement functionality after card is read (information is stored in cardInfo) }funcuserChoseManual(_paymentViewController: DyScanDefaultViewController!){ paymentViewController.dismiss(animated:true, completion:nil)// Implement functionality for transitioning manual entry }funconProgressUpdate(_progressUpdate: DyScanProgressUpdate, inpaymentViewController: DyScanViewController!){let network = progressUpdate.networklet lastFourDigits = progressUpdate.lastFourDigits// Implement functionality to use this info mid-scan }}
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.
cardOrientation:String
Whether the card scanned was vertical or horizontal.
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 = selfviewController.apiKey ="{YOUR API KEY}"// for version lower than 1.1.0let navigationController =UINavigationController(rootViewController: viewController)navigationController.modalPresentationStyle = .fullScreenpresent(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, onFailure, and onSuccess.
Optionally, you can implement the function onProgressUpdate to access information about the card being scanned while the scan is ongoing (available for version 1.2.9 of DyScan and up). The DyScanProgressUpdate class has two attributes (both of string type): lastFourDigits and network, which correspond to the last four digits and network of the credit card (e.g., Visa or Mastercard) being scanned, respectively. You may choose to surface this information to your users to give them more feedback as they are waiting for their card to scan.
extensionExampleViewController:DyScanViewDelegate{funconFailure(_dyScanIOView: DyScanView!, reason: DyScanExitReason) {//Implement functionality when we could not scan }funconSuccess(_dyScanIOView: DyScanView!, cardInfo: DyScanCreditCardInfo?) {//Implement functionality when scanning completes (information is stored in cardInfo) }funconProgressUpdate(_dyScanIOView: DyScanView!, progressUpdate: DyScanProgressUpdate) {let network = progressUpdate.networklet lastFourDigits = progressUpdate.lastFourDigits// Implement functionality to use this info mid-scan }}
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.
cardOrientation:String
Whether the card scanned was vertical or horizontal.
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.height))dyScanView?.apiKey ="{YOUR API KEY}"// for version lower than 1.1.1dyScanView?.delegate = selfdyScanView?.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
numberOnCompletionAlwaysHorizontal:Bool
Whether to display number on completion horizontally in fixed position.
false
showDynetiLogo:Bool
Whether to display the Dyneti logo and wordmark above the scan region.
true
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
roundCorners:Bool
Whether the scan region has round corners resembling the credit-card outline. If set to false, the scan region becomes a rectangle.
true
expandCorners:Bool
Whether to show the corners expanded outward with respect to the scan frame.
false
chopCorners:Bool
Whether to show the corners with limited length instead of having them expand all the way until they intersect.
false
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. If set to false, torch toggle button will appear.
true
vibrateOnCompletion:Bool
Whether to cause the phone to vibrate on a successful scan.
true
cardFrameAccessibilityLabel:String?
The accessibility label of card scan frame.
"Align your card to this frame"
enableSidewaysScanning:Bool
Whether to allow cards to scan in sideways orientation. If set to true, vertical cards will be able to be scanned when positioned in the horizontal scan window. Note that enableSidewaysScanning and showRotateButton should not simultaneously be set to true when using the view controller, and that isVertical should not be used when enableSidewaysScanning is set to true when using DyScan as a view.
false
detectWrongCard: Bool
Whether to detect when the end-user is scanning the wrong card (when using DyScan for verification). If set to true and the string parameters expectedBIN and expectedLastFourDigits (which correspond to the first six and last four digits of the expected credit card number) are provided, when the end user attempts to scan the wrong card, the onProgressUpdate callback returns a boolean numberMismatch with true value (which can be used to signal the end user that they are not scanning the expected card) and the scan continues. Upon scanning the expected card, the scan completes.
false
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. By default, the text is displayed in one line and font size is automatically shrunk to fit on the screen. To display it in multiple lines, use\n for line breaks.
nil
helperTextColor:UIColor
The color of the helper text.
UIColor.white
helperTextFont:UIFont
The font and text size of the helper text.
System font, size: 25
helperTextPosition:Enum
DyScanHelperTextPosition
The position of the helper text. DyScanHelperTextPosition enum values: top, center, bottom
bottom
showRotateButton:Bool
Whether to show a rotate button to support vertical cards better.
false
Additionally, there are some public fields you can use to easily add buttons with additional functionality to your scan screen. Note that these are available only if you are using DyScan as a view. The fields are described below:
Public fields
Name
Description
isVertical:Bool
Whether to set scan region to vertical card orientation
true - vertical card
false - horizontal card
Also can be used to get current scan region orientation (true when vertical).
isTorchEnabled:Bool
Whether to turn torch on or off.
Also can be used to check if torch is currently turned on (true when torch is on).