The Anyline SDK

This section describes how to implement and use the Anyline SDK in your iOS application.

Overview

Anyline consists of a number of components working together to accomplish a scan. Each component corresponds in the iOS SDK to a class or protocol in Swift as well as in Objective-C.

The SDK classes you are most likely to interact with would be the ALScanView and the ALScanPluginDelegate:

  • ALScanView - a UIView that contains the scanning interface: a camera view as well as a flash/torch component.

  • ALScanPluginDelegate - a protocol containing methods allowing the delegate to handle the received scan result.

In addition, depending on your specific needs your code may also need to directly (or indirectly) interact with some additional components:

  • ALViewPluginBase - a protocol an instance (or instances) of whom is held by an ALScanView, defining functionality implemented by both ALScanViewPlugin and ALViewPluginComposite.

  • ALScanViewPlugin - an object responsible for the scan view user interface and visual feedback elements.

  • ALViewPluginComposite - an object running multiple instances of ALScanViewPlugin.

  • ALScanPlugin - an object held by ALScanViewPlugin, which handles the scanning capabilities as well as low-level image processing, and which sends any scan results back to its ALScanPluginDelegate.

Adding Anyline to your Scanning Workflow

By this time, you should already have initialized the Anyline SDK with the license key for your application. For more details, please see Initialize the Anyline SDK.

For the code snippets below, and the ones the follow, it is assumed that the Anyline framework has been imported into the source code where you are using Anyline:

  • Swift

  • Objective-C

import Anyline
#include <Anyline/Anyline.h>

Add the ScanView to your view hierarchy

To present a scan view with your configuration, a configured ALScanView needs to be added to a UIViewController 's view hierarchy.

The simplest and recommended way to do so is to create an ALScanView with a factory method. In viewDidLoad,

  • Swift

  • Objective-C

let JSONStr = "{\"viewPluginConfig\":{\"pluginConfig\":{\"tinConfig\":{\"scanMode\":\"DOT\"},\"cancelOnResult\":true},\"scanFeedbackConfig\":{\"style\":\"contour_rect\"}}}"

do {
    self.scanView = try ALScanViewFactory.withJSONString(JSONStr, delegate: self)
} catch {
    // handle the error
}

if let scanView = self.scanView {
    // add scan view to the view hierarchy
    view.addSubview(scanView)
    // set the scan view's frame (either programmatically or via AutoLayout)
    scanView.frame = view.frame
    // ...
    scanView.startCamera()
}
NSString JSONString = @"{\"viewPluginConfig\":{\"pluginConfig\":{\"tinConfig\":{\"scanMode\":\"DOT\"},\"cancelOnResult\":true},\"scanFeedbackConfig\":{\"style\":\"contour_rect\"}}}";

NSError *error;
self.scanView = [ALScanViewFactory withJSONString:JSONString delegate:self error:&error];

