Camera scanning with SocketCam¶
Support¶
The Flutter Capture SDK now has support for SocketCam C820 and C860.
Requirements¶
In order to use SocketCam in your Flutter app, you will need to install or upgrade the Flutter Capture SDK version 1.5.
iOS Requirements
You will need to update pods with pod install --repo-update
.
In your Info.plist, you need to add the key to allow access to the camera. Add the below code to the bottom of your dict tag.
<key>NSCameraUsageDescription</key>
<string>Need to enable camera access for SocketCam products</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<key>UISupportedExternalAccessoryProtocols</key>
<array>
<string>com.socketmobile.chs</string>
</array>
<key>NSCameraUsageDescription</key>
<string>Need to enable camera access for SocketCam products</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>sktcompanion</string>
</array>
Android Requirements
In AndroidManifest.xml you will need to add the below code.
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
<meta-data android:name="com.socketmobile.capture.APP_KEY" android:value="{YOUR_APP_KEY}"/>
<meta-data android:name="com.socketmobile.capture.DEVELOPER_ID" android:value="{YOUR_DEVELOPER_ID}"/>
You might also have to add the file network_security_config.xml file to android/app/src/main/res/xml in order to avoid a clearText permissions error. See the code below for the file.
<?xml version=”1.0” encoding=”utf-8”?> <network-security-config>
<base-config cleartextTrafficPermitted=”false” /> <domain-config cleartextTrafficPermitted=”true”>
<domain includeSubdomains=”false”>localhost</domain> <domain includeSubdomains=”false”>127.0.0.1</domain>
</domain-config>
</network-security-config>
Then, in your AndroidManifest.xml, in your first application tag, add this property:
android:networkSecurityConfig=”@xml/network_security_config”
For more information, check out the Android docs.
Using SocketCam¶
Once you have all of the changes above, you can start using SocketCam in your Flutter App.
In order to do this, in your app you will need to first enable SocketCam, using a setProperty
to set the socketCamStatus
property.Once it is enabled, to open the view finder and start scanning you can set the trigger by setting the trigger property.
Below is an example of enabling SocketCam.
Future<void> _setSocketCamStatus(int? arg) async {
CaptureProperty property = CaptureProperty(
id: CapturePropertyIds.socketCamStatus,
type: CapturePropertyTypes.byte,
value: arg,
);
try {
CaptureProperty? data =
await widget.socketCamCapture?.setProperty(property);
setStatus(
'successfully changed socket cam status: ${_supportOpts[arg]?['message']}',
);
} on CaptureException catch (exception) {
String code = exception.code.toString();
String message = exception.message;
setStatus('failed to set socket cam status: $code :', message);
}
}
Finally, here is how to set the trigger property.
final List<Map<String, dynamic>> triggerOptions = [
{'label': 'Start', 'value': Trigger.start},
{'label': 'Stop', 'value': Trigger.stop},
{'label': 'Continuous Scan', 'value': Trigger.continuousScan},
];
...
Future<void> _setSocketCamTrigger() async {
CaptureProperty property = CaptureProperty(
id: CapturePropertyIds.triggerDevice, // Replace with the correct id value for TriggerDevice
type: CapturePropertyTypes.byte, // Replace with the correct type value for Byte
value: _triggerType,
);
try {
var data = await widget.socketCamDevice?.setProperty(property);
var triggerOpt = triggerOptions.firstWhere((x) => x["value"] == _triggerType);
setStatus("successfully changed TriggerDevice: '${triggerOpt["label"]}'");
} on CaptureException catch (exception) {
String code = exception.code.toString();
String message = exception.message; // Replace with your errorCheck method
setStatus("failed to set TriggerDevice: $code : $message");
}
}
In order to check if you already have SocketCam enabled, you can use a getProperty
request like so.
Future<void> getSocketCamStatus() async {
CaptureProperty property = const CaptureProperty(
id: CapturePropertyIds.socketCamStatus,
type: CapturePropertyTypes.none,
value: {},
);
try {
var data = await widget.socketCamCapture!.getProperty(property);
Map<String, dynamic> x = _supportOpts[data.value]!;
setState(() {
_socketCamEnabled = data.value;
});
setStatus('successfully retrieved SocketCamStatus: ${x['message']}');
} on CaptureException catch (exception) {
String code = exception.code.toString();
String message = exception.message;
setStatus('failed to get SocketCamStatus: $code : $message');
}
}
By checking if SocketCam is enabled you won’t need to go through the trouble of re-enabling it.
Differentiating SocketCam from other devices¶
It is recommended in the UI to save the capture instance that is tied to SocketCam separately from other device capture instances as to avoid get/set property and usage conflicts. You can differentiate a SocketCam device from another device, such as a D740, by checking the device type in the device arrival event. See the below code from an onCaptureEvent callback.
_onCaptureEvent(e, handle) {
if (e == null) {
return;
} else if (e.runtimeType == CaptureException) {
_updateVals("${e.code}", e.message, e.method, e.details);
return;
}
logger.log('onCaptureEvent from: ', '$handle');
switch (e.id) {
case CaptureEventIds.deviceArrival:
Capture deviceCapture = Capture(logger);
_openDeviceHelper(deviceCapture, e, false, handle);
break;
...
}
...
Future _openDeviceHelper(Capture deviceCapture, CaptureEvent e, bool isManager, int handle) async {
// deviceArrival checks that a device is available
// openDevice allows the device to be used (for decodedData)
List<DeviceInfo> arr = _devices;
DeviceInfo _deviceInfo = e.deviceInfo;
logger.log('Device ${isManager ? 'Manager' : ''} Arrival =>',
'${_deviceInfo.name} (${_deviceInfo.guid})');
try {
int res = await deviceCapture.openDevice(_deviceInfo.guid, _capture);
// res is 0 if no error, if not zero there is error in catch
if (res == 0 && !arr.contains(_deviceInfo)) {
if (SocketCamTypes.contains(_deviceInfo.type)) {
setState(() {
_socketcamDevice = deviceCapture;
_socketCamHandle = handle;
});
} else {
setState(() {
_deviceCapture = deviceCapture;
});
}
arr.add(_deviceInfo);
setState(() {
_devices = arr;
});
}
_updateVals('Device${isManager ? ' Manager' : ''} Opened',
'Successfully added "${_deviceInfo.name}"');
} on CaptureException catch (exception) {
_updateVals(exception.code.toString(), exception.message,
exception.method, exception.details);
}
}