Skip to content

RFID Chip Processing via External Devices

Overview

  1. Add Permissions
  2. Set Processing Scenario
  3. Get Universal NFC Tag Object
  4. Read RFID Chip

Examples

Overview

The Document Reader SDK helps process RFID chip not only via internal NFC module of the mobile device itself, but also provides the universal interface to connect the external RFID reader over Bluetooth. This can be useful for the cases, when a mobile device lacks the integrated NFC module, or you need to utilize a concrete external reader.

1. Add Permissions

Add the following permission to your Info.plist:

Info.plist
<key>NSBluetoothAlwaysUsageDescription</key>
<string>Requires access to your phone’s Bluetooth module.</string>

Bluetooth permissions are imported from the BTDevice library and automatically merged to the application's AndroidManifest.xml, no additional actions from your side are required.

Note that you will also need to request the Bluetooth permissions at runtime.

For Android, add the following to android/app/src/main/AndroidManifest.xml:

AndroidManifest.xml
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

For iOS, add the following to ios/Runner/Info.plist:

Info.plist
<key>NSBluetoothAlwaysUsageDescription</key>
<string>Requires access to your phone’s Bluetooth module.</string>

Adding permissions heavily depends on the hyrbid architecture of your app, that's why we can only provide a list of permissions. Make sure to check out how permissions are set for your exact architecture.

Android:

AndroidManifest.xml
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

iOS:

Info.plist
<key>NSBluetoothAlwaysUsageDescription</key>
<string>Requires access to your phone’s Bluetooth module.</string>

For Android, add the following to Platforms/Android/AndroidManifest.xml:

AndroidManifest.xml
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

For iOS, add the following to Platforms/iOS/Info.plist:

Info.plist
<key>NSBluetoothAlwaysUsageDescription</key>
<string>Requires access to your phone’s Bluetooth module.</string>

2. Set Processing Scenario

If you have set up the optical processing with the selected scenario, and the license used for Mobile SDK covers the RFID chip reading, then no need to define the scenario again for the RFID chip processing—it will be set automatically. The access key for RFID chip reading is obtained during the optical processing.

If you don't need the document optical processing, but only RFID chip reading, then set the access key manually and the dedicated RFID scenario as follows:

DocReader.shared.processParams.scenario = RGL_SCENARIO_RFID;
RGLDocReader.shared.processParams.scenario = RGL_SCENARIO_RFID;
DocumentReader.Instance().processParams().scenario = Scenario.SCENARIO_RFID
DocumentReader.Instance().processParams().scenario = Scenario.SCENARIO_RFID;
DocumentReader.instance.processParams.scenario = Scenario.RFID;
DocumentReader.instance.processParams.scenario = Scenario.RFID
// Android
DocumentReader.Instance().ProcessParams().Scenario = Scenario.ScenarioRFID;

// iOS
RGLDocReader.Shared.ProcessParams.Scenario = Constants.RGL_SCENARIO_RFID;

3. Get Universal NFC Tag Object

Using the dedicated third-party SDK, connect to your external RFID reader and get the NFC tag in accordance with its API. Then, conform the proprietary object to the universal Regula NFC tag interface. See the following example.

extension MyUniversalNFCTag: RGLUniversalNFCTagTransport {
    func sendApduCommand(data: Data, completionHandler: @escaping (Data, UInt8, UInt8, (any Error)?) -> Void) {
        deviceManager.sendCommand(data) { result in
            switch result {
            case .success(let response):
                let payload = response.payload
                completionHandler(payload, response.statusWord1, response.statusWord2, nil)
            case .failure(let error):
                completionHandler(Data(),0, 0, error)
            }
        }
    }
}
@interface MyUniversalNFCTag: NSObject <RGLUniversalNFCTagTransport>

@end

@implementation MyUniversalNFCTag

- (void)sendApduCommand:(NSData * _Nonnull)data completionHandler:(nonnull void (^)(NSData * _Nonnull, uint8_t, uint8_t, NSError * _Nullable))completionHandler {

    [deviceManager sendCommand:data completion:^(SDKResult *result, SDKError *error) {
        switch (result) {
            case SUCCESS:
                completionHandler(result.payload, result.response.statusWord1, result.response.statusWord2, nil);
                break;

            default:
                completionHandler(Data(),0, 0, error);
                break;
        }
    }];
}

