ЖТЯИ.00118-01 97 02-01 КриптоКлюч SDK. Руководство Разработчика. iOS

    КриптоКлюч SDK для встраивания в мобильное приложение представляет собой набор программных компонентов для использования в мобильных приложениях, который позволяет производить удаленное выполнение операций подписи и управление сертификатами, а также подтверждать операции Пользователя в КриптоПро Ключ, инициированные другими способами.

    Термины и определения

    Тип Описание
    User Объект, содержащий всю необходимую информацию для выполнения действий от имени пользователя. Содержит, в том числе, информацию для доступа к экземпляру СЭП (url, корневой сертификат и пр.), "вектор аутентификации" для подтверждения действий и пр. С точки зрения СЭП данный объект является устройством, подключенным к учетной записи пользователя СЭП
    Device Объект, содержащий информацию об устройствах, подключенных к той же учетной записи, что и объект User. Данный объект не содержит "вектор аутентификации" и не может использоваться для подтверждения операций или выполнения других действий
    Operation Операция СЭП, для которой требуется подтверждение/отклонение. Операция может содержать несколько документов. При подтверждении/отклонении операции все содержащиеся в ней документы будут подписаны/отклонены. Операция создается на сервере СЭП
    Operation.Document Документ, входящий в операцию, либо обрабатываемый самостоятельно
    Document Description "Сниппет" документа, сформированный сервером СЭП на основе шаблона для сниппета и содержания документа
    Document Preview Визуализированный в человеко-читаемую форму документ, сформированный сервером СЭП на основе шаблона для визуализации и содержания документа
    Document RawPDF "Сырое" содержание документа (например, текстового файла), преобразованное в формат PDF
    Certificate Сертификат, привязанный к ключу подписи в учетной записи на СЭП

    Установка

    Xcode 15.4+ Swift 5.10

    Для использования CKeySDK необходимо добавить в проект:

    • Фреймворк
    • Ресурсы
    • Корневые сертификаты

    Добавление фреймворка

    Swift Package Manager

    Добавьте пакет CKeySDK из репозитория:

    https://.../ckey.git
    

    CocoaPods

    Добавьте в файл Podfile зависимости:

    pod 'CKeySDK',           :git => '...'
    

    Ручная установка

    Добавьте в проект CKeySDK.xcframework.

    Carthage

    Т.к. Carthage не поддерживает распространение бинарных фреймворков, данный метод не используется.

    Ресурсы

    Ресурсы лежат в репозитории в папке Resources. Их необходимо прикрепить к приложению. Папку locale нужно добавить с флагом Create folder references.

    При интеграции с помощью SPM/CocoaPods фреймворк можно найти в Project Navigator.

    • SPM: Package Dependencies -> CKeySDK -> Referenced Binaries -> CKeySDK.xcframework
    • CocoaPods: Pods -> Pods -> CKeySDK -> Frameworks -> CKeySDK.xcframework

    Корневые сертификаты

    Для взаимодействия с серверами в ресурсы приложения в папку root-certs нужно поместить сертификаты:

    AppName.app/root-certs/
        cert_1.crt
        cert_2.cer
        ...
        cert_N.certificate
    

    Дополнительные действия

    После сборки таргета необходимо запустить скрипт ConfigureApplication, который лежит в репозитории в папке <tbw>. В настройках таргета необходимо выбрать Build Phases -> New Run Script Phase. Примеры для различных способов установки:

    # SPM
    sh ${BUILD_DIR%Build/*}/SourcePackages/checkouts/ckeysdk/Tools/ConfigureApplication
    
    # CocoaPods
    tbw
    

    Также можно переместить ConfigureApplication из репозитория в любое удобное место и указать нужный путь.

    Инициализация

    Инициализировать библиотеку нужно перед вызовом внутренних функций SDK. Можно выставить уровень логирования и режим работы. Пример для AppDelegate:

    import UIKit
    import CKeySDK
    
    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
    
        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    
            // Установка уровня логирования и настройка конфигурации
            #if DEBUG
            CKeySDK.setLogLevel([.debug, .keys])
            let configuration = CKey.Configuration(debugMode: true)
            #else
            let configuration = CKey.Configuration()
            #endif
    
            do {
                // Инициализация библиотеки
                try CKey.initialize(configuration: configuration)
            } catch {
                ...
            }
            ...
    
        }
    
    }
    

    При debugMode: true проверка сертификатов на отзыв отключена, при запуске приложения отобразится экран, что SDK находится в режиме разработчика.

    Объекты и функции

    Для работы c УКЭП можно использовать:

    • UsersManager: Создает и управляет учетными записями пользователя на устройстве
    • OperationsManager: Получает информацию и подписывает операции и документы
    • CertificatesManager: Управляет сертификатами пользователей
    • DevicesManager: Управляет устройствами, привязанными к учетной записи
    • PolicyManager: Получает информацию о сервере СЭП

    Для работы c УНЭП можно использовать любые объекты и функции. Есть классы, которые включают в названии NonQual, в них есть расширенный набор методов:

    • UsersManagerNonQual: Создает и управляет учетными записями пользователя на устройстве
    • OperationsManagerNonQual: Получает информацию и подписывает операции и документы
    • CertificatesManagerNonQual: Управляет сертификатами пользователей
    • KeysManagerNonQual: Управляет сертификатами пользователей.

    Привязка устройства к учетной записи

    Перед тем, как начать подписывать документы и операции, нужно создать пользователя. Есть 3 способа это сделать:

    1. Онлайн-привязка устройства (сценарий с уникальный идентификатором)
    2. Привязка устройства с использованием QR-кода
    3. Привязать к другому устройству

    Сценарии УКЭП

    Онлайн-привязка устройства

    let createdUser = try await UsersManager.createUser(
        serviceURL: serverURL,          // Адрес сервера СЭП
        name: name,                     // Имя для сохранения учетной записи
        pushNotificationsData: data,    // Данные для отправки пуш-уведомлений
        deviceName: deviceName,         // Отображаемое дружественное имя устройства
        externalId: externalId,         // Внешний идентификатор
        alias: alias,                   // Человекочитаемый идентификатор устройства
        requirePassword: requirePwd     // Требуется ли установка пароля
    )
    

    Пользователь создан и сохранен в хранилище, его статус — .installed. Теперь нужно дождаться, когда его статус на сервере СЭП сменится на .notVerified. Чтобы проверить текущий статус:

    let updatedUser = try await UsersManager.updateStatus(
        user: user
    )
    

    Как только статус пользователя станет .notVerified, его возможно верифицировать:

    let verifiedUser = try await UsersManager.acceptAccountChanges(
        user: user
    )
    

    При верификации может потребоваться QR-код. Это зависит от настроек политики сервера.

    Теперь статус пользователя .active, с ним можно продолжить работу.

    Привязка устройства с использованием QR-кода

    let createdUser = try await UsersManager.createUserWithInitQR(
        name: name,                     // Имя для сохранения учетной записи
        pushNotificationsData: data,    // Данные для отправки пуш-уведомлений
        deviceName: deviceName,         // Отображаемое дружественное имя устройства
        externalId: externalId,         // Внешний идентификатор
        alias: alias,                   // Человекочитаемый идентификатор устройства
        requirePassword: true           // Требуется ли установка пароля
    )
    

    При создании пользователя данным способом потребуется отсканировать QR-код, сгенерированный сервером. После создания статус пользователя — .active, с ним можно продолжить работу.

    Привязать к другому устройству

    Данный способ применяется, когда уже есть устройство с подтвержденным пользователем и нужно привязать новое устройство. Потребуется передать идентификатор данного пользователя на новое устройство.

    Получить идентификатор можно у экземпляра пользователя:

    // Идентификатор подтвержденного пользователя, к которому привязываем новое устройство
    let uid = user.UserID
    

    На новом устройстве вызываем метод:

    let createdUser = try await UsersManager.createUserWithApproval(
        serviceURL: serverURL,          // Адрес сервера СЭП
        uid: uid,                       // Идентификатор пользователя, к которому привязываем устройство
        name: name,                     // Имя для сохранения учетной записи
        pushNotificationsData: data,    // Данные для отправки пуш-уведомлений
        deviceName: deviceName,         // Отображаемое дружественное имя устройства
        externalID: externalID,         // Внешний идентификатор
        alias: alias,                   // Человекочитаемый идентификатор устройства
        requirePassword: true           // Требуется ли установка пароля
    )
    

    Мы создали нового пользователя, его статус — .approveRequired, требуется подтверждение с основного устройства. На экране отобразится QR-код, который нужно отсканировать основным устройством.

    На основном устройстве вызываем метод processAwaitingDevice:

    try await DevicesManager.processAwaitingDevice(
        user: user  // Пользователь к которому привязываем устройство
    )
    

    Далее, на новом устройстве проверяем статус:

    try await UsersManager.checkApprovalStatus(
        user: newUser
    )
    

    Теперь новое устройство подтверждено, статус пользователя — .active и с ним можно работать на новом устройстве.

    Сценарии УНЭП

    В сценариях УНЭП пользовательский интерфейс SDK не используется, применяются дополнительные методы для работы с данными и используется класс UsersManagerNonQual.

    Зарегистрировать онлайн

    Для начала регистрации мы вызываем метод createUser:

    let createdUser = try await UsersManagerNonQual.createUser(
        serviceURL: serverURL,          // Адрес сервера СЭП
        pushNotificationsData: data,    // Данные для отправки пуш-уведомлений
        deviceName: deviceName,         // Отображаемое дружественное имя устройства
        externalId: externalId,         // Внешний идентификатор
        alias: alias,                   // Человекочитаемый идентификатор устройства
    )
    

    После регистрации будет создан User в статусе created. Для дальнейшей работы его нужно сохранить в хранилище.

    
    let storedUser = try await UsersManagerNonQual.store(
       user: user,        // Новый пользователь 
       name: name,        // Имя для хранения
       password: password // Пароль для хранения
    )
    

    После успешного сохранения у пользователя сменится статус на .installed. Далее, необходимо дождаться от сервера смены статуса на .notVerified. Для проверки статуса нужно вызвать UsersManager.updateStatus:

    //  Обновляем сведения о пользователе
    let updatedUser = UsersManager.updateStatus(
        user: user
    )
    if updatedUser.state == .notVerified {
        ...
    }
    

    После смены статуса на .notVerified необходимо вызвать метод UsersManagerNonQual.acceptAccountChanges. Данный метод требует, чтобы перед выполнением user.isReadyToSign == true.

    Дополнительно для присоединения может потребоваться QR-код: если user.verification == .qrRequired. Его необходимо отсканировать и распарсить заранее, а содержимое передать в параметре verificationQRValue.

    Персональные данные клиента для присоединения можно проверить в User.profile.

    if !user.isReadyToSign {
        // Предъявляем пароль
        try UsersManagerNonQual.submitPassword(user: user, password: password)
    }
    
    if user.verification == .qrRequired {
        // Парсим QR-код
        let qrValue = ...
        // Проверяем
        let verificationQRCode: QRCodeVerification = try CKey.analyzeQR(qrValue)
    }
    
    // Присоединяем к УЗ
    let acceptedUser = try await UsersManagerNonQual.acceptAccountChanges(
      user: user,                             // Пользователь
      verificationQRCode: verificationQRCode  // QR-код
    )
    

    Привязка устройства с использованием QR-кода

    Для начала регистрации с QR кодом его нужно получить и распарсить. После этого его можно передать в метод UsersManagerNonQual.createUserWithInitQR.

    QR-код может требовать активации. Код активации предоставляет сервер. Длину кода активации можно узнать, вызвав PolicyManager.getPolicy, в переменной Policy.activationCodeLength.

    
    // Парсим QR-код
    let registrationQRCode: QRCodeKinit = try CKey.analyzeQR(qrValue)
    
    // Проверяем активацию
    if !qrCode.isActivated {
        let activatedQRCode = try CKey.activate(qrCodeKinit: qrCode, code: activationCode)
    }
    
    // Регистрируем
    let createdUser = try await UsersManagerNonQual.createUserWithInitQR(
        qrCode: qrCode,                               // QR-код
        pushNotificationsData: pushNotificationsData, // Данные для отправки пуш-уведомлений
        deviceName: deviceName,                       // Отображаемое дружественное имя устройства
        externalId: externalId,                       // Внешний идентификатор
        alias: alias,                                 // Человекочитаемый идентификатор устройства
    )
    

    После регистрации будет создан User в статусе created. Для дальнейшей работы его нужно сохранить в хранилище.

    let storedUser = try await UsersManagerNonQual.store(
       user: user,        // Новый пользователь 
       name: name,        // Имя для хранения
       password: password // Пароль для хранения
    )
    

    Привязать к другому устройству

    Для привязки к другому устройству требуется знать uid и serviceURL уже существующего на другом устройствке пользователя. На новом устройстве нужно вызвать метод UsersManagerNonQual.createUserWithApproval с этими данными:

    let createdUser = try await UsersManagerNonQual.createUserWithApproval(
        serviceURL: serviceURL,                        // Адрес для взаимодействия существующего пользователя
        uid: userId,                                   // UserID существующего пользователя 
        pushNotificationsData: pushNotificationsData,  // Данные для отправки пуш-уведомлений
        deviceName: deviceName,                        // Отображаемое дружественное имя устройства
        externalId: externalId,                        // Внешний идентификатор
        alias: alias,                                  // Человекочитаемый идентификатор устройства
    )
    

    После регистрации будет создан User в статусе created. Для дальнейшей работы его нужно сохранить в хранилище.

    let storedUser = try await UsersManagerNonQual.store(
       user: user,        // Новый пользователь 
       name: name,        // Имя для хранения
       password: password // Пароль для хранения
    )
    

    После сохранения статус сменится на .approveRequired — присоединение данного пользователя нужно подтвердить или отклонить на основном устройстве. Для этого нужно вызвать DevicesManagerNonQual.approve или DevicesManagerNonQual.reject.

    Если для присоединения требуется отобразить персональные данные нового пользователя, то их можно найти в unapprovedUser.qrCode. В сценарии УКЭП на новом устройстве отображается этот QR-код, старое устройство его сканирует и отображает содержимое на экране.

    // Получаем список устройств
    let devices = try await DevicesManager.listDevices(
        user: user // Основной активный пользователь
    )
    
    // Находим неподтвержденное устройство
    let notApprovedDevice = devices.first(where { $0.state == .approveRequired })
    
    if !user.isReadyToSign {
        // Предъявляем пароль
        try UsersManagerNonQual.submitPassword(user: user, password: password)
    }
    
    // Подтверждаем присоединение
    try await DevicesManagerNonQual.approve(
       device: notApprovedDevice,   // Устройство, ожидающее подтверждения
       user: user                   // Основной активный пользователь
    )
    
    // ... или отклоняем
    try await DevicesManagerNonQual.reject(
       device: notApprovedDevice,   // Устройство, ожидающее подтверждения
       user: user                   // Основной активный пользователь
    )
    

    После этого на новом устройстве нужно проверить и обновить статус пользователя:

    do {
        let approvedUser = try await UsersManagerNonQual.checkApprovalStatus(
            user: userToCheck // Новый пользователь
        ) 
    } catch SDKError.approveRequired {
        ... // По-прежнему ожидаем подтверждение на основном устройстве
    } catch { 
        ...
    }
    

    Устройства и пользователи

    Управление пользователями на текущем устройстве осуществляется с помощью классов UsersManager и UsersManagerNonQual.

    Управление устройствами осуществляется с помощью DevicesManager и DevicesManagerNonQual.

    Пользователей, установленных на устройстве, можно получить в UsersManager.users.

    Связанные устройства (в том числе и ожидающие подтверждения) можно получить, вызвав DevicesManager.listDevices:

    let devices = try await DevicesManager.listDevices(user: user)
    

    Прикрепление пользователя к устройству

    Добавление пользователя на новое устройство нужно подтвердить на старом с помощью метода DevicesManager.processAwaitingDevice.

    Пример использования:

    
    // Проходим регистрацию на новом устройстве
    let approvedUser = try await UsersManager.createUserWithApproval(
        serviceURL: serverURL,           // Адрес сервера СЭП
        uid: mainDeviceUserId,           // Идентификатор пользователя с основного устройства
        name: name,                      // Имя для сохранения учетной записи
        pushNotificationsData: data,     // Данные для отправки пуш-уведомлений
        deviceName: deviceName,          // Отображаемое дружественное имя устройства
        externalId: externalId,          // Внешний идентификатор
        alias: alias,                    // Человекочитаемый идентификатор устройства
        requirePassword: requirePwd,     // Требуется ли установка пароля
        statusCheckingInterval: interval // Интервал проверки присоединения устройства
    )
    
    // На основном устройстве потребуется подтвердить присоединение нового
    try await DevicesManager.processAwaitingDevice(
        user: user  // Пользователь, к которому привязывается новое устройство
    )
    

    С остальными методами можно ознакомиться в описаниях классов

    • DevicesManagerNonQual
    • DevicesManager

    Операции и документы

    Получение списка операций

    let operations = try await OperationsManager.getOperationsList(
        user: user,         // Пользователь, для которого проверяются операции
        operationType: nil, // Фильтр операций по типу
        operationID: nil    // Фильтр по идентификатору
    )
    

    Подтверждение операции

    let approveRequest = try await OperationsManager.confirmOperation(
        operation: operation,   // Операция для подтверждения
        user: user,             // Пользователь, подтверждающий операцию
        signMode: .online       // Способ подтверждения. В данном случае — online
    )
    

    Загрузка документов

    let uploadedDocumentId = try await OperationsManager.uploadDocument(
        documentContent: documentData,      // Бинарные данные документа
        title: documentTitle,               // Заголовок документа
        snippetTemplate: documentSnippet,   // HTML-сниппет документа
        previewTemplate: documentPreview,   // HTML-превью документа
        user: user                          // Пользователь-владелец документа
    )
    

    Подпись документов

    
    // Формируем параметры подписания
    let templateId = signServerParams.processingTemplates.first.id
    let certificateId = certificate.CertificateId
    let signParams = SignParams(
        signTemplateId: templateId, // Идентификатор шаблона подписи
        certId: certificateId,      // Идентификатор сертификата, которым будем подписывать
        pinCode: ""                 // Пин-код от сертификата. Если пин-код не установлен, то укажите пустую строку
    )
    
    // Подписываем и получаем результаты подписания
    let signingResults = try await OperationsManager.signDocuments(
        documentsIDs: confirmedDocuments,           // Документы для подписания
        user: user,                                 // Пользователь, подписывающий документы
        signParams: signParams                      // Параметры подписания
    )
    

    Дополнительная информация

    Параметры подписания

    Для параметров подписания нужно получить параметры сервера подписания и идентификатор сертификата:

    // Получаем параметры сервера подписания
    let signServerParams = try await PolicyManager.getSignServerParams(
        user: user  // Пользователь, запрашивающий параметры сервера подписания
    )
    
    ...
    
    // Получаем сертификат
    let certificates = try await CertificatesManager.listCertificates(
        user: user  // Пользователь, запрашивающий сертификаты
    )
    
    ...
    
    // Выбираем сертификат, например, первый в списке. Запросы на сертификат игнорируем
    let certificate: Certificate = certificates.first(where: {
        $0.type == .certificate
    })
    

    С остальными доступными методами можно ознакомиться в описании API:

    • OperationsManager
    • OperationsManager​Non​Qual.

    Обновление профиля устройства

    Для обновление профиля устройства и симметричных ключей можно воспользоваться методом UsersManager.renew(user:callback:). После использования метода старый User будет заменен новым.

    let userToRenew: User = ... // Пользователь, которого хотим обновить
    let renewedUser = try await UsersManagerNonQual.renew(user: userToRenew)
    

    Работа с NFC картами и токенами Рутокен

    Для работы с NFC требуется отдельная сборка CKeySDK_NFC

    Установка сборки с NFC

    Swift Package Manager

    Добавьте пакет CKey_NFC из репозитория:

    https://.../ckey-nfc.git
    

    CocoaPods

    Добавьте в файл Podfile зависимости:

    pod 'CKey_NFC',           :git => 'https://.../ckey-nfc.git'
    

    Ручная установка

    Добавьте в проект CKey_NFC.xcframework.

    Ресурсы для NFC

    Необходимо добавить в проект ресурсы аналогично инструкции.

    Настройка проекта

    Для работы с картами и токенами Рутокен нужно дополнительно настроить проект по документации Рутокен.

    Убедитесь, что в проект добавлены все необходимые библиотеки и указаны все идентификаторы карт.

    Для работы с NFC токенами доступно 2 сценария:

    • Работа с NFC картами и токенами Рутокен
      • Установка сборки с NFC
        • Swift Package Manager
        • CocoaPods
        • Ручная установка
        • Ресурсы для NFC
      • Настройка проекта
      • Импорт сертификата с карты
      • Создание ключей на карте

    Импорт сертификата с карты

    Для импорта сертификата сначала нужно получить с карты все доступные сертификаты, а потом нужный загрузить на сервер.

    При перечислении сертификатов будет возвращен массив [Result<Certificate, Error>]. Считывание данных сертификата — отдельная операция. Поэтому возвращаются результаты всех считываний по-отдельности.

    После перечисления необходимо выбрать нужный сертификат и выгрузить его в СЭП. Для этого нужно передать его в метод CertificateManager.setCertificate(user:certificate:).

    После выгрузки сертификата NFC-токен можно использовать для подписании документов.

    // Перечисление доступных сертификатов на карте
    let certificatesResults = try await CertificatesManager.listExternalCertificates()
    
    let certificateToImport = ... // Выбираем сертификат для импорта
    
    // Загружаем сертификат на сервер
    try await CertificatesManager.setCertificate(
        user: user,
        certificate: certificateToImport
    )
    

    Создание ключей на карте

    Создание ключей происходит при вызове метода CertificatesManagerNonQual.signCertificateRequest. Место для создания ключей выбирается параметром keysSource. По-умолчанию выбрано KeysSourceIdentifier.localGeneric — ключи создаются на устройстве. Для NFC-токенов необходимо выбрать KeysSourceIdentifier.rutokenNFC.

    После создания ключей и подписания запроса на сертификат, нужно дождаться выпуска сертификата. Текущие сертификаты проверяем методом CertificatesManager.listCertificates(user:callback:).

    Как только сертификат будет выпущен, его можно установить на устройство методом CertificatesManager.install.

    После установки сертификата NFC-токен можно использовать для подписания документов.

    
    // Подписываем запрос на сертификат
    try await CertificatesManagerNonQual.sign(
        certificateRequest: certificateRequest,
        user: user,
        keysSource: .rutokenNFC // Используем NFC-токен Рутокен
    )
    
    // Получаем список сертификатов
    let certificates = CertificatesManager.listCertificates(...)
    
    // Проверяем, выпущен ли сертификат
    let certificateToInstall: Certificate = certificates.first {
        // Сертификат активный
        $0.state == .active && 
        // Ключи хранятся на клиенте
        $0.isClient &&
        // Ключи хранятся на текущем устройстве
        CertificatesManagerNonQual.checkIfAccessibleOnThisDevice(certificate: $0, for: user) &&
        // Сертификт не установлен
        !CertificatesManagerNonQual.checkIfInstalled(certificate: $0, for: user)
    } 
    
    // Устанавливаем выпущеный сертификат
    try await CertificatesManagerNonQual.install(
        certificate: certificateToInstall,
        user: user
    )
    

    Логирование

    У фреймворка есть возможность подключить внешний логгер. Для этого логгер должен наследовать протокол LoggerProtocol.

    public protocol LoggerProtocol {
    
        func debug(_ message: String, category: LoggingCategory)
        func error(_ message: String, category: LoggingCategory)
        func sensitive(_ message: String, category: LoggingCategory)
    
    }
    
    
    /// Пример логгера
    
    struct MyLogger: LoggerProtocol {
    
        func debug(_ message: String, category: LoggingCategory) {
            ...
        }
    
        func error(_ message: String, category: LoggingCategory) {
            ...
        }
    
        func sensitive(_ message: String, category: LoggingCategory) {
            ...
        }
    
    }
    

    После определения логгера, его нужно передать в метод CKey.setLogger(...):

    let myLogger = MyLogger()
    // CKey.setLogLevels([.debug, .keys]) <- Теперь можно убрать из кода приложения
    CKey.setLogger(myLogger, options: [.debug, .sensitive])
    

    После этого сообщения из SDK будут передаваться в установленный логгер.


    Сохранение логов в файл

    В SDK нет встроенных методов для сохранения логов файл. Но можно подключить стороннюю библиотеку, например CocoaLumberjack:

    import CocoaLumberjack
    import CocoaLumberjackSwift
    
    ...
    
    // Настраиваем CocoaLumberjack
    let fileLogger = DDFileLogger()
    fileLogger.logFileManager.maximumNumberOfLogFiles = 2  // Храним только 2 файла
    fileLogger.maximumFileSize = 256 * 1024                // не более 256kb каждый
    fileLogger.rollingFrequency = 60 * 60 * 24             // с сообщениями за последние 24 часа
    DDLog.add(fileLogger)
    
    ...
    
    // Описываем методы логгера
    final class MyLogger: LoggerProtocol {
    
        func debug(_ message: String, category: LoggingCategory) {
            DDLogInfo("[SDK][\(category)] \(message)")
        }
    
        func error(_ message: String, category: LoggingCategory) {
            DDLogError("[SDK][\(category)] \(message)")
        }
    
        func sensitive(_ message: String, category: LoggingCategory) {
            #if DEBUG
            DDLogInfo("[SDK][Sensitive][\(category)] \(message)")
            #endif
        }
    
    }
    
    ...
    
    // Назначаем логгер
    CKey.setLogger(MyLogger(), options: [.debug, .sensitive])
    

    Чтобы получить логи, используем API CocoaLumberjack:

    fileLogger
        .logFileManager
        .sortedLogFileInfos
        .compactMap { (info: DDInfo) -> Data in
            FileManager.default.contents(atPath: info.filePath) // Читаем логи из файла
        }
        .forEach { (logData: Data) in
            ... // Обрабатываем логи каждого файла
        }
    

    Оформление интерфейса

    За внешний вид интерфейса отвечают файлы экранов *.xib и ассеты CKeySDK_Assets.xcassets. Префикс ассетов может отличаться в зависимости от версии SDK — CKeySDK или CKeySDK_NFC.

    Xib файлы

    Xib Описание
    CKeySDK_MainNavigationController.xib Контроллер навигации всех экранов
    CKeySDK_MainNavigationController.xib Контроллер навигации всех экранов
    CKeySDK_CameraNavigationController.xib Контроллер навигации экрана с камерой
    CKeySDK_OverlayViewController.xib Оверлей с индикатором активности. Закрывает экран приложения при взаимодействии с фреймворком.
    CKeySDK_CameraViewController.xib Экран с камерой
    CKeySDK_ApprovingQRViewController.xib Экран с QR-кодом для присоединения другого устройства
    CKeySDK_PasswordViewController.xib Экран с вводом и созданием ПИН-кода
    CKeySDK_BiometrySuggestionViewController.xib Экран с предложением использовать биометрию
    CKeySDK_DocumentsListViewController.xib Экран со списком документов
    CKeySDK_DocumentPreviewCell.xib Ячейка с превью документа
    CKeySDK_PDFViewController.xib Просмотр PDF документа
    CKeySDK_AcceptAccountActionsViewController.xib Действия при подтверждении присоединения к УЗ
    CKeySDK_ProcessDeviceActionsViewController.xib Действия при подтверждении присоединения к другому устройству
    CKeySDK_DocumentsActionsViewController.xib Действия при подписании документов
    CKeySDK_OperationActionsViewController.xib Действия при работе с операцией с документами
    CKeySDK_InfoViewController.xib Общие экран с таблицей значений
    CKeySDK_KeyValueCell.xib Ячейка с заголовком и значением
    RndmBioViewController.xib Генератор случайных чисел CPROCSP
    RndmBioViewControllerIPhone.xib Генератор случайных чисел CPROCSP для iPhone

    Ассеты

    В ассетах CKeySDK_Assets.xcassets лежат цвета и изображения по-умолчанию.

    Совместимость с Appearance

    Для настройки оформления через код используются классы с префиксом Custom. Они применяют к элементам в xib'ах стили, описаные в CKey.appearance.*:

    • CustomView
    • CustomImageView
    • CustomLabel
    • CustomButton
    • CustomKeyboardButton
    • CustomGradientView
    • CustomPDFView

    Если сбросить класс компонентов на стандартный (UIView, UILabel, ...), то стили Appearance применяться не будут.

    Работа с распространенными ошибками

    SDKError

    Данные ошибки возвращает SDK.

    При возникновении ошибки SDKError.networkError, необходимо смотреть на параметр code:

    12002

    The request has timed out

    Превышено ожидание ответа от сервера.

    12007

    The server name could not be resolved.

    Не удается подключиться к конечной точке. Возможные причины:

    • отсутствие интернета
    • некорректный адрес сервера
    • сервер недоступен

    12175

    WinINet failed to perform content decoding on the response. For more information, see the Content Encoding topic.

    Возникла проблема с сертификатами. Возможные причины:

    • В бандле приложения нет папок root-certs/prod с корневыми сертификатами сервера
    • Корневые сертификаты имеют некорректный формат. Например, у них расширение .cer, а не .crt. Либо они не в формате PEM.
    • Среди сертификатов нет подходящих для работы с данным сервером
    • Сервер не настроен должным образом

    Работа с UI

    Методы SDK в которых есть интерфейс, могут возвращать ошибку SDKError.canceled — она означает, что пользователь закрыл UI.

    ServerError

    Данные ошибки возвращает сервер. При обработке статуса пользователя можно наткнуться на следующие ошибки:

    • .userNotFound: Пользователь был удален на сервере
    • .deviceBlocked: Устройство заблокировано на сервере
    • .keyExpiredOrNotYetValid: Срок действия ключей истек еще не наступил

    Т.е. например при вызове UsersManager.updateStatus мы не получим User со статусом .expired, а метод вернет ошибку ServerError.keyExpiredOrNotYetValid

    В начало © ООО "КРИПТО-ПРО", 2000–2025