Skip to content

Instantly share code, notes, and snippets.

@Nikituh
Last active July 29, 2020 10:51
Show Gist options
  • Save Nikituh/71a73f26c153aa9eb8f01df33c5ef7e0 to your computer and use it in GitHub Desktop.
Save Nikituh/71a73f26c153aa9eb8f01df33c5ef7e0 to your computer and use it in GitHub Desktop.
Scanbot react-native rough draft

React Native – A new standard for Document Scanning with Scanbot

Introduction

Ever since it was announced 2013, React has been gaining more and more traction in the world of software development. Reactive Design Pattern has become a well-known term in itself, no longer tied to the world of Facebook's React (although the origin of the term is somewhat contested).

Shortly thereafter, in 2015, the development team at Facebook also delved into the world of mobile development, creating their own framework called React Native. I, like most developers, was skeptical at first – yet another platform, just make things more complicated. And for the first few years, I was probably right to be skeptical, as react native has gone through several "phases", introducing radical updates that have brought more pain than pleasure to developers

However, in the past few years, React Native has "grown up" and has proven itself to be a formidable force in the world of Cross-Platform Mobile Development. But I digress, for the time being, I am not here to compare mobile frameworks. Let's build a Scanbot Document Scanner App with React Native!

Getting Started with React

Tools

First off, React Native is not "magic". In layman's terms, it's just a blanket on top of a native iOS and Android app that offers and unified API for rendering views. Therefore, we require the same basic mobile development tools as if we were doing it in Java or Objective-C:

Then, it's wise to have java and path set in your path. It's wise, but if you're on a clean install of Android Studio, haven't made any previous java- or gradle-related installs, it shouldn't be necessary.

