Выполнение операций над токенами

Синхронные операции над токенами не следует вызывать в главном потоке, т.к. они могут выполняться продолжительное время. К тому же логика работы с токеном через ридеры (iR301-UL, iR301-U, bR301, bR301 BLE, JaCarta USB) и NFC смарт-карту отличается.

При работе через ридеры токен всегда подключен к мобильному устройству и к нему можно получить доступ из любого ViewController вашего приложения. Но при работе через NFC смарт-карту открывается сессия, ограниченная минимум 20 секундами, которая отображает системный ViewController для индикации пользователю о необходимости поднести NFC смарт-карту к мобильному устройству и только в эту сессию можно выполнять операции на токене. После закрытия сессии связь с токеном прерывается.

Таким образом при работе с NFC, если на первом ViewController получить список токенов со смарт-карты, а на втором ViewController выпонить какие-либо операции над токеном, то в нем придется повторять все действия по поиску токена.

Для решения данной проблемы необходимо использовать методы execBlock или execBlockWithParameters, которые:

  • при подключении через ридеры (iR301-UL, iR301-U, bR301, bR301 BLE, JaCarta USB) выполнят синхронные операции в отдельном потоке;
  • при подключении через NFC смарт-карту откроют NFC сессию, повторно найдут токен, предъявят PIN-кода (если он был успешно предъявлен ранее) и выполнят синхронные операции.

Таким образом, эти методы обеспечивают единообразную работу с токеном вне зависимости от способа подключения.

Важно

Не следует вызывать методы execBlock или execBlockWithParameters внутри handler метода getTokensWithAlertMessage, т.к. NFC сессия уже открыта и открытие повторной приведет к ошибке.

Общий пример использования

Требуется прочитать список сертификатов у токена, который был получен с помощью методов startWithQueue, getTokensWithQueue или getTokensWithAlertMessage.

Подобный вариант использования представлен в следующих примерах SDK: JaCartaSample_ObjC и JaCartaSample_Swift.

// Получение token при помощи методов
// [startWithQueue:notificationCenter:tokenAttached:tokenDetached:watcherStopped:],
// [getTokensWithQueue:attempts:attemptsDelay:predicate:handler:],
// или [getTokensWithAlertMessage:predicate:handler:].
// id<JCToken> token = ...;

// ...

NSDictionary* parameters = [[NSDictionary alloc] initWithObjectsAndKeys:
    @"You can scan NFC-tags by holding them behind the top of your device", JCTokenParamNFCAlertMessage,
    nil
];

// 1. Асинхронное выполнение кода.
// Для смарт-карты с ридером это будет обычный асинхронный вызов.
// Для NFC смарт-карты это будет асинхронный вызов c открывшейся новой NFC сессией.
[token execBlockWithParameters:parameters block:^(NSError * _Nullable error) {
    if (error) {
        // 2. Обработка ошибки.
        // Может вернуться в случае неудачного открытия NFC сессии.
        return;
    }

    // 3. Чтение сертификатов с токена.
    JCCertificateListResult *result = [token readCertificates];
    dispatch_async(dispatch_get_main_queue(), ^{
        // 4. Обработка результата чтения сертификатов в главном потоке
    });
}];

Пример выполнения синхронных операций токена на смарт-карте, подключенной к ридеру, сразу после его получения

Требуется прочитать список сертификатов у токена, который был получен с помощью метода getTokensWithQueue.

Используется метод execBlock и синхронные операции вызываются внутри него.

Подобный вариант использования представлен в следующих примерах SDK: JCSignSample_ObjC и JCSignSample_Swift.

// 1. Проверка наличия readerWatcher.
// Объект существует, если инициализация менеджера прошла успешно
// и был передан хотя бы один из следующих флагов: JCReadersIR301AndBR301, JCReadersBR301BLEAndBR500
id<JCReaderWatcher> readerWatcher = JCManager.defaultManager.readerWatcher;
if (!readerWatcher) {
    // 2. Обработка отсутствия объекта readerWatcher
    return;
}

// 3. Запуск процесса поиска токенов
BOOL started = [readerWatcher
                getTokensWithQueue:dispatch_get_main_queue()
                attempts:5
                attemptsDelay:1.0
                predicate:^BOOL(id<JCToken> _Nonnull token, BOOL * _Nonnull stop) {
    // 5. Для примера берем первый попавшийся токен.
    *stop = YES;
    return YES;
}

                handler:^(NSArray<id<JCToken>> * _Nullable tokens, NSError * _Nullable error) {
    if (error) {
        // 6. Обработка ошибки поиска токенов
        return;
    }
    id<JCToken> token = tokens[0];
    // 7. Асинхронное выполнение кода.
    [token execBlock:^(NSError * _Nullable error) {
        // 8. Чтение сертификатов с токена.
        JCCertificateListResult *result = [token readCertificates];
        dispatch_async(dispatch_get_main_queue(), ^{
            // 9. Обработка результата чтения сертификатов в главном потоке
        });
    }];
}];

if (!started) {
    // 4. Обработка ситуации, когда процесс поиска токенов не запустился.
    return;
}

Пример выполнения синхронных операций токена на NFC смарт-карте сразу после его получения

Требуется прочитать список сертификатов у токена, который был получен с помощью метода getTokensWithAlertMessage.

Методы execBlock или execBlockWithParameters не используются, а синхронные операции вызываются внутри handler метода getTokensWithAlertMessage.

Подобный вариант использования представлен в следующих примерах SDK: JCSignSample_ObjC и JCSignSample_Swift.

// 1. Проверка наличия nfcWatcher.
// Объект существует, если инициализация менеджера прошла успешно
// и был передан флаг JCReadersNFC
id<JCNFCWatcher> nfcWatcher = JCManager.defaultManager.nfcWatcher;
if (!nfcWatcher) {
    // 2. Обработка отсутствия объекта nfcWatcher
    return;
}

[nfcWatcher
 getTokensWithAlertMessage:@"You can scan NFC-tags by holding them behind the top of your device"
 predicate:^BOOL(id<JCToken> _Nonnull token, BOOL * _Nonnull stop) {
    // 3. Для примера берем первый попавшийся токен.
    *stop = YES;
    return YES;
}
 handler:^(NSArray<id<JCToken>> * _Nullable tokens, NSError * _Nullable error) {
    if(error) {
        // 4. Обработка ошибки поиска токенов.
        // NFC сессия будет закрыта.
        return;
    }

    // 5. Чтение сертификатов с токена.
    JCCertificateListResult *result = [tokens[0] readCertificates];
    dispatch_async(dispatch_get_main_queue(), ^{
        // 6. Обработка результата чтения сертификатов в главном потоке
    });

    // NFC сессия будет закрыта и связь с токеном исчезнет.
}];