@unif/react-native-hms-scan 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,8 +5,8 @@ import com.facebook.react.uimanager.SimpleViewManager
5
5
  import com.facebook.react.uimanager.ThemedReactContext
6
6
  import com.facebook.react.uimanager.ViewManagerDelegate
7
7
  import com.facebook.react.uimanager.annotations.ReactProp
8
- import com.facebook.react.viewmanagers.HmsScanViewManagerInterface
9
8
  import com.facebook.react.viewmanagers.HmsScanViewManagerDelegate
9
+ import com.facebook.react.viewmanagers.HmsScanViewManagerInterface
10
10
 
11
11
  /**
12
12
  * Fabric ViewManager for "HmsScanView". Delegates prop dispatch to the
@@ -17,7 +17,6 @@ import com.facebook.react.viewmanagers.HmsScanViewManagerDelegate
17
17
  class HmsScanViewManager :
18
18
  SimpleViewManager<HmsScanView>(),
19
19
  HmsScanViewManagerInterface<HmsScanView> {
20
-
21
20
  private val mDelegate: ViewManagerDelegate<HmsScanView> =
22
21
  HmsScanViewManagerDelegate(this)
23
22
 
@@ -25,26 +24,37 @@ class HmsScanViewManager :
25
24
 
26
25
  override fun getName(): String = NAME
27
26
 
28
- public override fun createViewInstance(context: ThemedReactContext): HmsScanView =
29
- HmsScanView(context)
27
+ public override fun createViewInstance(context: ThemedReactContext): HmsScanView = HmsScanView(context)
30
28
 
31
29
  @ReactProp(name = "formatsCsv")
32
- override fun setFormatsCsv(view: HmsScanView?, value: String?) {
30
+ override fun setFormatsCsv(
31
+ view: HmsScanView?,
32
+ value: String?,
33
+ ) {
33
34
  view?.setFormatsCsv(value)
34
35
  }
35
36
 
36
37
  @ReactProp(name = "continuous", defaultBoolean = true)
37
- override fun setContinuous(view: HmsScanView?, value: Boolean) {
38
+ override fun setContinuous(
39
+ view: HmsScanView?,
40
+ value: Boolean,
41
+ ) {
38
42
  view?.setContinuous(value)
39
43
  }
40
44
 
41
45
  @ReactProp(name = "paused", defaultBoolean = false)
42
- override fun setPaused(view: HmsScanView?, value: Boolean) {
46
+ override fun setPaused(
47
+ view: HmsScanView?,
48
+ value: Boolean,
49
+ ) {
43
50
  view?.setPaused(value)
44
51
  }
45
52
 
46
53
  @ReactProp(name = "torch", defaultBoolean = false)
47
- override fun setTorch(view: HmsScanView?, value: Boolean) {
54
+ override fun setTorch(
55
+ view: HmsScanView?,
56
+ value: Boolean,
57
+ ) {
48
58
  view?.setTorch(value)
49
59
  }
50
60
 
@@ -52,13 +62,12 @@ class HmsScanViewManager :
52
62
  * Map internal Fabric event names to the JS prop callback names declared in
53
63
  * HmsScanViewNativeComponent.ts.
54
64
  */