if (self.scanView) {
    [self addScanViewToViewHierarchy(self.scanView);
    [self.scanView startCamera];
}

Starting Anyline 53, changes have been made to the way in which a ScanView is constructed and set up. For more information, please refer to Migrating to Anyline 53.

While creating each component, it is recommended that you handle any errors during any class’s initializer. For instance with Swift, use a try operator with a ScanViewPlugin or ViewPluginConfig initializer and handle any errors thrown from the catch block. For Objective-C, pass in a non-null NSError reference to the error: parameter.

Note that if an error object has been passed back with a non-null value, then the object associated with the initializer was likely not successfully created, so the error object can provide some insight into the problem and potentially suggest a course of action.

The above example creates an ALScanView configured with the included JSON string, which should be a valid Anyline config. If the string is not a valid config, the view will not be created, and an error would be thrown. You would then need to provide a way to handle this error.

Do not forget to also add the ALScanView to your view hierarchy and configure it as you would with any other UIView object (including setting its frame), and then call its startCamera method.

In addition, you should implement the ALScanPluginDelegate protocol in your delegate class (here it would be the UIViewController) and then start the scanning process (refer to the following sections).

Start the Scanning Process

To start the scanning process, simply call the startScanning method from the ScanView (typically after its camera has been started). Doing so will begin to process the frame images that are provided by the device’s camera module.

  • Swift

  • Objective-C

do {
    try self.scanView.startScanning()
} catch {
    // handle any errors
}
NSError *error;
[scanViewPlugin startWithError:&error];
// handle any errors

Implement the ScanPluginDelegate

After some time, assuming conditions for a successful scan are met, results from a scan will be returned by Anyline. To use the results obtained from the scanning process, have your UIViewController or another object implement the ALScanPluginDelegate protocol:

  • Swift

  • Objective-C

class MeterScanViewController: UIViewController, ALScanPluginDelegate { … }
@interface MeterScanViewController: UIViewController <ALScanPluginDelegate>

Then, implement a number of methods from this protocol. This will be discussed in more detail in a subsequent section. At the very least, have your delegate implement the scanPlugin(_:resultReceived:): method (the scanResult parameter and more specifically its pluginResult object holds the results of the scan process):

  • Swift

  • Objective-C

func scanPlugin(_ scanPlugin: ALScanPlugin, resultReceived scanResult: ALScanResult) {
    print("the result: \(scanResult.pluginResult.meterResult?.value ?? "")")
}
- (void)scanPlugin:(ALScanPlugin *)scanPlugin resultReceived:(ALScanResult *)scanResult {
    NSLog(@"the result: ", scanResult.pluginResult.meterResult.value);
}

Complete Source Code

The source code for the above example is shown here:

  • Swift

  • Objective-C

import Anyline

class MeterScanViewController: UIViewController {

    fileprivate var scanView: ALScanView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let JSONStr = """
{\"viewPluginConfig\":{\"pluginConfig\":{\"id\":\"meter_auto\",\"meterConfig\":{\"scanMode\":\"auto_analog_digital_meter\"},\"cancelOnResult\":true},\"cutoutConfig\":{\"maxWidthPercent\":\"80%\",\"ratioFromSize\":{\"width\":3,\"height\":1}},\"scanFeedbackConfig\":{}}}
"""
        do {
            self.scanView = try ALScanViewFactory.withJSONString(JSONStr, delegate: self)
            self.installScanView(scanView)
            self.scanView.startCamera()
            try self.scanView?.startScanning()
        } catch {
            print("error: \(error.localizedDescription)")
        }
    }

    fileprivate func installScanView(_ scanView: ALScanView) {
        self.view.addSubview(scanView)
        scanView.translatesAutoresizingMaskIntoConstraints = false
        scanView.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
        scanView.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true
        scanView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
        scanView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
    }
}

extension MeterScanViewController: ALScanPluginDelegate {

    func scanPlugin(_ scanPlugin: ALScanPlugin, resultReceived scanResult: ALScanResult) {
        print(scanResult.pluginResult.meterResult?.value ?? "")
    }
}
#import <Anyline/Anyline.h>

@interface MeterScanViewController : UIViewController <ALScanPluginDelegate>

@property (nonatomic, strong) ALScanView *scanView;

@end


@implementation MeterScanViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    NSString *config = @"{\"viewPluginConfig\":{\"pluginConfig\":{\"id\":\"meter_auto\",\"meterConfig\":{\"scanMode\":\"auto_analog_digital_meter\"},\"cancelOnResult\":true},\"cutoutConfig\":{\"maxWidthPercent\":\"80%\",\"ratioFromSize\":{\"width\":3,\"height\":1}},\"scanFeedbackConfig\":{}}}";

    NSError *error;
    self.scanView = [ALScanViewFactory withJSONString:config delegate:self error:&error];
    if (!self.scanView) {
        // handle error
    }

    [self installScanView:self.scanView];
    [self.scanView startCamera];

    BOOL success = [self.scanView startScanningWithError:&error];
    if (success) {
        // handle error
    }
}


// MARK: - Handle & present results

- (void)installScanView:(ALScanView *)scanView {
    [self.view addSubview:scanView];

    scanView.translatesAutoresizingMaskIntoConstraints = false;
    [scanView.leftAnchor constraintEqualToAnchor:self.view.leftAnchor].active = YES;
    [scanView.rightAnchor constraintEqualToAnchor:self.view.rightAnchor].active = YES;
    [scanView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor].active = YES;
    [scanView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES;
}

- (void)scanPlugin:(ALScanPlugin *)scanPlugin resultReceived:(ALScanResult *)scanResult {
    NSLog(@"result: %@", scanResult.pluginResult.meterResult.value);
}

@end

Questions or need further assistance? Please reach out to the Anyline Support Helpdesk.