@end
class NfcDeviceTag : IUniversalNfcTag {

    override fun sendApduCommand(apduCommand: ByteArray): ByteArray? =
        deviceManager.sendCommand(apduCommand)?.also { return it }
            ?: Log.e(TAG, "Exception: empty response").let { null }

}
public class NfcDeviceTag implements IUniversalNfcTag {

    @Override
    public byte[] sendApduCommand(byte[] apduCommand) {
        byte[] response = deviceManager.sendCommand(apduCommand);
        if (response == null) {
            Log.e(TAG, "Exception: empty response");
            return null;
        }
        return response;
    }
}
// Android
public class NfcDeviceTag : IUniversalNfcTag {
    public byte[] SendApduCommand(byte[] apduCommand) {
        byte[] response = deviceManager.sendCommand(apduCommand);
        if (response == null) {
            Console.WriteLine("Exception: empty response");
            return null;
        }
        return response;
    }
}

// iOS
public class MyUniversalNFCTag : RGLUniversalNFCTagTransport
{
    public void SendApduCommand(NSData data, Action<NSData, byte, byte, NSError> completionHandler)
    {
        deviceManager.SendCommand(data, (SDKResult result, SDKError error) => {
            switch (result)
            {
                case SUCCESS:
                    completionHandler(result.payload, result.response.statusWord1, result.response.statusWord2, nil);
                    break;

                default:
                    completionHandler(Data(), 0, 0, error);
                    break;
            }
        });
    }
}

4. Read RFID Chip

To start RFID chip reading via the universal interface, use the method below. Note that unlike the standard RFID reader flow, in this case the predefined Regula UI is not applied, so the UX customization is completely up to you.

DocReader.shared.readRFID(universalNFCTag: universalTag) { notificationAction, notification in 
    // Notification with status reading RFID
} completion: { action, results, error, errorCode in
    switch action {
      case .complete:
        print("Complete")
      case .cancel:
        print("Canceled")
      case .error:
        print("Error: \(error)")
      default:
        break
    }
}
[RGLDocReader.shared readRFIDWithUniversalTag:universalTag notificationCallback:^(RGLRFIDNotificationAction notificationAction, RGLRFIDNotify * _Nullable notification) {
    // Notification with status reading RFID
} completion:^(RGLRFIDCompleteAction action, RGLDocumentReaderResults * _Nullable results, NSError * _Nullable error, RGLRFIDErrorCodes errorCode) {
    switch (action) {
        case RGLRFIDCompleteActionComplete:
            NSLog(@"Complete");
            break;
        case RGLRFIDCompleteActionCancel:
            NSLog(@"Canceled");
            break;
        case RGLRFIDCompleteActionError:
            NSLog(@"Error: %@", error);
            break;
        default:
            break;
    }
}];
DocumentReader.Instance().readRFID(universalNfcTag, object : IRfidReaderCompletion() {
    override fun onProgress(notification: DocumentReaderNotification) {
        super.onProgress(notification)
    }

    override fun onCompleted(
        rfidAction: Int,
        documentReaderResults: DocumentReaderResults?,
        error: DocumentReaderException?
    ) {}
})
DocumentReader.Instance().readRFID(universalNfcTag, new IRfidReaderCompletion() {

    @Override
    public void onProgress(@NonNull DocumentReaderNotification notification) {
        super.onProgress(notification);
    }

    @Override
    public void onCompleted(int rfidAction, @Nullable DocumentReaderResults documentReaderResults, 
                            @Nullable DocumentReaderException e) {

    }
});
var config = RFIDConfig.withoutUI((action, results, error) {
  // display results
});
config.onProgress = (notification) {
  // display progress
};
DocumentReader.instance.rfid(config);
var config = RFIDConfig.withoutUI((action, results, error) => {
  // display results
});
config.onProgress = (notification) => {
  // display progress
};
DocumentReader.instance.rfid(config);
// Android
DocumentReader.Instance().ReadRFID(universalNfcTag, this);

// iOS
RGLDocReader.Shared.ReadRFIDWithUniversalTag(universalTag, (action, notify) => {  }, (action, results, error, errorCodes) => { });

Examples

Explore the examples of the RFID processing via external Bluetooth devices by the links:

Next Steps