This will let the React CLI know which java to use (in case you've downloaded several versions of java). I advise to use OpenJDK 8 for Android development (11 should be fine, 14 is iffy with older versions of gradle). You can just download and in stall it – a couple o' clicks and you're done.

Then, on a Mac or Linux, go to /Users/$USER/ and open .bash_profile, .zshrc or .bashrc with you preferred text editor and add the following lines to it:

export JAVA_HOME=/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home
export ANDROID_HOME=/Users/$USER/Library/Android/sdk
export PATH=${PATH}:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools

After that, source <filename> to reload the file. That's it!

Note that I've also added platform-tools to my path. That is not required, but very handy for debugging all possible things, most notably the command adb devices will show whether you have a debuggable device available or not.

And finally, the tools required for the React Native layer to properly function:

I personally prefer installing everything through brew. The setup is quite simple. First, install brew:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"

Then, make sure it's up to date and install node:

brew update
brew install node

And that's it. You're now just about ready to start coding. One last hint from the official React Native environment setup guide:

React Native has a built-in command line interface. Rather than install and manage a specific version of the CLI globally, we recommend you access the current version at runtime using npx, which ships with Node.js. With npx react-native <command>, the current stable version of the CLI will be downloaded and executed at the time the command is run.

Hello World!

The hard part was setting up the environment. From now on it's smooth sailing ⛵

We'll be using typescript for this example, as it is the recommended approach for writing javascript these days (besides, I personally prefer strongly-typed languages, much less #yolo). Run the following:

npx react-native init ScanbotApp --template react-native-template-typescript

That should take a couple of minutes but it's also an awesome one-liner that does absolutely everything for you: everying from creating and configuring the native projects to npm install. After that's done, simply:

cd ScanbotApp  
react-native run-android

And you should be greeted by the following:

Scanbot SDK

Now we finally get to the good stuff – Scanbot! If you're reading this, you're probably aware of what npm is, nevertheless, in short, your "Hello World" app has a file called package.json that defines all the dependencies you have. As you can see, react-native itself already defines a whole bunch of them, everything from linters to typescript to jsx syntax.

Let's add another one there (to dependencies, not devDependencies, as we need the ScanbotSDK during runtime as well, not just for development purposes) and then install it via npm install:

"react-native-scanbot-sdk": "4.1.0"

iOS

Since ScanbotSDK for react-native is a wrapper of the native SDK, an additional step is to also download the native SDK. As of react-native version 0.62, native dependencies are automatically resolved and you do not need to add anything to the Podfile (iOS native equivalent of package.json), but you do still have to go to the iOS folder and install native dependencies:

  • cd ios
  • pod install

That was almost too easy, wasn't it? Well, this isn't over yet...

Android

As with most things in mobile development, you expect the android equivalent of something to be a bit more difficult to configure. This isn't necessarily a bad thing, quite the opposite, having more options to configure is mostly a good a thing. It can get somewhat frustrating, though.

To configure gradle-level requirements, we advise Android Studio, as it supports better syntax highlighting and a visual interface. You are, of course, free to use any text editor – even Nodepad will do the trick.

First, you should enable multidex. That's done via adding multiDexEnabled true to your android/app/build.gradle as such:

defaultConfig {
    applicationId "com.scanbotapp"
    minSdkVersion rootProject.ext.minSdkVersion
    targetSdkVersion rootProject.ext.targetSdkVersion
    versionCode 1
    versionName "1.0"
    multiDexEnabled true
 }

Enabling MultiDex is just a fancy way of saying "Yes, I know this app has a heavy-weight ML-based document scanning SDK and I don't care".

Right there in the same file, you should also specify that it should pick the first instance of libc++_shared.so that it finds, on the same level as defaultConfig , as follows:

packagingOptions {
    pickFirst '**/libc++_shared.so'
}

This needs to be specified because many third-party dependencies have native binaries that use the c++ shared library (in the context of gradle, react-native itself is a third-party dependency that uses it, and so does ScanbotSDK).

Another thing you should add is android:largeHeap="true" and that under your application tag of android/app/src/main/AndroidManifest.xml file, as such:

<application 
      android:largeHeap="true"
      android:name=".MainApplication"
      ...

That's just a fancy way of saying what MultiDex is for, except that multidex is for compile-time, largeHeap is for runtime.

Next, you should also add ScanbotSDK paths to your application-level gradle (android/build.gradle). That way, gradle knows exactly where to find our SDK:

allprojects {
    repositories {
	      ...
        // Scanbot SDK Maven repositories:
        maven { url 'https://nexus.scanbot.io/nexus/content/repositories/releases/' }
        maven { url 'https://nexus.scanbot.io/nexus/content/repositories/snapshots/' }
    }
}

Right there in your application-level gradle, you should also increase the minSdkVersion to 21, which is a requirement for the latest versions of ScanbotSDK (and, unless specifically requested otherwise, in general a good idea – supporting backwards compatibility below Android 5.0 is a nightmare).

And finally, specify where react-native-scanbot-sdk is located in your repository. That can be achieved by adding the following lines to android/settings.gradle:

include ':react-native-scanbot-sdk'
project(':react-native-scanbot-sdk').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-scanbot-sdk/android/app')

Wipes sweat off forehead... And that's all there is to it!

React-Native

If we're both using the the same app template, you should also be able to do the following. For the sake of simplicity, slap a click-handler to the to a TextView, e.g. the following line:

<Text style={styles.sectionTitle} >Step One</Text>

becomes:

<Text
  style={styles.sectionTitle}
  onPress={() => {
    console.log('Hello click-handler!');
  }}>
  Step One
</Text>

Then, let's just create a global variable to decide what our click-handler should actually do:

let initialized = false;

Now that the basics are out of the way, it's time to start working with the SDK.

Before we begin, you should define the imports. For this example, we just need three things: the SDK itself, and then to option and configuration classes:

import ScanbotSDK, {
  BarcodeScannerConfiguration,
  InitializationOptions,
} from 'react-native-scanbot-sdk/src';

The first real step is initialisation. That goes as follows:

const options: InitializationOptions = {
  licenseKey: '',
};
await ScanbotSDK.initializeSDK(options);

Similarily, to start the QR- and Barcode scanner, the snippet is as follows:

const configuration: BarcodeScannerConfiguration = {};
const result = await ScanbotSDK.UI.startBarcodeScanner(configuration);

Just to review, your entire onPress should look like this:

onPress={async () => {
  if (!initialized) {
    const options: InitializationOptions = {
      licenseKey: '',
    };
    await ScanbotSDK.initializeSDK(options);
    initialized = true;
    Alert.alert("SDK initialized", "Press me again to start Barcode Scanner");
  } else {
    const configuration: BarcodeScannerConfiguration = {};
    const result = await ScanbotSDK.UI.startBarcodeScanner(configuration);
    if (result?.barcodes?.length > 0) {
      Alert.alert("Barcode detected", result.barcodes[0].text);
    }
  }
}}>

Now that we've got everyting sorted out, go ahead and scan the following QR code:

Reactive UI design

// TODO advanced sample, displaying scanned documents, updating texts etc

Conclusion & References

While every cross-platform solution does have its problems in the form of internal inconsistencies, the simplicity and and elegance of react does make software development very smooth and, dare I say, "fun".

I'm sure that, at this point, you'd like to know more about the possibilities with react-native and ScanbotSDK. Here are a few links for you:

  • Explore the features of ScanbotSDK in our example app
  • If you've had enough of coding for now, that's fine, everyone needs a break. Then, have a look at our extensive documentation

TODO Notes:

  • Title
  • Introduction a bit much?
  • Inconsistent level of technical detai
  • Conclusion?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment