Показать/Скрыть содержание

    Встраивание КриптоПро Ключ SDK в мобильное приложение (iOS)

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

    Инструкция предназначена для разработчиков мобильных приложений для iOS версии 13 и новее, использующих фреймворк разработки пользовательских интерфейсов UI Kit. Требуется Xcode 11 и macOS 10.15 или новее. Рекомендуется использовать последние версии перечисленного программного обеспечения.

    Добавление необходимых файлов в проект

    1. Перенести в папку Frameworks Вашего проекта полученный фреймворк с КриптоПро Ключ SDK DSSFramework.xcframework.

    • В XCode перенести в папку Frameworks c выбранной опцией Create folder references.
    • Открыть DSSFramework.xcframework как папку через Finder и также перенести DSSFrameworkSupport.xcframework в папку Frameworks с аналогичной опцией.

    2. Открыть DSSFramework.xcframework как папку через Finder и оттуда перенести папку Scripts в корневую папку Вашего проекта.

    Примечание

    Корневой папкой будем называть главную папку проекта, где лежат файлы проекта XCode .xcodeproj (.xcworkspace) и/или папку, относительно которой идет работа с git.

    3. В Xcode из DSSFramework.xcframework перенести файл AppControl.c в папку, где лежат файлы приложения-клиента. Например, у корневой папки SignIt есть внутри одноименная папка SignIt, где лежат файлы AppDelegate и прочие.

    При копировании необходимо использовать следующие параметры.

    4. В Xcode в DSSFramework.xcframework открыть папку CSP и перетащить папки en.lproj и ru.lproj в папку Resources.

    При копировании необходимо использовать следующие параметры.

    После добавления папок их иконки в XCode слева должны быть серого цвета.

    5. В Xcode в DSSFramework.xcframeworkиз папки CSP перенести оставшиеся файлы в папку Resources Вашего проекта.

    При копировании необходимо использовать следующие параметры.

    Итоговый результат должен выглядеть следующим образом.

    *6. Настройка правил сборки в случае использования Xcode 16 и новее: изменить параметр Build Rules для папки locale. По умолчанию параметр равен Apply to Each File. Необходимо установить значение параметра Apply Once to Folder, выбрав его из выпадающего списка (1, 2). После установки значения необходимо убедиться, что папка включена в необходимые для сборки Target Membership Вашего проекта (3).

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

    1. Открыть настройки Вашего проекта и выбрать свое приложение в Targets. Во вкладке General открыть опцию "Frameworks, Libraries, and Embedded Content" и напротив DSSFramework.xcframework выбрать опцию Embed & Sign.

    2. Открыть настройки Вашего проекта и выбрать свое приложение в Targets. Во вкладке Build Phases открыть опцию Run Script. Удалить все, что там было до этого, и добавить следующую строку:
    ./Scripts/ConfigureApplication.

    Примечание

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

    3. Открыть настройки Вашего проекта и выбрать свое приложение в Targets. Во вкладке Build Settings открыть опцию Build Options. В ней установить значение User Script Sandboxing равным No. Это необходимо, чтобы была возможность выполнять дополнительные исполняемые файлы при сборке проекта.

    Активация контроля целостности мобильного приложения

    Примечание

    Выполнение этого пункта является обязательным, но не позволит пользоваться Canvas для предпросмотра UI. Допустимо выполнить шаги данного пункта после разработки UI мобильного приложения. См. подробнее в документации по встраиванию КриптоПро CSP для iOS

    1. Во вкладке Build Settings открыть опцию Build Options. В ней установить значение Enable Debug Dylib равным No.

    2. В коде собственного мобильного приложения объявить метод контроля целостности:

    @_silgen_name("register_app_checksum")
    func registerAppChecksum()
    
    Примечание

    Необходимо убедиться, что в дистрибутиве SDK в файле AppControl.c есть объявление метода register_app_checksum.

    3. Вызвать метод registerAppChecksum при запуске собственного мобильного приложения для вычисления эталонной контрольной суммы приложения и метод checkIntegrity для ее проверки.

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

    Подробнее о контроле целостности

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

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

    SDKFramework.shared._init() { res in
                var message: String = "Инициализация SDK"
                switch res {
                case .init_ok:
                    //MARK:- Успешная инициализация
                    message = "SDK успешно инициализирован"
                case .init_lockScreen_not_installed:
                    //MARK:- На устройстве не настроен экран блокировки
                    message("SDK инициализирован")
                case .init_certs_not_installed:
                    //MARK:- Корневые сертификаты не установлены
                    message = "Ошибка инициализации SDK"
                case .init_device_rooted:
                    //MARK:- Устройство имеет права суперпользователя
                    message = "Ошибка инициализации SDK"
                }
                print(message)
            }
    

    Интеграция с UI собственного приложения

    В SDK предусмотрено взаимодействие с пользователем, поэтому для работы пользовательского интерфейса необходимо реализовать протокол DSSNavigationDelegate. Он отвечает за “стыковку” интерфейса приложения, куда встраивают SDK, и веб-интерфейса самого SDK.

    Описание протокола

    @MainActor
    public protocol DSSNavigationDelegate: AnyObject {
    
        /// Показ форм SDK
        /// - Parameters:
        ///   - navigationController: NavigationController, который необходимо отобразить, желательно на UIWindow
        ///   - animated: нужна ли анимация?
        ///   - completion: завершения события показа
        func needShow(navigationController: DSSNavigationController, animated: Bool, completion: @escaping (() -> Void))
    
        /// Закрытие форм SDK
        /// - Parameters:
        ///   - navigationController: NavigationController, который необходимо спрятать (должен соответствовать needShow)
        ///   - animated: нужна ли анимация?
        ///   - completion: завершения события закрытия
        func needHide(navigationController: DSSNavigationController, animated: Bool, completion: @escaping (() -> Void))
    
        /// Требование показа модального экрана сетевой активности
        func needShowLoading()
        /// Требование закрытия модального экрана сетевой активности
        func needHideLoading()
    }
    
    Примечание
    • В методах needShow / needHide параметр navigationController – это объект подкласса от UINavigationController, отвечающий за UI в SDK.
    • Методы needShow / needHide вызывается самим SDK при его необходимости отобразить/закрыть пользовательский интерфейс.
    • В методе needShow SDK передает свой navigationController, который необходимо отобразить в данный момент.

    Описанный выше протокол необходимо встроить в место взаимодействия собственного приложения с UI, например, в файл SceneDelegate.swift (Создается автоматически при создании проекта, отвечает за жизненный цикл приложения). Для этого необходимо добавить в метод scene следующие строки.

    Листинг начала метода scene

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession,
    options connectionOptions: UIScene.ConnectionOptions)
    

    Добавляемые строки

    DSSNavigation.shared.delegate = self
    DSSNavigation.shared.modalLoadingForSilentRequestType = .outer
    
    Примечание

    Параметр modalLoadingForSilentRequestType отвечает за отображение модального окна загрузки сетевой активности SDK.

    • Значение modalLoadingForSilentRequestType = .outer означает, что модальное окно сетевой активности SDK будет реализовано тем, кто встраивает SDK. При использовании данного типа реализации собственные окна загрузки необходимо настраивать и отображать собственными средствами в методах needShowLoading / needHideLoading.
    • Значение modalLoadingForSilentRequestType = .inner означает, что модальное окно сетевой активности SDK будет отображается средствами SDK.

    Пример работы с UI в SDK и реализация протокола DSSNavigationDelegate в файле SceneDelegate.swift, где currentVC - текущий UIViewController, отображаемый собственным приложением. Отображение модальных окон сетевой загрузки не предусмотрено.

    import UIKit
    import DSSFramework
    
    class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    
        var window: UIWindow?
        var currentVC: UIViewController?
    
        func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
            //...Собственная работа с UI
    
            DSSNavigation.shared.delegate = self
            DSSNavigation.shared.modalLoadingForSilentRequestType = .outer
        }
    
        //...Остальные методы SceneDelegate
    }
    
    extension SceneDelegate: DSSNavigationDelegate {
        func needShowLoading() { }
    
        func needHideLoading() { }
    
        func needShow(navigationController: DSSNavigationController,
            animated: Bool, completion: @escaping (() -> Void)) {
    
            guard let window = self.window else { return }
            self.currentVC = window.rootViewController
    
            window.rootViewController = navigationController
    
            if animated == true {
                let options: UIView.AnimationOptions = .transitionCrossDissolve
                UIView.transition(with: window, duration: 0.2, options: options,
                                  animations: {}, completion: { completed in
                    completion()
                })
            } else {
                completion()
            }
        }
    
        func needHide(navigationController: DSSNavigationController,
                      animated: Bool, completion: @escaping (() -> Void)) {
    
            guard let window = self.window else { return }
            guard let currentVC = self.currentVC else { return }
            window.rootViewController = currentVC
    
            if animated == true {
                let options: UIView.AnimationOptions = .transitionCrossDissolve
                UIView.transition(with: window, duration: 0.2, options: options,
                                  animations: {}, completion: { completed in
                    completion()
                })
            } else {
                completion()
            }
        }
    }
    

    Тестовый пример проекта

    Загрузить тестовый проект

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