Integrating with Nexus
Importing DyScan
The easiest way to integrate DyScan is by using our Nexus repository, which is covered in this guide.
If you would rather include DyScan directly as a library, see the instructions here.
In the project-level build.gradle
add the Dyneti Maven repository (credentials provided during integration):
allprojects {
repositories {
// Other repositories are here
maven {
credentials {
username = "nexusUsername"
password = "nexusPassword"
}
url "https://nexus.dyneti.com/repository/dyscan-fraud/"
authentication {
basic(BasicAuthentication)
}
}
}
}
- Default
- TensorFlow exclude
In the app-level build.gradle
add the dependency:
dependencies {
// Other dependencies are here
implementation 'com.dyneti.android.dyscan:dyscan-fraud:1.4.2'
}
In order to reduce your final app size, you can exclude unwanted architectures in your app's build.gradle
:
// Remove simulator architectures
android {
...
packagingOptions {
exclude 'lib/x86/libimage_processing_util_jni.so'
exclude 'lib/x86/libtensorflowlite_jni.so'
exclude 'lib/x86_64/libimage_processing_util_jni.so'
exclude 'lib/x86_64/libtensorflowlite_jni.so'
}
}
In the app-level build.gradle
add the dependency:
dependencies {
// Other dependencies are here
implementation ('com.dyneti.android.dyscan:dyscan-fraud:1.4.2') {
exclude module: 'tensorflow-lite'
}
implementation 'org.tensorflow:tensorflow-lite:2.1.0'
}
If you would rather integrate without using our Nexus repository, see Manually Importing the Library.
16 KB Page Size Support
Certain newer Android devices will begin using 16 KB page size. Dyneti has released version 1.7.14
which supports these devices.
To upgrade:
Change your implementation directive to use 1.7.14
implementation('com.dyneti.android.dyscan:dyscan-fraud:1.7.14')
or
implementation ('com.dyneti.android.dyscan:dyscan:1.7.14')
or
implementation 'com.dyneti.android.dyscan_protect:dyscan:1.7.14')
Gradle version 8.10
is required to build with support for 16 KB page size. Make sure the distributionUrl
in gradle-wrapper.properties
points to the correct version.
If you encounter the following error while building your project
Duplicate class kotlin.collections.jdk8.CollectionsJDK8Kt found in modules jetified-kotlin-stdlib-1.8.22 (org.jetbrains.kotlin:kotlin-stdlib:1.8.22) and jetified-kotlin-stdlib-jdk8-1.6.21 (org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.21)
Add the following dependency to your app-level build.gradle:
dependencies {
// Fix duplicate class
implementation(platform("org.jetbrains.kotlin:kotlin-bom:1.8.0"))
}
Initializing DyScan
In your Application
class add the following line to init DyScan
.
public class DyScanApplication extends Application {
//...
@Override
public void onCreate() {
super.onCreate();
//...
DyScan.init(this, "{YOUR_API_KEY}");
//...
}
}
Camera features support
By default, DyScan uses uses-feature
tags in its AndroidManifest.xml
file to filter out devices that don't support the required camera features. This filtering affects the host app's supported device count in Google Play.
You can override this filtering by adding the below lines into your AndroidManifest.xml
manifest tag section:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
...
<uses-feature android:name="android.hardware.camera" android:required="false" tools:replace="required" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" tools:replace="required" />
...
</manifest>
If you choose to override the default tags settings inAndroidManifest.xml,
you should additionally check manually if the device is supported before calling DyScan functions to avoid a bad user experience (see below).
if (DyScan.isDeviceSupported(context)) {
// open DyScanActivity
Intent intent = new Intent(context, DyScanActivity.class);
startActivityForResult(intent, SCAN_REQUEST_CODE);
} else {
// alternate flow if device is not supported
}
Interfacing DyScan
Import the following DyScan classes in your Activity that will launch DyScan:
import com.dyneti.android.dyscan.DyScanActivity;
import com.dyneti.android.dyscan.CreditCard;
This example assumes that you're going to launch the scanner from a button, and that you've set the button's onClick
handler in the layout XML via android:onClick="onScanPress"
. (If not, the process is analogous, just use the code inside this function). onScanPress
is implemented as
public void onScanPress(View v) {
Intent scanIntent = new Intent(this, DyScanActivity.class);
// MY_SCAN_REQUEST_CODE (e.g., 1337) is arbitrary and is only used within this activity.
startActivityForResult(scanIntent, MY_SCAN_REQUEST_CODE);
}
Next, override onActivityResult()
to get the scan result.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == MY_SCAN_REQUEST_CODE) {
if (data != null && data.hasExtra(DyScanActivity.EXTRA_SCAN_RESULT)) {
CreditCard scanResult = data.getParcelableExtra(DyScanActivity.EXTRA_SCAN_RESULT);
// Do stuff with results in scanResult
}
}
}
CreditCard
has the following methods for getting values:
Method | Return type | Description |
---|---|---|
Method | Return type | Description |
getScanId() | String | The scan UUID |
getPayloadId() | String | A unique identifier for the payload. To be used with the Integrity Check API. |
getCardNumber() | String | The card number read, as a string. |
getExpiryMonth() | int | If read, the expiration month of the card, otherwise 0. |
getExpiryYear() | int | If read, the expiration year of the card (the full four-digit year), otherwise 0. |
isFraud() | boolean | a boolean indicating card legitimacy. isFraud is true when the card is fraudulent, and false if card is legitimate |
getTimestamp() | long | an ISO8601 timestamp indicating when the scan occurred |
getDeclineReasons() | DeclineReasons | a class containing reasons why a card scanned is declared as fraudulent |
getCardOrientation() | String | Whether the card scanned was vertical or horizontal. |
Reasons for decline include the following methods:
isFormatMismatch()
: a boolean that indicates that the card assets do not match the card type as detected by the BIN (e.g., the card number or logo are not where we expect them to be).isNumberMismatch()
: a boolean that indicates that the BIN and last four digits of the scanned card do not match with what we expect. Note this reason is only available if you provide us with the expected BIN and last four.isGeneratedImage()
: a boolean that indicates that the image is likely generated (e.g., the image is being scanned through a screen, or does not have corners or wear and tear).isRateLimited()
: a boolean that indicates that an attacker has been attempting multiple scans in rapid succession using the same device.isTamperedFeatures()
: a boolean that indicates that at least one of the other features has been tampered with
Customizing DyScanActivity
The DyScanActivity can be customized by passing EXTRAs along with the intent. This allows you to modify both the appearance and behavior of the Activity.
EXTRA | Description | Default Value |
---|---|---|
EXTRA_HELPER_TEXT_STRING | What to text to display to the user to guide them in scanning their card. It is highly recommended that you set this value; otherwise we will try to provide this text based on EXTRA_LANGUAGE . | Dependent on EXTRA_LANGUAGE |
EXTRA_HELPER_TEXT_COLOR | The color to use to display the helper text. | Color.WHITE |
EXTRA_HELPER_TEXT_SIZE_SP | The size of the helper text in sp unit. | 18 |
EXTRA_HELPER_TEXT_FONT_FAMILY | The font family name of the helper text. The font needs to be placed in assets first. | Default font |
EXTRA_HELPER_TEXT_POSITION | The position of the helper text. DyScanHelperTextPosition enum values: TOP, CENTER, BOTTOM | DyScanHelperTextPosition.BOTTOM |
EXTRA_SHOW_HELPER_TEXT | Whether to show the helper text on screen. | true |
EXTRA_SHOW_CORNERS | Whether to show the scan area outline | true |
EXTRA_CORNER_THICKNESS | How thick to make the lines outlining the scan area, indicating to the user where to place their credit card. Input as a float. | 15f |
EXTRA_CORNER_INACTIVE_COLOR | The color to use in drawing the outline of the scan region when nothing of interest is detected. | Color.GRAY |
EXTRA_CORNER_ACTIVE_COLOR | The color to use in drawing the outline of the scan region when corners are detected. | Color.CYAN |
EXTRA_CORNER_COMPLETED_COLOR | The color to use in drawing the outline of the scan region when we have successfully scanned a card. | Color.GREEN |
EXTRA_BACKGROUND_COLOR | The color to use to obscure everything outside the scan region in order to draw the user’s attention to the scan region. | Color.GRAY |
EXTRA_BACKGROUND_OPACITY | The opacity to use when obscuring everything outside the scan region, as an integer ranging from 0 (transparent) to 255 (opaque). | 115 |
EXTRA_SHOW_ROTATE_BUTTON | Whether to show the button which allows the user to rotate the scan region by 90 degrees, facilitating the scanning of vertical cards. | false |
EXTRA_SHOW_MANUAL_ENTRY_BUTTON | Whether to show a button at the bottom of the screen allowing the user to choose to exit the scanning Activity. | false |
EXTRA_MANUAL_ENTRY_STRING | The String to display on the manual entry button if shown. This should be set if you are showing the manual entry button. | |
EXTRA_SHOW_RESULT_OVERLAY | Whether to briefly show the scanned card number (and date, if present) as an overlay over the screen after a successful scan. | false |
EXTRA_RESULT_OVERLAY_ALWAYS_HORIZONTAL | Whether to display number on completion horizontally in fixed position. | false |
EXTRA_SHOW_DYNETI_LOGO | Whether to show a dark blue Dyneti logo and wordmark above the scan region. | true |
EXTRA_SHOW_CARD_OVERLAY | Whether to show the overlay displaying a sample card number and expiration date hinting at the user to place their card in the scan region. | true |
EXTRA_LANGUAGE | If EXTRA_HELPER_TEXT_STRING is set, this value is ignored, and setting that value is strongly recommended. Otherwise, when no helper text string is provided, we will attempt to use the inputted ISO 639-1 Code as a String to supply a String ourselves. If we do not have a String for this language code, or no language code is provided, we will fall back to English. | The default locale's language according to the device |
EXTRA_LIGHT_TORCH_WHEN_DARK | Whether the phone will turn on the flashlight if multiple frames have appeared to be too dark. If set to false, torch toggle button will appear. | true |
EXTRA_VIBRATE_ON_COMPLETION | Whether the device will vibrate once it has successfully extracted the credit card data from the images provided by the camera. | true |
EXTRA_CARD_FRAME_CONTENT_DESCRIPTION | The content description of card scan frame. | "Align your card to this frame" |
EXTRA_IS_CHALLENGE | Whether DyScanActivity is being used as a fraud check. This is currently only used for logging purposes, but in the future may impact behavior. | false |
EXTRA_DEBUG_LOG | Whether to print out some additional logging that may be helpful for debugging issues in an app. Errors are always printed regardless of this value. | false |
EXTRA_SIDEWAYS_SCANNING_ENABLED | 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 |
EXTRA_AWAIT_SCAN_STORAGE | Whether to strictly wait for the scan data to be uploaded to the backend before returning a successful result | false |
If you want to have more control over the experience than DyScanActivity provides, we also offer a DyScanView.