Встраивание КриптоПро Ключ 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
.
Это необходимо, чтобы была возможность выполнять дополнительные исполняемые файлы при сборке проекта.
Инициализация SDK
Для загрузки SDK в составе собственного приложения рекомендуется вызывать сразу после запуска или при запуске приложения следующий код:
DSSCryptoProDss.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()
}
}
}