@@ -869,22 +869,58 @@ - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:
869
869
for (id barcodeType in self.barCodeTypes ) {
870
870
if ([metadata.type isEqualToString: barcodeType]) {
871
871
AVMetadataMachineReadableCodeObject *transformed = (AVMetadataMachineReadableCodeObject *)[_previewLayer transformedMetadataObjectForMetadataObject: metadata];
872
- NSDictionary *event = @{
873
- @" type" : codeMetadata.type ,
874
- @" data" : codeMetadata.stringValue ,
875
- @" bounds" : @{
876
- @" origin" : @{
877
- @" x" : [NSString stringWithFormat: @" %f " , transformed.bounds.origin.x],
878
- @" y" : [NSString stringWithFormat: @" %f " , transformed.bounds.origin.y]
879
- },
880
- @" size" : @{
881
- @" height" : [NSString stringWithFormat: @" %f " , transformed.bounds.size.height],
882
- @" width" : [NSString stringWithFormat: @" %f " , transformed.bounds.size.width]
883
- }
884
- }
885
- };
886
-
887
- [self onCodeRead: event];
872
+ NSMutableDictionary *event = [NSMutableDictionary dictionaryWithDictionary: @{
873
+ @" type" : codeMetadata.type ,
874
+ @" data" : [NSNull null ],
875
+ @" rawData" : [NSNull null ],
876
+ @" bounds" : @{
877
+ @" origin" : @{
878
+ @" x" : [NSString stringWithFormat: @" %f " , transformed.bounds.origin.x],
879
+ @" y" : [NSString stringWithFormat: @" %f " , transformed.bounds.origin.y]
880
+ },
881
+ @" size" : @{
882
+ @" height" : [NSString stringWithFormat: @" %f " , transformed.bounds.size.height],
883
+ @" width" : [NSString stringWithFormat: @" %f " , transformed.bounds.size.width]
884
+ }
885
+ }
886
+ }
887
+ ];
888
+
889
+ NSData *rawData;
890
+ // If we're on ios11 then we can use `descriptor` to access the raw data of the barcode.
891
+ // If we're on an older version of iOS we're stuck using valueForKeyPath to peak at the
892
+ // data.
893
+ if (@available (iOS 11 , *)) {
894
+ // descriptor is a CIBarcodeDescriptor which is an abstract base class with no useful fields.
895
+ // in practice it's a subclass, many of which contain errorCorrectedPayload which is the data we
896
+ // want. Instead of individually checking the class types, just duck type errorCorrectedPayload
897
+ if ([codeMetadata.descriptor respondsToSelector: @selector (errorCorrectedPayload )]) {
898
+ rawData = [codeMetadata.descriptor performSelector: @selector (errorCorrectedPayload )];
899
+ }
900
+ } else {
901
+ rawData = [codeMetadata valueForKeyPath: @" _internal.basicDescriptor.BarcodeRawData" ];
902
+ }
903
+
904
+ // Now that we have the raw data of the barcode translate it into a hex string to pass to the JS
905
+ const unsigned char *dataBuffer = (const unsigned char *)[rawData bytes ];
906
+ if (dataBuffer) {
907
+ NSMutableString *rawDataHexString = [NSMutableString stringWithCapacity: ([rawData length ] * 2 )];
908
+ for (int i = 0 ; i < [rawData length ]; ++i) {
909
+ [rawDataHexString appendString: [NSString stringWithFormat: @" %02lx " , (unsigned long )dataBuffer[i]]];
910
+ }
911
+ [event setObject: [NSString stringWithString: rawDataHexString] forKey: @" rawData" ];
912
+ }
913
+
914
+ // If we were able to extract a string representation of the barcode, attach it to the event as well
915
+ // else just send null along.
916
+ if (codeMetadata.stringValue ) {
917
+ [event setObject: codeMetadata.stringValue forKey: @" data" ];
918
+ }
919
+
920
+ // Only send the event if we were able to pull out a binary or string representation
921
+ if ([event objectForKey: @" data" ] != [NSNull null ] || [event objectForKey: @" rawData" ] != [NSNull null ]) {
922
+ [self onCodeRead: event];
923
+ }
888
924
}
889
925
}
890
926
}
0 commit comments