Getting Started

If you rather like to jump into some code than to walk through a Quick Start Guide, a good starting point for development with the Anyline SDK on React-Native, is to download the React-Native GitHub Repository.

The bundle includes:

  • anylinesdk-plugin: The plugin that you can add to your project
  • example: A simple React-Native example project, demonstrating how the Anyline SDK React-Native-Plugin can be used

Requirements

In order to be able to use the Anyline SDK React-Native Plugin, the following requirements have to be met:

Android

  • An Android device with Android SDK Level >= 19
  • An Android device with decent camera functionality (recommended: 720p and adequate auto focus)

iOS

  • minimum iOS 10.0
  • minimum iPhone 5

Warning

For now, the CancelOnResult setting is forced to true.

React-Native Quick Start Guide

In this guide, we will show you how to integrate the Anyline React-Native Plugin into your existing React-Native project.

For more information about React-Native itself, how to use plugins, etc., please refer to The Facebook React-Native Website.

Warning

Keep in mind, all the images are saved in the cache directory of the app. For performance reasons, we only provide the path as string, so we don’t have to transfer the whole image through the bridge. Please be aware, that you should not use the images in the cache directory for persistent storage, but store the images in a location of your choice for persistence.

Generate an Anyline License

In order to run the Anyline SDK in your app, you require a License Key. The Guide on How To Generate a License can be found at Anyline License Key Generation

This section focuses on how to integrate the license on React-Native.

Add the Anyline SDK Plugin to your Project

Download or Clone the Repo to your node_modules from React-Native GitHub Repository.

You can also just use

npm i --save anyline-ocr-react-native-module

You also need to link it, executed in the root of your application.

react-native link

Get native Dependencies

Android

Setup Packages

Package name must match with the bundleID from your Anyline License.

Add Anyline Package

Go into the native Android folder of your Project to your MainApplication.

Import the AnylinePackage

import com.anyline.reactnative.AnylinePackage;

and add the package to your getPackages function

@Override
 protected List<ReactPackage> getPackages() {
   return Arrays.<ReactPackage>asList(
       new MainReactPackage(),
         new AnylinePackage()
   );
 }

iOS

Disable bitcode in your project.

Podfile

  • Copy the Podfile from our example Project to your native iOS root folder.
  • Change the target of the Podfile to your project name.
  • pod install

Permissions

Add Camera Permissions to Info.plist

Privacy - Camera Usage Description

Add also every other permission you want to configure in your config.js (vibrate, sound).

Anyline License

Your BundleIdentifier of your app has to match with your bundleID from your Anyline License.

Create your Javascript file

You can now start to create your Javascript files. Or you can build your React-Native application based on the example provided in the React-Native GitHub Repository. The example are located under example/Anyline.

The following setup is just a recommendation. You can, of course, implement the Plugin the way you prefer.

Import the plugin to your JavaScript file

Import plugin
import AnylineOCR from 'anyline-ocr-react-native-module';

Import the config file

Import Config
import config from '../config';

Add the Anyline component

The Anyline SDK React-Native Plugin provides requires two callback functions: onResult and onError. Call the native View with setup()

Callback

Call the Plugin
    openOCR = () => {
        AnylineOCR.setup(
            JSON.stringify(config),
            'scan',
            this.onResult,
            this.onError
        );
    };

Promise

openAnyline = async () => {
    ...

    try {
        const result = await AnylineOCR.setupPromise(JSON.stringify(config), "scan");
    } catch(error) {
        console.error(error);
    }

    ...
}
onResult(result)

This function is called once the scan was successfully performed.

The returned result object is a stringified json-object containing all the scaned values and check-digits .

{
    reading : 'Result of the Scan',
    imagePath : 'path to cropped image',
    fullImagePath : 'path to full image',
    barcode : 'result of the simultaneous barcode scanning',
    scanMode : 'selected scanMode',
    meterType : 'meter type',
    cutoutBase64 : 'base64 string of cropped image',
    fullImageBase64 : 'base64 string of full image'
}
onError(error)

This function is called if an error occurred or the user canceled the scanning.

The returned error object is a String, providing the error message.

onError Method
    onError = (error) => {
        console.error(error);
        alert(error);
    };

Add the License Key

You need a license key, in order to run the scanning process in your app. You can learn about creating a license key in Anyline License Key Generation.

Add the license key to your anyline object like this

