UNPKG

5.61 kBPlain TextView Raw
1// Copyright 2016-present 650 Industries. All rights reserved.
2
3#import <EXBarCodeScanner/EXBarCodeScanner.h>
4#import <EXBarCodeScanner/EXBarCodeScannerUtils.h>
5#import <UMBarCodeScannerInterface/UMBarCodeScannerInterface.h>
6#import <UMCore/UMDefines.h>
7
8@interface EXBarCodeScanner() <AVCaptureMetadataOutputObjectsDelegate>
9
10@property (nonatomic, strong) AVCaptureMetadataOutput *metadataOutput;
11@property (nonatomic, weak) AVCaptureSession *session;
12@property (nonatomic, weak) dispatch_queue_t sessionQueue;
13@property (nonatomic, copy, nullable) void (^onBarCodeScanned)(NSDictionary*);
14@property (nonatomic, assign, getter=isScanningBarCodes) BOOL barCodesScanning;
15@property (nonatomic, strong) NSDictionary<NSString *, id> *settings;
16
17@end
18
19NSString *const EX_BARCODE_TYPES_KEY = @"barCodeTypes";
20
21@implementation EXBarCodeScanner
22
23- (instancetype)init
24{
25 if (self = [super init]) {
26 _settings = [[NSMutableDictionary alloc] initWithDictionary:[[self class] _getDefaultSettings]];
27 }
28 return self;
29}
30
31# pragma mark - JS properties setters
32
33- (void)setSettings:(NSDictionary<NSString *, id> *)settings
34{
35 for (NSString *key in settings) {
36 if ([key isEqualToString:EX_BARCODE_TYPES_KEY]) {
37 NSArray<NSString *> *value = settings[key];
38 NSSet *previousTypes = [NSSet setWithArray:_settings[EX_BARCODE_TYPES_KEY]];
39 NSSet *newTypes = [NSSet setWithArray:value];
40 if (![previousTypes isEqualToSet:newTypes]) {
41 NSMutableDictionary<NSString *, id> *nextSettings = [[NSMutableDictionary alloc] initWithDictionary:_settings];
42 nextSettings[EX_BARCODE_TYPES_KEY] = value;
43 _settings = nextSettings;
44 UM_WEAKIFY(self);
45 [self _runBlockIfQueueIsPresent:^{
46 UM_ENSURE_STRONGIFY(self);
47 [self maybeStartBarCodeScanning];
48 }];
49 }
50 }
51 }
52}
53
54- (void)setIsEnabled:(BOOL)newBarCodeScanning
55{
56 if ([self isScanningBarCodes] == newBarCodeScanning) {
57 return;
58 }
59 _barCodesScanning = newBarCodeScanning;
60 UM_WEAKIFY(self);
61 [self _runBlockIfQueueIsPresent:^{
62 UM_ENSURE_STRONGIFY(self);
63 if ([self isScanningBarCodes]) {
64 if (self.metadataOutput) {
65 [self _setConnectionsEnabled:true];
66 } else {
67 [self maybeStartBarCodeScanning];
68 }
69 } else {
70 [self _setConnectionsEnabled:false];
71 }
72 }];
73}
74
75# pragma mark - Public API
76
77- (void)maybeStartBarCodeScanning
78{
79 if (!_session || !_sessionQueue || ![self isScanningBarCodes]) {
80 return;
81 }
82
83 if (!_metadataOutput) {
84 [_session beginConfiguration];
85
86 AVCaptureMetadataOutput *metadataOutput = [[AVCaptureMetadataOutput alloc] init];
87 [metadataOutput setMetadataObjectsDelegate:self queue:_sessionQueue];
88 if ([_session canAddOutput:metadataOutput]) {
89 [_session addOutput:metadataOutput];
90 _metadataOutput = metadataOutput;
91 }
92 [_session commitConfiguration];
93
94 if (!_metadataOutput) {
95 return;
96 }
97 }
98
99 NSArray<AVMetadataObjectType> *availableRequestedObjectTypes = @[];
100 NSArray<AVMetadataObjectType> *requestedObjectTypes = @[];
101 NSArray<AVMetadataObjectType> *availableObjectTypes = _metadataOutput.availableMetadataObjectTypes;
102 if (_settings && _settings[EX_BARCODE_TYPES_KEY]) {
103 requestedObjectTypes = [[NSArray alloc] initWithArray:_settings[EX_BARCODE_TYPES_KEY]];
104 }
105
106 for(AVMetadataObjectType objectType in requestedObjectTypes) {
107 if ([availableObjectTypes containsObject:objectType]) {
108 availableRequestedObjectTypes = [availableRequestedObjectTypes arrayByAddingObject:objectType];
109 }
110 }
111
112 [_metadataOutput setMetadataObjectTypes:availableRequestedObjectTypes];
113}
114
115- (void)stopBarCodeScanning
116{
117 if (!_session) {
118 return;
119 }
120
121 [_session beginConfiguration];
122
123 if ([_session.outputs containsObject:_metadataOutput]) {
124 [_session removeOutput:_metadataOutput];
125 _metadataOutput = nil;
126 }
127
128 [_session commitConfiguration];
129
130 if ([self isScanningBarCodes] && _onBarCodeScanned) {
131 _onBarCodeScanned(nil);
132 }
133}
134
135# pragma mark - Private API
136
137- (void)_setConnectionsEnabled:(BOOL)enabled
138{
139 if (!_metadataOutput) {
140 return;
141 }
142 for (AVCaptureConnection *connection in _metadataOutput.connections) {
143 connection.enabled = enabled;
144 }
145}
146
147- (void)_runBlockIfQueueIsPresent:(void (^)(void))block
148{
149 if (_sessionQueue) {
150 dispatch_async(_sessionQueue, block);
151 }
152}
153
154# pragma mark - AVCaptureMetadataOutputObjectsDelegate
155
156- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects
157 fromConnection:(AVCaptureConnection *)connection
158{
159 if (!_settings || !_settings[EX_BARCODE_TYPES_KEY] || !_metadataOutput) {
160 return;
161 }
162
163 for(AVMetadataObject *metadata in metadataObjects) {
164 if([metadata isKindOfClass:[AVMetadataMachineReadableCodeObject class]]) {
165 AVMetadataMachineReadableCodeObject *codeMetadata = (AVMetadataMachineReadableCodeObject *) metadata;
166 for (id barcodeType in _settings[EX_BARCODE_TYPES_KEY]) {
167 if ([metadata.type isEqualToString:barcodeType]) {
168
169 NSDictionary *event = @{
170 @"type" : codeMetadata.type,
171 @"data" : codeMetadata.stringValue
172 };
173
174 if (_onBarCodeScanned) {
175 _onBarCodeScanned(event);
176 }
177 return;
178 }
179 }
180 }
181 }
182}
183
184# pragma mark - default settings
185
186+ (NSDictionary *)_getDefaultSettings
187{
188 return @{
189 EX_BARCODE_TYPES_KEY: [[EXBarCodeScannerUtils validBarCodeTypes] allValues],
190 };
191}
192
193@end