Migrating to Anyline 43.0.0
We have completed a major update to the Anyline classes in version 43. If you are coming from a previous Anyline version, it is helpful to go over some of the more significant changes in this page. For more detailed information about the classes, please head over to API Documentation.
It is also worth having a look at Plugin Configuration for more specific implementation guidance.
New way to initialize the scan plugin
ScanPlugins, ScanViewPlugins, etc., have seen changes in the ways in which they are initialized with Anyline 43.
With earlier versions, in order to implement a scan use case, you would initialize the following components:
1) a ScanView, 2) a ScanViewPlugin, and 3) a ScanPlugin, and with the latter two components, concrete
instances specific to your scanning use case should be chosen, such as for instance ALOCRScanPlugin
and ALOCRScanViewPlugin
:
ALOCRConfig *config = [self getOCRConfig];
NSError *error = nil;
ALOCRScanPlugin *serialNumberScanPlugin = [[ALOCRScanPlugin alloc] initWithPluginID:@"ANYLINE_OCR"
delegate:self
ocrConfig:config
error:&error];
ALScanViewPluginConfig *scanViewPluginConfig = [self getScanViewPluginConfig];
serialNumberScanViewPlugin = [[ALOCRScanViewPlugin alloc] initWithScanPlugin:self.serialNumberScanPlugin
scanViewPluginConfig:scanViewPluginConfig];
[serialNumberScanViewPlugin addScanViewPluginDelegate:self];
self.scanView = [[ALScanView alloc] initWithFrame:frame
scanViewPlugin:self.serialNumberScanViewPlugin];
With Anyline 43, it now becomes possible to only initialize an ALScanView
and an
ALScanViewPlugin
(from the latter a suitable ALScanPlugin
will also be automatically initialized), by passing
in configuration objects targeting the scanning use case you intend to use.
Note that unlike with previous versions, ALScanViewPlugin
and ALScanPlugin
are the concrete classes to use in
your application code – rather than say, ALOCRScanViewPlugin
or ALOCRScanPlugin
.
In addition, when initializing a ScanView, a scan view config object is required along with a scan view plugin.
-
Swift
-
Objective-C
let serialNrConfigJSONStr = self.getSerialNumberConfigJSONString()
// The SDK provides a number of NSString extension methods like this one to deserialize a
// potential JSON object(s) in an NSString (for more info, see ALJSONExtras extension in ALJSONUtilities.h)
guard let configJSONDict = serialNrConfigJSONStr.asJSONObject() else {
// handle the error
return;
}
do {
let scanViewPlugin = try ALScanViewPlugin(jsonDictionary: configJSONDict)
} catch {
// handle `error`, if necessary
}
// Notice here that `scanPlugin` is already a part of the ScanViewPlugin that had been created
scanViewPlugin.scanPlugin.delegate = self
let scanView = ALScanView(frame: frame, scanViewPlugin: scanViewPlugin)
view.addSubview(scanView)
scanView.startCamera()
NSString *serialNrConfigJSONStr = [self getSerialNumberConfigJSONString];
// The SDK provides a number of NSString extension methods like this one to deserialize a
// potential JSON object(s) in an NSString (for more info, see ALJSONExtras extension in ALJSONUtilities.h)
NSDictionary *configJSONDict = [serialNrConfigJSONStr asJSONObject];
ALScanViewPlugin *scanViewPlugin = [[ALScanViewPlugin alloc] initWithJSONDictionary:configJSONDict
error:&error];
// handle `error`, if necessary
// Notice here that `scanPlugin` is already a part of the ScanViewPlugin that had been created
scanViewPlugin.scanPlugin.delegate = self;
ALScanView *scanView = [[ALScanView alloc] initWithFrame:frame
scanViewPlugin:scanViewPlugin
error:&error];
[self.view add:scanView];
[self.scanView startCamera];
As you can see here, ALScanViewPlugin
is the only scan view plugin class used, with the particulars for serial number
scanning being completely defined within the configuration object defined here in JSON.
As discussed in Building Plugins Programmatically, it is possible to still create and structure Anyline components without JSON configs, however, our recommendation is to initialize components using properly-formatted JSON config files. |
An ALScanView
can also be initialized with an optional ALScanViewConfig
parameter:
-
Swift
-
Objective-C
try ALScanView(frame: frame, scanViewPlugin: anyScanViewPlugin, scanViewConfig: anyScanViewConfig)
[[ALScanView alloc] initWithFrame:anyFrame scanViewPlugin:anyScanViewPlugin scanViewConfig:anyScanViewConfig error:&error]
After initializing an To achieve the desired outcome, you should instead fully recreate a new |
Composite Plugins
Nesting composite plugins is currently not supported in this version of Anyline. |
The ALPluginComposite
class, which replaces the old plugin composite type ALAbstractScanViewPluginComposite
,
is now (along with ALScanViewPlugin
) a concrete implementation of the ALScanViewPluginBase
protocol.
ALPluginComposite
is now used for both parallel and sequential scanning modes, replacing the concrete classes
(ALParallelScanViewPluginComposite
and ALSerialScanViewPluginComposite
) from the previous version.
We’ve also added a ALScanViewPluginFactory
helper class, with a method to conveniently initialize either a
composite or a non-composite scan view plugin based on the supplied JSON configuration object:
-
Swift
-
Objective-C
let scanViewPlugin: ALScanViewPluginBase = ALScanViewPluginFactory.withJSONDictionary(self.getJSONConfigDict())
if scanViewPlugin is ALScanViewPlugin {
// treat scanViewPlugin as an ALScanViewPlugin
} else if scanViewPlugin is ALViewPluginComposite {
// treat scanViewPlugin as an ALViewPluginComposite
}
NSObject<ALScanViewPluginBase> *scanViewPlugin = [ALScanViewPluginFactory withJSONDictionary:[self getJSONConfigDict]];
if ([scanViewPlugin isKindOfClass:[ALScanViewPlugin class]]) {
// treat scanViewPlugin as an ALScanViewPlugin
} else if ([scanViewPlugin isKindOfClass:[ALViewPluginComposite class]]) {
// treat scanViewPlugin as an ALViewPluginComposite
}
ALPluginComposite
comes with a new delegate type called ALPluginCompositeDelegate
, which includes the method
-viewPluginComposite:allResultsReceived:
that is called when results from all children plugins have been successfully
scanned. You may still subscribe to child scan plugin events individually (ie setting their delegates) by accessing them
through the children
property:
-
Swift
-
Objective-C
// Here we think `viewPlugin` may be a composite based on the JSON config provided
let viewPlugin: ALScanViewPluginBase = ALScanViewPluginFactory.withJSONDictionary(JSONConfigDict)
// subscribe to children plugin callback events
for child in viewPlugin.children {
if child is ALScanViewPlugin {
(child as! ALScanViewPlugin).scanPlugin.delegate = self
}
}
// Here we think `viewPlugin` may be a composite based on the JSON config provided
NSObject<ALScanViewPluginBase> *viewPlugin = [ALScanViewPluginFactory withJSONDictionary:JSONConfigDict];
// subscribe to children plugin callback events
for (NSObject<ALScanViewPluginBase> *child in viewPlugin.children) {
if ([child isKindOfClass:ALScanViewPlugin.class]) {
((ALScanViewPlugin *)child).scanPlugin.delegate = self;
}
}
New JSON config file structure
There are changes as well with the way Anyline structures parses JSON config files starting with version
43. Now, any top-level config key name ends with Config
(for instance, scanFeedBackConfig
, flashConfig
, etc).
{
"cameraConfig": {
...
},
"flashConfig": {
...
},
"viewPluginConfig": {
"pluginConfig": {
...
},
"cutoutConfig": {
...
},
"scanFeedbackConfig": {
...
}
}
}
Keys in the config JSON are case-sensitive. Do not write, say, scanfeedbackConfig (lowercase 'F') where
scanFeedbackConfig is required.
|
Here’s a direct comparison of the same JSON configuration in the old vs. new style:
Old JSON |
New JSON |
|
|
1 | camera is now called cameraConfig (see 7.) |
2 | flash is now called flashConfig (see 8.) |
3 | viewPlugin is now called viewPluginConfig (see 9.) |
4 | plugin is now called pluginConfig and no longer contains a specific 'plugin', but instead, an XXXConfig object
specific to the scanning use case (in this case a meterConfig ) |
5 | scanFeedback is now called scanFeedbackConfig (see 11.) |
6 | cancelOnResult is not part of the viewPlugin anymore, instead it is part of the pluginConfig (see 10.) |
Please refer to Plugin Configuration for more details.
There is a slight change in cutoutConfig on how the cropPadding property works. cropPadding now only takes
positive values, so for example if you use a value of 5 for the horizontal padding, it will now crop off 5 pixels from
each side of the cutout.
|
New delegate methods
We’ve also made some changes to the Objective-C delegates to ALScanPlugin
, ALScanViewPlugin
, and ALScanView
,
standardizing their interface and eliminating the need to implement delegate protocols for different use cases.
Delegates such as ALOCRScanPluginDelegate
, ALIDPluginDelegate
, and so on, no longer exist in the new version
and have now been replaced by a single protocol: ALScanPluginDelegate
.
- (void)anylineOCRScanPlugin:(ALOCRScanPlugin *)anylineOCRScanPlugin
didFindResult:(ALOCRResult *)result {
// ...
}
- (void)anylineLicensePlateScanPlugin:(ALLicensePlateScanPlugin *)anylineLicensePlateScanPlugin
didFindResult:(ALLicensePlateResult *)result {
// ...
}
-
Swift
-
Objective-C
func scanPlugin(_ scanPlugin: ALScanPlugin, resultReceived scanResult: ALScanResult) {
// (access license plate results or OCR results in the same method)
}
- (void)scanPlugin:(ALScanPlugin *)scanPlugin
resultReceived:(ALScanResult *)scanResult {
// (access license plate results or OCR results in the same method)
}
To round it up, here are the other methods from ALScanPluginDelegate
that provide additional information about a
scanning session (all methods are optional):
-
Swift
-
Objective-C
protocol ALScanPluginDelegate {
func scanPlugin(_ scanPlugin: ALScanPlugin, resultReceived scanResult: ALScanResult)
func scanPlugin(_ scanPlugin: ALScanPlugin, errorReceived event: ALEvent)
func scanPlugin(_ scanPlugin: ALScanPlugin, scanRunSkipped event: ALEvent)
func scanPlugin(_ scanPlugin: ALScanPlugin, scanInfoReceived event: ALEvent)
func scanPlugin(_ scanPlugin: ALScanPlugin, visualFeedbackReceived event: ALEvent)
}
@protocol ALScanPluginDelegate <NSObject>
@optional
- (void)scanPlugin:(ALScanPlugin *)scanPlugin errorReceived:(ALEvent *)event;
- (void)scanPlugin:(ALScanPlugin *)scanPlugin visualFeedbackReceived:(ALEvent *)event;
- (void)scanPlugin:(ALScanPlugin *)scanPlugin scanInfoReceived:(ALEvent *)event;
- (void)scanPlugin:(ALScanPlugin *)scanPlugin scanRunSkipped:(ALEvent *)event;
@end
In each method, the ALEvent
parameter can be examined by using the JSONObject
(or JSONStr
) property.
A new result type
ALScanResult
is now structured in a way in that result types of use cases we support are now strongly-typed and
are defined as part of the result object.
This means that for example if you are scanning OCRs, then an ocrResult
will be a non-null property that you can expect to find the scan result within ALScanResult
.
-
Swift
-
Objective-C
func scanPlugin(_ scanPlugin: ALScanPlugin, resultReceived scanResult: ALScanResult) {
// the scanned OCR result
let ocrString = scanResult.pluginResult.ocrResult?.text
}
- (void)scanPlugin:(ALScanPlugin *)scanPlugin resultReceived:(ALScanResult *)scanResult {
// the scanned OCR result
NSString *ocrString = scanResult.pluginResult.ocrResult.text;
}
Check the API Documentation section for more result types.
👉 Have a look at the Scanning Capabilities section for more specific implementation details. 👈
Questions or need further assistance? Please reach out to the Anyline Support Helpdesk.