Add the License Key
  license: 'eyAiYW5kcm9pZElkZW50aWZpZXIiOiBbICJjb20uYW55bGluZS5leGFtcGxlLnJl\n' +
      'YWN0bmF0aXZlIiBdLCAiZGVidWdSZXBvcnRpbmciOiAib24iLCAiaW9zSWRlbnRp\n' +
      'ZmllciI6IFsgImNvbS5hbnlsaW5lLmV4YW1wbGUucmVhY3RuYXRpdmUiIF0sICJs\n' +
      'aWNlbnNlS2V5VmVyc2lvbiI6IDIsICJtYWpvclZlcnNpb24iOiAiMyIsICJwaW5n\n' +
      'UmVwb3J0aW5nIjogdHJ1ZSwgInBsYXRmb3JtIjogWyAiaU9TIiwgIkFuZHJvaWQi\n' +
      'IF0sICJzY29wZSI6IFsgIkFMTCIgXSwgInNob3dQb3BVcEFmdGVyRXhwaXJ5Ijog\n' +
      'ZmFsc2UsICJzaG93V2F0ZXJtYXJrIjogdHJ1ZSwgInRvbGVyYW5jZURheXMiOiA5\n' +
      'MCwgInZhbGlkIjogIjIwMjAtMTItMzEiIH0KUlliRzFBbFgwempXZTVLYkdtK000\n' +
      'SXFXME5jWUdTZWNBU0t6M3k0QnQ3VGFjMWgrVEpveHlIVXFTb1JxWFZKNgpXRlhH\n' +
      'N2kvVjFqNjVTTEgyS0V4NUpoRlZKT0Y1UDhJR1VLak9CY1ozR2o5WHRTLzdub3Ni\n' +
      'ZHoxTTlqZWlJRWJYCjZ1ZXFyVmtyNGRpRVJsOWNDQ01kOWRvTG80dnJiMGpIbzZ0\n' +
      'bk12d2VrWFdUaUFnSlNjNXB5MGlOc2F6MjRKZFYKa3dEWnY2dG9Oa1NIdjhRWTVj\n' +
      'U3laSWdNSHFsRTZBUkVxcG5oNlA5THh3aWF1Sm5Sd2o4OWFWVCt4ZkoyaFdLbgpU\n' +
      'NE9tUzVraWdNUVZLaW8vaWlJS2tIVEVUdUxjYWJEWWtacExZdVR2YnU1S1hIc0R6\n' +
      'b1NxUUJTL3ZFS3VYUHhhCjNnanZnS285M3lrSjJKQjVBZjZiSkE9PQo=',

How to identify the Application ID

The Application ID on React-Native can be found in native Parts (Android and iOS) of your project.

Add the View Configuration

The View Configuration defines the look & feel of your scanning application. More information about the View Configuration can be found in Anyline View Configuration.

Add the View Configuration
  options: {
      "camera": {
          "captureResolution": "720p"
      },
      "flash": {
          "mode": "manual",
          "alignment": "bottom_right",
      },
      "viewPlugin": {
          "plugin": {
              "id": "Meter_ID",
              "meterPlugin": {
                  "scanMode": "ANALOG_METER"
              }
          },
          "cutoutConfig": {
              "style": "rect",
              "alignment": "top_half",
              "strokeWidth": 2,
              "cornerRadius": 4,
              "strokeColor": "FFFFFF",
              "outerColor": "000000",
              "outerAlpha": 0.3,
              "feedbackStrokeColor": "0099FF"
          },
          "scanFeedback": {
              "style": "CONTOUR_RECT",
              "strokeColor": "0099FF",
              "fillColor": "220099FF",
              "blinkOnResult": true,
              "beepOnResult": true,
              "vibrateOnResult": true
          },
          "cancelOnResult": true
      },
      "nativeBarcodeEnabled": true,
      "segment": {
          "titles": ["Analog", "Digital"],
          "modes": ["ANALOG_METER", "DIGITAL_METER"],
          "tintColor": "CCCCCC",
          "offset": {
              "x": 0,
              "y": 400
          }
      }
  }
Additional Parameters in the View Configuration

React-Native adds some additional parameters to the View configuration.

nativeBarcodeEnabled

You can enable the Simultaneous Barcode scanning while scanning meter reader.

quality

Here you can set the quality of the saved transformed and full image. The range is 0 - 100, where 0 is the lowest quality and 100 the best.

quality

Only for the Document product

cropAndTransformErrorMessage

If set cropAndTransformErrorMessage as custom error message, a notification will appear in the screen containing this error message when the SDK gets the result, but can’t detect the corners. This requires “cropAndTransformID” is set to true. Default String is empty (so no notification will be shown).

cropAndTransformErrorMessage

Only for the MRZ product

iOS Done Button Configuration

On iOS, a done button can be added to the view by providing additional parameters.

"doneButton": { // iOS only. Android uses hardware back button.
    "title": "OK",
    "type": "rect", // fullwidth, rect
    "cornerRadius": 0,
    //"backgroundColor":"#EEEEEE", // default clearcolor
    "textColor": "FFFFFF",
    "textColorHighlighted": "CCCCCC",
    "fontSize": 33,
    "fontName": "HelveticaNeue",
    "positionXAlignment": "center", // left,right,center - no affect on fullwidth
    "positionYAlignment": "bottom", // top, center, bottom
    "offset": {
        "x": 0, // postive -> right
        "y": -88, // postive -> down
    }
}
doneButton.title

The title of the button.

JSON-Type Example
String OK
doneButton.type

The type of the button. Can be one of rect or fullWidth.

JSON-Type Example
String rect
doneButton.cornerRadius

The corner radius of the button

JSON-Type Example
Integer 0
doneButton.backgroundColor

The buttons background color. Default is set to clearcolor

JSON-Type Example
String (RRGGBB) EEEEEE
doneButton.textColor

The buttons text color.

JSON-Type Example
String (RRGGBB) FFFFFF
doneButton.textColorHighlighted

The buttons text color when highlighted.

JSON-Type Example
String (RRGGBB) CCCCCC
doneButton.fontSize

The font size of the buttons text.

JSON-Type Example
Integer 33
doneButton.fontName

The font family name of the buttons text.

JSON-Type Example
String HelveticaNeue
doneButton.positionXAlignment

The X alignment of the button. One of left, center, or right.

fullwidth

This parameter has no effect if type is set to fullwidth.

JSON-Type Example
String center
doneButton.positionYAlignment

The Y alignment of the button. One of top, center, or bottom.

JSON-Type Example
String bottom
doneButton.offset.x

The X offset relative to the algignment. Positive values move the button to the right.

JSON-Type Example
Integer 10
doneButton.offset.y

The Y offset relative to the algignment. Positive values move the button downwards.

JSON-Type Example
Integer -80

Add the Anyline OCR Configuration

Note

This is only necessary if you want to use the Anyline OCR

The Anyline OCR plugin can be used to create plenty of different use cases. It offers a generic interface, which can be used to scan a variety of texts, from IBAN codes to Scrabble letters.

The description of all parameters can be found at Plugins > AnylineOCR Add this to your config File.

Add the Anyline OCR Configuration
    ocr: {
        "scanMode": "AUTO",
        "aleFile" : "assets/myVoucherAle.ale",
        "tesseractLanguages": ["anyline_capitals"],
        "traineddataFiles": ["trainedData/anyline_capitals.traineddata"],
        "charWhitelist": "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
        "validationRegex": "[A-Z0-9]{8}$",
        "isBrightTextOnDark": true

.._react_native_custom_traindata:

Add custom TrainData to the OCR Plugin

If you want to add you custom traindata, you have to copy it into the native project folder.

iOS

ios custom training data structure
    ios
     └─── trainedData
             └─── myTrainedData.traineddata

Android

android custom training data structure
    android
        └─── app
              └─── src
                    └─── main
                           └─── assets
                                  └─── traindData
                                          └─── myTrainedData.traineddata

Also you have to reflect those file paths in your OCR Config.

A String of your custom Anyline ALE file for the OCR step of the Anyline SDK.

iOS

ios custom training data structure
    ios
     └─── ale
           └─── myTrainedData.traineddata

Android

android custom training data structure
    android
        └─── app
              └─── src
                    └─── main
                           └─── assets
                                  └─── ale
                                        └─── myAleFile.ale

.._react_native_add_anyline_to_project_and_start:

Start the Scanning

Now everything is set up to start the scanning process with the provided configuration.

Callback

Start the Scanning with Callbacks
         openOCR = () => {
            AnylineOCR.setup(
                JSON.stringify(config),
                'scan',
                this.onResult,
                this.onError
            );
         };

Promise

Start the Scanning with Promises
        openAnyline = async () => {
            try {
                const result = await AnylineOCR.setupPromise(JSON.stringify(config), "scan");
            } catch(error) {
                console.error(error);
            }
        }

Start the Scanning

  • onResult: The result callback function
  • onError: The error callback function
  • scanMode: String to start the corresponding Plugin or Use-Case.
  • config: An object consisting of the license and the options

Additional Functions

getLicenseExpiryDate

Check till when the provided License is or was valid. Returns a string.

Get License expiry date
    import AnylineOCR, { getLicenseExpiryDate } from 'anyline-ocr-react-native-module';
    ...
    console.log(getLicenseExpiryDate(myLicenseString)); // 'YYYY-MM-DD'

Full Example

index.js

Full JS example with Android Permissions
import React, {Component} from 'react';
import {
    AppRegistry,
    PermissionsAndroid,
    StyleSheet,
    Text,
    View,
    Platform
} from 'react-native';

import AnylineOCR from 'anyline-ocr-react-native-module';

import Result from './Result';

import config from '../config';


class Anyline extends Component {

    state = {
        hasScanned: false,
        result: '',
        imagePath: '',
        fullImagePath: '',
        barcode: '',
        scanMode: '',
        meterType: '',
        cutoutBase64: '',
        fullImageBase64: '',
    };

    openOCR = () => {
        AnylineOCR.setup(
            JSON.stringify(config),
            'scan',
            this.onResult,
            this.onError
        );
    };

    requestCameraPermission = async() => {


        try {
            const granted = await PermissionsAndroid.request(
                PermissionsAndroid.PERMISSIONS.CAMERA
            );
            if (granted === PermissionsAndroid.RESULTS.GRANTED) {
                console.log('Camera permission allowed');
                this.openOCR();
            } else {
                console.log("Camera permission denied");
            }
        } catch (err) {
            console.warn(err);
        }
    };

    hasCameraPermission = async() => {
        try {
            const result = await PermissionsAndroid.check(
                PermissionsAndroid.PERMISSIONS.CAMERA);
            return result;
        } catch (err) {
            console.warn(err);
        }
    };

    checkCameraPermissionAndOpen = () => {
        this.hasCameraPermission().then((hasCameraPermission) => {
            console.log('hasCameraPermission result is ' + hasCameraPermission);
            if (hasCameraPermission) {
                console.log('Opening OCR directly');
                this.openOCR();
            } else {
                this.requestCameraPermission();
            }
        });
    };

    onResult = (dataString) => {
        const data = JSON.parse(dataString);

        this.setState({
            hasScanned: true,
            result: data.reading,
            imagePath: data.imagePath,
            fullImagePath: data.fullImagePath,
            scanMode: data.scanMode,
            meterType: data.meterType,
            cutoutBase64: data.cutoutBase64,
            fullImageBase64: data.fullImageBase64,
        });
    };

    onError = (error) => {
        console.error(error);
        alert(error);
    };

    render() {
        const {
            hasScanned,
            result,
            imagePath,
            fullImagePath,
            barcode,
            scanMode,
            meterType,
            cutoutBase64,
            fullImageBase64,
        } = this.state;

        const platformText = (Platform.OS === 'android') ?
            (<Text onPress={this.checkCameraPermissionAndOpen}>Open OCR reader!</Text>) :
            (<Text onPress={this.openOCR}>Open OCR reader!</Text>);

        return (
            <View style={styles.container}>
                {hasScanned ? (
                        <Result
                            result={result}
                            imagePath={imagePath}
                            fullImagePath={fullImagePath}
                            barcode={barcode}
                            scanMode={scanMode}
                            meterType={meterType}
                            cutoutBase64={cutoutBase64}
                            fullImageBase64={fullImageBase64}
                        />
                    ) : (
                        platformText
                    )}
            </View>
        );
    }
}


const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#F5FCFF',
    },
});

AppRegistry.registerComponent('Anyline', () => Anyline);

Meter config.js with Segment

Full Meter config example with Segment
export default {
    license: 'LICENSE_KEY_STRING',
    options: {
        captureResolution: '720p',
        cutout: {
            style: 'rect',
            alignment: 'top',
            offset: {
                'x': 0,
                'y': 120,
            },
            strokeWidth: 2,
            cornerRadius: 4,
            strokeColor: 'F21C0A',
            outerColor: '000000',
            outerAlpha: 0.3,
        },
        flash: {
            mode: 'manual',
            alignment: 'bottom_right',
        },
        beepOnResult: true,
        vibrateOnResult: true,
        blinkAnimationOnResult: true,
        cancelOnResult: true,
        reportingEnabled: true,
        visualFeedback: {
            style: 'rect',
            strokeColor: 'F21C0A',
            fillColor: '22F21C0A',
            cornerRadius: 2,
        },
        segment: {
            titles: [
                'Analog',
                'Digital'
            ],
            modes: [
                'ANALOG_METER',
                'DIGITAL_METER'
            ],
            tintColor: 'F21C0A',
            offset: {
                x: 0,
                y: 600
            }
        }
    },
    nativeBarcodeEnabled: true
}