55
- override fun getExportedCustomDirectEventTypeConstants(): Map<String, Any> {
56
- return mapOf(
65
+ override fun getExportedCustomDirectEventTypeConstants(): Map<String, Any> =
66
+ mapOf(
57
67
  "topScanResult" to mapOf("registrationName" to "onScanResult"),
58
68
  "topScanError" to mapOf("registrationName" to "onScanError"),
59
- "topTorchStatus" to mapOf("registrationName" to "onTorchStatus")
69
+ "topTorchStatus" to mapOf("registrationName" to "onTorchStatus"),
60
70
  )
61
- }
62
71
 
63
72
  companion object {
64
73
  const val NAME = "HmsScanView"
@@ -16,34 +16,30 @@ import com.facebook.react.uimanager.ViewManager
16
16
  * getReactModuleInfoProvider,视图走 createViewManagers + listOf(ViewManager)。
17
17
  */
18
18
  class ReactNativeHmsScanPackage : BaseReactPackage() {
19
-
20
19
  override fun getModule(
21
20
  name: String,
22
- reactContext: ReactApplicationContext
23
- ): NativeModule? {
24
- return if (name == HmsScanModule.NAME) {
21
+ reactContext: ReactApplicationContext,
22
+ ): NativeModule? =
23
+ if (name == HmsScanModule.NAME) {
25
24
  HmsScanModule(reactContext)
26
25
  } else {
27
26
  null
28
27
  }
29
- }
30
28
 
31
- override fun getReactModuleInfoProvider() = ReactModuleInfoProvider {
32
- mapOf(
33
- HmsScanModule.NAME to ReactModuleInfo(
34
- name = HmsScanModule.NAME,
35
- className = HmsScanModule.NAME,
36
- canOverrideExistingModule = false,
37
- needsEagerInit = false,
38
- isCxxModule = false,
39
- isTurboModule = true
29
+ override fun getReactModuleInfoProvider() =
30
+ ReactModuleInfoProvider {
31
+ mapOf(
32
+ HmsScanModule.NAME to
33
+ ReactModuleInfo(
34
+ name = HmsScanModule.NAME,
35
+ className = HmsScanModule.NAME,
36
+ canOverrideExistingModule = false,
37
+ needsEagerInit = false,
38
+ isCxxModule = false,
39
+ isTurboModule = true,
40
+ ),
40
41
  )
41
- )
42
- }
42
+ }
43
43
 
44
- override fun createViewManagers(
45
- reactContext: ReactApplicationContext
46
- ): List<ViewManager<*, *>> {
47
- return listOf(HmsScanViewManager())
48
- }
44
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> = listOf(HmsScanViewManager())
49
45
  }
@@ -24,34 +24,27 @@ RCT_EXPORT_MODULE(HmsScan)
24
24
 
25
25
  // AVAuthorizationStatus -> our CameraPermissionStatus string.
26
26
  // authorized -> granted; notDetermined -> undetermined; denied/restricted -> blocked.
27
- + (NSString *)stringForAuthorizationStatus:(AVAuthorizationStatus)status
28
- {
27
+ + (NSString *)stringForAuthorizationStatus:(AVAuthorizationStatus)status {
29
28
  switch (status) {
30
- case AVAuthorizationStatusAuthorized:
31
- return @"granted";
32
- case AVAuthorizationStatusNotDetermined:
33
- return @"undetermined";
34
- case AVAuthorizationStatusDenied:
35
- case AVAuthorizationStatusRestricted:
36
- return @"blocked";
37
- default:
38
- return @"undetermined";
29
+ case AVAuthorizationStatusAuthorized:
30
+ return @"granted";
31
+ case AVAuthorizationStatusNotDetermined:
32
+ return @"undetermined";
33
+ case AVAuthorizationStatusDenied:
34
+ case AVAuthorizationStatusRestricted:
35
+ return @"blocked";
36
+ default:
37
+ return @"undetermined";
39
38
  }
40
39
  }
41
40
 
42
- - (void)getCameraPermissionStatus:(RCTPromiseResolveBlock)resolve
43
- reject:(RCTPromiseRejectBlock)reject
44
- {
45
- AVAuthorizationStatus status =
46
- [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
41
+ - (void)getCameraPermissionStatus:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
42
+ AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
47
43
  resolve([HmsScanModule stringForAuthorizationStatus:status]);
48
44
  }
49
45
 
50
- - (void)requestCameraPermission:(RCTPromiseResolveBlock)resolve
51
- reject:(RCTPromiseRejectBlock)reject
52
- {
53
- AVAuthorizationStatus current =
54
- [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
46
+ - (void)requestCameraPermission:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
47
+ AVAuthorizationStatus current = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
55
48
 
56
49
  // Only notDetermined can present the system prompt. For an already-resolved
57
50
  // state, return it directly (requestAccess would still call back immediately,
@@ -63,12 +56,12 @@ RCT_EXPORT_MODULE(HmsScan)
63
56
 
64
57
  [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo
65
58
  completionHandler:^(BOOL granted) {
66
- // Re-read the authoritative status rather than inferring from `granted`,
67
- // so restricted/denied are reported correctly.
68
- AVAuthorizationStatus updated =
69
- [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
70
- resolve([HmsScanModule stringForAuthorizationStatus:updated]);
71
- }];
59
+ // Re-read the authoritative status rather than inferring from `granted`,
60
+ // so restricted/denied are reported correctly.
61
+ AVAuthorizationStatus updated =
62
+ [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
63
+ resolve([HmsScanModule stringForAuthorizationStatus:updated]);
64
+ }];
72
65
  }
73
66
 
74
67
  #pragma mark - Image loading
@@ -76,8 +69,7 @@ RCT_EXPORT_MODULE(HmsScan)
76
69
  // Load a UIImage from a local URI: file:// , an absolute/relative file path,
77
70
  // or a data: URI. Remote URLs and Photos (ph:// / assets-library://) are not
78
71
  // supported here -> returns nil so the caller rejects E_IMAGE_LOAD_FAILED.
79
- + (nullable UIImage *)imageForURI:(NSString *)uri
80
- {
72
+ + (nullable UIImage *)imageForURI:(NSString *)uri {
81
73
  if (uri.length == 0) {
82
74
  return nil;
83
75
  }
@@ -121,13 +113,11 @@ RCT_EXPORT_MODULE(HmsScan)
121
113
  - (void)decodeImage:(NSString *)uri
122
114
  formatsCsv:(NSString *)formatsCsv
123
115
  resolve:(RCTPromiseResolveBlock)resolve
124
- reject:(RCTPromiseRejectBlock)reject
125
- {
116
+ reject:(RCTPromiseRejectBlock)reject {
126
117
  UIImage *image = [HmsScanModule imageForURI:uri];
127
118
  if (image == nil) {
128
119
  reject(kErrImageLoadFailed,
129
- [NSString stringWithFormat:@"无法从 URI 加载图片(仅支持 file:// / 绝对路径 / data:):%@",
130
- uri ?: @"(nil)"],
120
+ [NSString stringWithFormat:@"无法从 URI 加载图片(仅支持 file:// / 绝对路径 / data:):%@", uri ?: @"(nil)"],
131
121
  nil);
132
122
  return;
133
123
  }
@@ -135,8 +125,7 @@ RCT_EXPORT_MODULE(HmsScan)
135
125
  @try {
136
126
  unsigned int formatType = [HmsScanResultMapper scanFormatTypeFromCsv:formatsCsv];
137
127
  // photoMode/Photo=YES: still-image (album) decode path, per HUAWEI guidance.
138
- HmsScanOptions *options =
139
- [[HmsScanOptions alloc] initWithScanFormatType:formatType Photo:YES];
128
+ HmsScanOptions *options = [[HmsScanOptions alloc] initWithScanFormatType:formatType Photo:YES];
140
129
 
141
130
  NSArray *raw = [HmsBitMap multiDecodeBitMapForImage:image withOptions:options];
142
131
  NSString *json = [HmsScanResultMapper jsonStringFromHuaweiArray:raw];
@@ -144,17 +133,14 @@ RCT_EXPORT_MODULE(HmsScan)
144
133
  // JS parseResultsJson handles the empty case.
145
134
  resolve(json);
146
135
  } @catch (NSException *exception) {
147
- reject(kErrDecodeFailed,
148
- exception.reason ?: @"HUAWEI Scan Kit 解码图片时发生异常",
149
- nil);
136
+ reject(kErrDecodeFailed, exception.reason ?: @"HUAWEI Scan Kit 解码图片时发生异常", nil);
150
137
  }
151
138
  }
152
139
 
153
140
  #pragma mark - TurboModule
154
141
 
155
142
  - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
156
- (const facebook::react::ObjCTurboModule::InitParams &)params
157
- {
143
+ (const facebook::react::ObjCTurboModule::InitParams &)params {
158
144
  return std::make_shared<facebook::react::NativeHmsScanSpecJSI>(params);
159
145
  }
160
146
 
@@ -20,10 +20,9 @@
20
20
  // Maps one of our BarcodeFormat tokens to the matching HMSScanFormatTypeCode bit.
21
21
  // Returns 0 for tokens HUAWEI iOS does not support (e.g. MULTI_FUNCTIONAL) or
22
22
  // UNKNOWN, so they contribute nothing to the OR-ed mask.
23
- + (unsigned int)bitForFormatToken:(NSString *)token
24
- {
25
- NSString *t = [[token stringByTrimmingCharactersInSet:
26
- [NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString];
23
+ + (unsigned int)bitForFormatToken:(NSString *)token {
24
+ NSString *t =
25
+ [[token stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString];
27
26
  if (t.length == 0) {
28
27
  return 0;
29
28
  }
@@ -32,20 +31,20 @@
32
31
  static dispatch_once_t onceToken;
33
32
  dispatch_once(&onceToken, ^{
34
33
  map = @{
35
- @"QR_CODE": @(QR_CODE),
36
- @"AZTEC": @(AZTEC),
37
- @"DATA_MATRIX": @(DATA_MATRIX),
38
- @"PDF417": @(PDF_417),
39
- @"CODABAR": @(CODABAR),
40
- @"CODE_39": @(CODE_39),
41
- @"CODE_93": @(CODE_93),
42
- @"CODE_128": @(CODE_128),
43
- @"EAN_8": @(EAN_8),
44
- @"EAN_13": @(EAN_13),
45
- @"UPC_A": @(UPC_A),
46
- @"UPC_E": @(UPC_E),
34
+ @"QR_CODE" : @(QR_CODE),
35
+ @"AZTEC" : @(AZTEC),
36
+ @"DATA_MATRIX" : @(DATA_MATRIX),
37
+ @"PDF417" : @(PDF_417),
38
+ @"CODABAR" : @(CODABAR),
39
+ @"CODE_39" : @(CODE_39),
40
+ @"CODE_93" : @(CODE_93),
41
+ @"CODE_128" : @(CODE_128),
42
+ @"EAN_8" : @(EAN_8),
43
+ @"EAN_13" : @(EAN_13),
44
+ @"UPC_A" : @(UPC_A),
45
+ @"UPC_E" : @(UPC_E),
47
46
  // Our ITF14 maps to HUAWEI's ITF bit.
48
- @"ITF14": @(ITF),
47
+ @"ITF14" : @(ITF),
49
48
  // MULTI_FUNCTIONAL / UNKNOWN have no HUAWEI iOS equivalent -> 0.
50
49
  };
51
50
  });
@@ -54,12 +53,10 @@
54
53
  return bit ? (unsigned int)bit.unsignedIntValue : 0u;
55
54
  }
56
55
 
57
- + (unsigned int)scanFormatTypeFromCsv:(NSString *)csv
58
- {
59
- NSString *trimmed = [csv stringByTrimmingCharactersInSet:
60
- [NSCharacterSet whitespaceAndNewlineCharacterSet]];
56
+ + (unsigned int)scanFormatTypeFromCsv:(NSString *)csv {
57
+ NSString *trimmed = [csv stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
61
58
  if (trimmed.length == 0) {
62
- return (unsigned int)ALL; // empty string == all formats
59
+ return (unsigned int)ALL; // empty string == all formats
63
60
  }
64
61
 
65
62
  unsigned int mask = 0u;
@@ -77,16 +74,14 @@
77
74
  // We tolerate it being delivered as an NSNumber (bit value) OR an NSString
78
75
  // (either a numeric string or already a token like "QR_CODE"), since the
79
76
  // public headers do not pin the type and demos have shown both shapes.
80
- + (NSString *)formatStringFromValue:(id)formatValue
81
- {
77
+ + (NSString *)formatStringFromValue:(id)formatValue {
82
78
  // Case 1: numeric (NSNumber, or numeric NSString) -> match the enum bit.
83
79
  NSInteger code = NSNotFound;
84
80
  if ([formatValue isKindOfClass:[NSNumber class]]) {
85
81
  code = [(NSNumber *)formatValue integerValue];
86
82
  } else if ([formatValue isKindOfClass:[NSString class]]) {
87
83
  NSString *s = (NSString *)formatValue;
88
- NSString *trimmed = [s stringByTrimmingCharactersInSet:
89
- [NSCharacterSet whitespaceAndNewlineCharacterSet]];
84
+ NSString *trimmed = [s stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
90
85
  // Pure-integer string?
91
86
  NSScanner *scanner = [NSScanner scannerWithString:trimmed];
92
87
  NSInteger parsed = 0;
@@ -95,15 +90,28 @@
95
90
  } else {
96
91
  // Case 2: already a token string -> normalize known spellings.
97
92
  NSString *upper = [trimmed uppercaseString];
98
- if ([upper isEqualToString:@"PDF_417"]) return @"PDF417";
99
- if ([upper isEqualToString:@"ITF"]) return @"ITF14";
93
+ if ([upper isEqualToString:@"PDF_417"])
94
+ return @"PDF417";
95
+ if ([upper isEqualToString:@"ITF"])
96
+ return @"ITF14";
100
97
  static NSSet<NSString *> *known = nil;
101
98
  static dispatch_once_t onceToken;
102
99
  dispatch_once(&onceToken, ^{
103
100
  known = [NSSet setWithArray:@[
104
- @"QR_CODE", @"AZTEC", @"DATA_MATRIX", @"PDF417", @"CODABAR",
105
- @"CODE_39", @"CODE_93", @"CODE_128", @"EAN_8", @"EAN_13",
106
- @"UPC_A", @"UPC_E", @"ITF14", @"MULTI_FUNCTIONAL",
101
+ @"QR_CODE",
102
+ @"AZTEC",
103
+ @"DATA_MATRIX",
104
+ @"PDF417",
105
+ @"CODABAR",
106
+ @"CODE_39",
107
+ @"CODE_93",
108
+ @"CODE_128",
109
+ @"EAN_8",
110
+ @"EAN_13",
111
+ @"UPC_A",
112
+ @"UPC_E",
113
+ @"ITF14",
114
+ @"MULTI_FUNCTIONAL",
107
115
  ]];
108
116
  });
109
117
  return [known containsObject:upper] ? upper : @"UNKNOWN";
@@ -114,20 +122,34 @@
114
122
 
115
123
  // Map enum bit -> our string. Compare against the global enum constants.
116
124
  switch (code) {
117
- case QR_CODE: return @"QR_CODE";
118
- case AZTEC: return @"AZTEC";
119
- case DATA_MATRIX: return @"DATA_MATRIX";
120
- case PDF_417: return @"PDF417";
121
- case CODABAR: return @"CODABAR";
122
- case CODE_39: return @"CODE_39";
123
- case CODE_93: return @"CODE_93";
124
- case CODE_128: return @"CODE_128";
125
- case EAN_8: return @"EAN_8";
126
- case EAN_13: return @"EAN_13";
127
- case UPC_A: return @"UPC_A";
128
- case UPC_E: return @"UPC_E";
129
- case ITF: return @"ITF14";
130
- default: return @"UNKNOWN";
125
+ case QR_CODE:
126
+ return @"QR_CODE";
127
+ case AZTEC:
128
+ return @"AZTEC";
129
+ case DATA_MATRIX:
130
+ return @"DATA_MATRIX";
131
+ case PDF_417:
132
+ return @"PDF417";
133
+ case CODABAR:
134
+ return @"CODABAR";
135
+ case CODE_39:
136
+ return @"CODE_39";
137
+ case CODE_93:
138
+ return @"CODE_93";
139
+ case CODE_128:
140
+ return @"CODE_128";
141
+ case EAN_8:
142
+ return @"EAN_8";
143
+ case EAN_13:
144
+ return @"EAN_13";
145
+ case UPC_A:
146
+ return @"UPC_A";
147
+ case UPC_E:
148
+ return @"UPC_E";
149
+ case ITF:
150
+ return @"ITF14";
151
+ default:
152
+ return @"UNKNOWN";
131
153
  }
132
154
  }
133
155
 
@@ -136,12 +158,11 @@
136
158
  // HUAWEI iOS does not publish a sceneType enum in the headers; precision is
137
159
  // limited. We map a few well-known scene tokens/codes and otherwise return nil
138
160
  // so `contentType` is omitted (the JS contract treats unknown as undefined).
139
- + (nullable NSString *)contentTypeFromSceneType:(id)sceneType
140
- {
161
+ + (nullable NSString *)contentTypeFromSceneType:(id)sceneType {
141
162
  NSString *token = nil;
142
163
  if ([sceneType isKindOfClass:[NSString class]]) {
143
- token = [[(NSString *)sceneType stringByTrimmingCharactersInSet:
144
- [NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString];
164
+ token = [[(NSString *)sceneType stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]
165
+ uppercaseString];
145
166
  } else if ([sceneType isKindOfClass:[NSNumber class]]) {
146
167
  // No documented numeric scene mapping -> leave unknown.
147
168
  return nil;
@@ -156,32 +177,31 @@
156
177
  static dispatch_once_t onceToken;
157
178
  dispatch_once(&onceToken, ^{
158
179
  map = @{
159
- @"TEXT": @"TEXT",
160
- @"URL": @"URL",
161
- @"URI": @"URL",
162
- @"EMAIL": @"EMAIL",
163
- @"PHONE": @"PHONE",
164
- @"TEL": @"PHONE",
165
- @"SMS": @"SMS",
166
- @"WIFI": @"WIFI",
167
- @"CONTACT": @"CONTACT",
168
- @"CONTACT_INFO": @"CONTACT",
169
- @"EVENT": @"EVENT",
170
- @"LOCATION": @"LOCATION",
171
- @"GEO": @"LOCATION",
172
- @"DRIVER": @"DRIVER",
173
- @"ISBN": @"ISBN",
174
- @"ARTICLE": @"ARTICLE",
175
- @"PRODUCT": @"ARTICLE",
180
+ @"TEXT" : @"TEXT",
181
+ @"URL" : @"URL",
182
+ @"URI" : @"URL",
183
+ @"EMAIL" : @"EMAIL",
184
+ @"PHONE" : @"PHONE",
185
+ @"TEL" : @"PHONE",
186
+ @"SMS" : @"SMS",
187
+ @"WIFI" : @"WIFI",
188
+ @"CONTACT" : @"CONTACT",
189
+ @"CONTACT_INFO" : @"CONTACT",
190
+ @"EVENT" : @"EVENT",
191
+ @"LOCATION" : @"LOCATION",
192
+ @"GEO" : @"LOCATION",
193
+ @"DRIVER" : @"DRIVER",
194
+ @"ISBN" : @"ISBN",
195
+ @"ARTICLE" : @"ARTICLE",
196
+ @"PRODUCT" : @"ARTICLE",
176
197
  };
177
198
  });
178
- return map[token]; // nil when unrecognized -> contentType omitted
199
+ return map[token]; // nil when unrecognized -> contentType omitted
179
200
  }
180
201
 
181
202
  #pragma mark - ResultPoint -> cornerPoints
182
203
 
183
- + (nullable NSNumber *)numberFromPointDict:(NSDictionary *)dict keys:(NSArray<NSString *> *)keys
184
- {
204
+ + (nullable NSNumber *)numberFromPointDict:(NSDictionary *)dict keys:(NSArray<NSString *> *)keys {
185
205
  for (NSString *key in keys) {
186
206
  id v = dict[key];
187
207
  if ([v isKindOfClass:[NSNumber class]]) {
@@ -196,8 +216,7 @@
196
216
 
197
217
  // HUAWEI delivers `ResultPoint` as an array of dicts with `posX`/`posY` numbers.
198
218
  // We tolerate a couple of key spellings just in case.
199
- + (nullable NSArray<NSDictionary *> *)cornerPointsFromResultPoint:(id)resultPoint
200
- {
219
+ + (nullable NSArray<NSDictionary *> *)cornerPointsFromResultPoint:(id)resultPoint {
201
220
  if (![resultPoint isKindOfClass:[NSArray class]]) {
202
221
  return nil;
203
222
  }
@@ -210,7 +229,7 @@
210
229
  NSNumber *x = [self numberFromPointDict:p keys:@[ @"posX", @"x", @"X" ]];
211
230
  NSNumber *y = [self numberFromPointDict:p keys:@[ @"posY", @"y", @"Y" ]];
212
231
  if (x != nil && y != nil) {
213
- [points addObject:@{ @"x": x, @"y": y }];
232
+ [points addObject:@{@"x" : x, @"y" : y}];
214
233
  }
215
234
  }
216
235
  return points.count > 0 ? [points copy] : nil;
@@ -218,8 +237,7 @@
218
237
 
219
238
  #pragma mark - Dict -> ScanResult
220
239
 
221
- + (nullable NSString *)valueFromHuaweiDict:(NSDictionary *)dict
222
- {
240
+ + (nullable NSString *)valueFromHuaweiDict:(NSDictionary *)dict {
223
241
  // Primary key is `text`; tolerate a couple of alternates defensively.
224
242
  for (NSString *key in @[ @"text", @"originalValue", @"showText", @"value" ]) {
225
243
  id v = dict[key];
@@ -230,15 +248,14 @@
230
248
  return nil;
231
249
  }
232
250
 
233
- + (nullable NSDictionary *)scanResultFromHuaweiDict:(NSDictionary *)dict
234
- {
251
+ + (nullable NSDictionary *)scanResultFromHuaweiDict:(NSDictionary *)dict {
235
252
  if (![dict isKindOfClass:[NSDictionary class]]) {
236
253
  return nil;
237
254
  }
238
255
 
239
256
  NSString *value = [self valueFromHuaweiDict:dict];
240
257
  if (value == nil) {
241
- return nil; // no usable decoded text -> drop
258
+ return nil; // no usable decoded text -> drop
242
259
  }
243
260
 
244
261
  NSMutableDictionary *out = [NSMutableDictionary dictionary];
@@ -258,8 +275,7 @@
258
275
  return [out copy];
259
276
  }
260
277
 
261
- + (NSArray<NSDictionary *> *)scanResultsFromHuaweiArray:(NSArray *)array
262
- {
278
+ + (NSArray<NSDictionary *> *)scanResultsFromHuaweiArray:(NSArray *)array {
263
279
  NSMutableArray<NSDictionary *> *results = [NSMutableArray array];
264
280
  if ([array isKindOfClass:[NSArray class]]) {
265
281
  for (id element in array) {
@@ -274,8 +290,7 @@
274
290
 
275
291
  #pragma mark - JSON
276
292
 
277
- + (NSString *)jsonStringFromScanResults:(NSArray<NSDictionary *> *)results
278
- {
293
+ + (NSString *)jsonStringFromScanResults:(NSArray<NSDictionary *> *)results {
279
294
  NSArray *safe = [results isKindOfClass:[NSArray class]] ? results : @[];
280
295
  if (![NSJSONSerialization isValidJSONObject:safe]) {
281
296
  return @"[]";
@@ -289,8 +304,7 @@
289
304
  return json ?: @"[]";
290
305
  }
291
306
 
292
- + (NSString *)jsonStringFromHuaweiArray:(NSArray *)array
293
- {
307
+ + (NSString *)jsonStringFromHuaweiArray:(NSArray *)array {
294
308
  return [self jsonStringFromScanResults:[self scanResultsFromHuaweiArray:array]];
295
309
  }
296
310