Commit e56c8c6b authored by Javokhir's avatar Javokhir
Browse files

2.3.3

parent 66252f44
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "83.5x83.5"
},
{
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21678"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="MyIdSample" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="18.840579710144929" y="97.767857142857139"/>
</scene>
</scenes>
<resources>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
<key>UISceneStoryboardFile</key>
<string>Main</string>
</dict>
</array>
</dict>
</dict>
</dict>
</plist>
//
// StartViewController.h
// MyIdSample
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface StartViewController : UIViewController
@end
NS_ASSUME_NONNULL_END
//
// StartViewController.m
// MyIdSample
#import "StartViewController.h"
@import MyIdSDK;
@interface StartViewController ()<MyIdClientDelegate>
@end
@implementation StartViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (IBAction)startMyId {
MyIdOrganizationDetails *organizationDetails = [[MyIdOrganizationDetails alloc] init];
organizationDetails.phoneNumber = @"4242";
MyIdAppearance *appearance = [[MyIdAppearance alloc] init];
appearance.primaryColor = [UIColor systemBlueColor];
MyIdConfig *config = [[MyIdConfig alloc] init];
config.clientId = @"";
config.passportData = @"";
config.dateOfBirth = @"";
config.externalId = @"";
config.buildMode = MyIdBuildModePRODUCTION;
config.entryType = MyIdEntryTypeAUTH;
config.residency = MyIdResidencyRESIDENT;
config.locale = MyIdLocaleUZ;
config.cameraShape = MyIdCameraShapeCIRCLE;
config.organizationDetails = organizationDetails;
config.appearance = appearance;
config.withPhoto = false;
[MyIdClient startWithConfig:config withDelegate:self];
}
#pragma mark MyIdClientDelegate
- (void)onSuccessWithResult:(MyIdResult *)result {
NSLog(@"%@", result.code);
NSLog(@"%@", result.comparisonValue);
NSLog(@"%@", result.image);
}
- (void)onErrorWithException:(MyIdException *)exception {
NSLog(@"%@", exception.code);
NSLog(@"%@", exception.message);
}
- (void)onUserExited {
NSLog(@"user exited");
}
@end
//
// AppDelegate.swift
// MyIdSample
//
// Created by Javokhir Savriev on 12/10/22.
//
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
return true
}
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
}
}
//
// SceneDelegate.swift
// MyIdSample
//
// Created by Javokhir Savriev on 12/10/22.
//
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let _ = (scene as? UIWindowScene) else { return }
}
func sceneDidDisconnect(_ scene: UIScene) {
}
func sceneDidBecomeActive(_ scene: UIScene) {
}
func sceneWillResignActive(_ scene: UIScene) {
}
func sceneWillEnterForeground(_ scene: UIScene) {
}
func sceneDidEnterBackground(_ scene: UIScene) {
}
}
//
// ViewController.swift
// MyIdSample
//
// Created by Javokhir Savriev on 12/10/22.
//
import UIKit
import MyIdSDK
class ViewController: UIViewController {
private let clientIdTextField: UITextField = {
let textField = UITextField()
textField.placeholder = "Client ID"
textField.borderStyle = .roundedRect
textField.translatesAutoresizingMaskIntoConstraints = false
return textField
}()
private let passportTextField: UITextField = {
let textField = UITextField()
textField.placeholder = "Passport data"
textField.borderStyle = .roundedRect
textField.translatesAutoresizingMaskIntoConstraints = false
return textField
}()
private let dobTextField: UITextField = {
let textField = UITextField()
textField.placeholder = "Date of birth"
textField.borderStyle = .roundedRect
textField.translatesAutoresizingMaskIntoConstraints = false
return textField
}()
private let textResult: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: 16)
label.textAlignment = .center
label.numberOfLines = 0
label.lineBreakMode = .byTruncatingTail
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
private let imageResult: UIImageView = {
let imageView = UIImageView()
imageView.heightAnchor.constraint(equalToConstant: 200).isActive = true
imageView.contentMode = .scaleAspectFit
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
private var buildType: MyIdBuildMode = .PRODUCTION
private var faceImage: UIImage? = nil
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
}
func loadPayload() throws -> Data {
let payloadURL = Bundle.main.url(forResource: "payload", withExtension: "json")!
let payloadData = try Data(contentsOf: payloadURL)
return payloadData
}
@objc func buildTypeControlChanged(sender: UISegmentedControl) {
if sender.selectedSegmentIndex == 1 {
buildType = .DEBUG
} else {
buildType = .PRODUCTION
}
}
@objc func scanButtonPressed(sender: UIButton) {
startMyId()
}
@objc func saveButtonPressed(sender: UIButton) {
saveImage()
}
private func startMyId() {
let config = MyIdConfig()
config.clientId = "client_id"
config.clientHash = "client_hash"
config.clientHashId = "client_hash_id"
config.passportData = self.passportTextField.text ?? ""
config.dateOfBirth = self.dobTextField.text ?? ""
config.buildMode = self.buildType
MyIdClient.start(withConfig: config, withDelegate: self)
}
private func saveImage() {
guard let image = faceImage else { return }
ImageSaver().writeToPhotoAlbum(image: image)
}
}
extension ViewController: MyIdClientDelegate {
func onSuccess(result: MyIdResult) {
textResult.text = "\(String(describing: result.code))"
imageResult.image = result.image
faceImage = result.image
}
func onError(exception: MyIdException) {
textResult.text = "\(String(describing: exception.message)) - \(String(describing: exception.code))"
}
func onUserExited() {
textResult.text = "User exited"
}
}
extension ViewController {
private func setupViews() {
let margins = view.layoutMarginsGuide
let scrollView = UIScrollView()
scrollView.translatesAutoresizingMaskIntoConstraints = false
let buildTypeControl = UISegmentedControl(items: ["PROD", "DEV"])
buildTypeControl.addTarget(self, action: #selector(buildTypeControlChanged), for: .valueChanged)
buildTypeControl.selectedSegmentIndex = 0
buildTypeControl.translatesAutoresizingMaskIntoConstraints = false
let scanButton = UIButton()
scanButton.translatesAutoresizingMaskIntoConstraints = false
scanButton.setTitle("Scan Face Data", for: .normal)
scanButton.setTitleColor(.blue, for: .normal)
scanButton.addTarget(self, action: #selector(scanButtonPressed), for: .touchUpInside)
let saveButton = UIButton()
saveButton.translatesAutoresizingMaskIntoConstraints = false
saveButton.setTitle("Save Image", for: .normal)
saveButton.setTitleColor(.red, for: .normal)
saveButton.addTarget(self, action: #selector(saveButtonPressed), for: .touchUpInside
let stackView = UIStackView()
stackView.axis = .vertical
stackView.alignment = .leading
stackView.spacing = 16
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.addArrangedSubview(clientIdTextField)
stackView.addArrangedSubview(passportTextField)
stackView.addArrangedSubview(dobTextField)
stackView.addArrangedSubview(scanButton)
stackView.addArrangedSubview(saveButton)
stackView.addArrangedSubview(textResult)
stackView.addArrangedSubview(imageResult)
scrollView.addSubview(stackView)
view.addSubview(scrollView)
NSLayoutConstraint.activate([
scrollView.leadingAnchor.constraint(equalTo: margins.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: margins.trailingAnchor),
scrollView.topAnchor.constraint(equalTo: margins.topAnchor),
scrollView.bottomAnchor.constraint(equalTo: margins.bottomAnchor)
])
NSLayoutConstraint.activate([
stackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
stackView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 20),
stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
stackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor)
])
NSLayoutConstraint.activate([
clientIdTextField.widthAnchor.constraint(equalTo: stackView.widthAnchor),
passportTextField.widthAnchor.constraint(equalTo: stackView.widthAnchor),
dobTextField.widthAnchor.constraint(equalTo: stackView.widthAnchor),
scanButton.centerXAnchor.constraint(equalTo: stackView.centerXAnchor),
saveButton.centerXAnchor.constraint(equalTo: stackView.centerXAnchor),
])
let tap = UITapGestureRecognizer(target: self, action: #selector(UIInputViewController.dismissKeyboard))
view.addGestureRecognizer(tap)
}
@objc func dismissKeyboard() {
view.endEditing(true)
}
}
// swift-tools-version: 5.9
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "MyIdSDK",
platforms: [
.iOS(.v12)
],
products: [
.library(
name: "MyIdSDK",
targets: ["MyIdSDK"]),
],
targets: [
.binaryTarget(
name: "MyIdSDK",
url: "https://gitlab.myid.uz/myid-public-code/myid-ios-sdk/uploads/3e2a52925cf517b1c29758dbba818027/MyIdSDK.xcframework.zip",
checksum: "ebff72f667d25135b8966a2a901d34ada25e71f976bc184a5fec5a1ac6acdbfb"
)
]
)
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'
target 'MyIdSample' do
use_frameworks!
target 'MyIdSampleTests' do
inherit! :search_paths
# Pods for testing
end
target 'MyIdSampleUITests' do
# Pods for testing
end
pod 'MyIdSDK'
end
\ No newline at end of file
PODS:
- MyIdSDK (2.2.2)
DEPENDENCIES:
- MyIdSDK
SPEC REPOS:
trunk:
- MyIdSDK
SPEC CHECKSUMS:
MyIdSDK: def78f7b73af02acda500f7a3f3e221ca9bfe20b
PODFILE CHECKSUM: 3d43422acf589a5c2bd22a9c89828a68b010d362
COCOAPODS: 1.13.0
### Manual Installation
# MyID iOS SDK
![Xcode manual installation steps](https://gitlab.myid.uz/myid-public-code/myid-ios-sdk/-/raw/master/images/xcode_manual_installation.png)
## Table of contents
1. Select your project in Xcode.
- [Changelog](CHANGELOG.md)
- [Getting started](#getting-started)
- [Before you begin](#11-before-you-begin)
- [Add the SDK dependency](#12-add-the-sdk-dependency)
- [Permissions](#13-permissions)
- [Usage](#usage)
- [Options](#21-options)
- [Handling callbacks](#22-handling-callbacks)
- [SDK error codes](#sdk-error-codes)
- [UI customization](CUSTOMIZATION.md)
2. Select your app target.
## Getting started
3. Select the **General** tab and then scroll down to **Frameworks, Libraries, and Embedded Content**.
### 1.1 Before you begin
4. Add the following files from the [release assets](https://gitlab.myid.uz/myid-public-code/myid-ios-sdk/-/releases):
Install or update Xcode to its latest version.
The SDK supports iOS 12+. The SDK has been built on Xcode 14.1 using Swift 5.8
- `MyIdSDK.xcframework`
### 1.2 Add the SDK dependency
> **Note**: Ensure you add the .xcframework files, rather than the .framework files.
#### [Manual installation](MANUAL_INSTALLATION.md)
5. Under the **Embed** column, ensure **Embed & Sign** is set for MyIdSDK framework.
#### Using Cocoapods
The SDK is available on Cocoapods and you can include it in your projects by adding the following to your Podfile:
```ruby
pod 'MyIdSDK', '~> 2.3.3'
```
Run `pod install` to get the SDK.
### 1.3 Permissions
The SDK uses the device camera. You're required to have the following keys in your application's `Info.plist` file:
* `NSCameraUsageDescription`
```xml
<key>NSCameraUsageDescription</key>
<string>Required for document and facial capture</string>
```
**Note**: All keys will be required for app submission.
## Usage
``` swift
import UIKit
import MyIdSDK
class ViewController : UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
private func startMyId() {
let config = MyIdConfig()
config.clientId = /* Your Client ID */
config.clientHash = /* Your Client Hash */
config.clientHashId = /* Your Client Hash ID */
config.passportData = passportData
config.dateOfBirth = dateOfBirth
config.buildMode = MyIdBuildMode.PRODUCTION
MyIdClient.start(withConfig: config, withDelegate: self)
}
}
extension ViewController: MyIdClientDelegate {
func onSuccess(result: MyIdResult) {
if let code = result.code {
print(code)
}
if let image = result.image {
print(img)
}
}
func onError(exception: MyIdException) {
print(exception.code)
print(exception.message)
}
func onUserExited() {
print("User exited")
}
}
```
### 2.1 Options
Option | Notes | Default
--- | --- | ---
`clientId` | Client ID | Provided by MyID sales team. Mandatory, if using entryType = MyIdEntryType.AUTH
`clientHash` | Client Hash | Provided by MyID sales team. Mandatory, if using entryType = MyIdEntryType.AUTH
`clientHashId` | Client Hash ID | Provided by MyID sales team. Mandatory, if using entryType = MyIdEntryType.AUTH
`passportData` | Passport serial number or PINFL data | Optional
`dateOfBirth` | Date of birth in. Format: `dd.MM.yyyy` | Optional
`minAge` | To set a specific minimum age to use MyID service | 16
`sdkHash` | 32 characters long string (Note 1.2) | Optional
`externalId` | 36 characters long. Should match with UUID4 regex (Note 1.3) | Optional
`threshold` | The value can be in the range of `0.55` - `0.99` | 0.55
`buildMode` | Build mode (Note 1.4) | MyIdBuildMode.PRODUCTION
`entryType` | Customizing the SDK Entry types (Note 1.5) | MyIdEntryType.AUTH
`residency` | To set a specific resident type | MyIdResidentType.RESIDENT
`locale` | To set a specific locale | MyIdLocale.UZ
`cameraShape` | To set a specific camera shape (Note 1.6) | MyIdCameraShape.CIRCLE
`resolution` | To set a specific camera resolution | MyIdResolution.RESOLUTION_480
`withPhoto` | Return SDK face image | false
**Note 1.1.** You can customize the screen for entering passport data and date of birth in your
application, in which case you can pass these parameters during initialization to the SDK, otherwise
the SDK requires the input of passport data and date of birth for user identification.
**Note 1.2.** If the `sdkHash` is empty, blank or string with length other than 32 has been
provided, we will continue showing the credentials screen.
**Note 1.3.** If the `externalId` is not empty, has a length of 36 characters and corresponds to the
regular expression UUID4, we will display a [recommendation](images/screen01.jpg) screen in case the
sdk detects a blurry photo.
**Note 1.4.** `MyIdBuildMode` contains **DEBUG** and **PRODUCTION** modes.
- **DEBUG** is used to sandbox.
- **PRODUCTION** is used to production.
**Note 1.5.** `MyIdEntryType` contains **AUTH** and **FACE** types.
- **AUTH** is used to identify the user through the MyID services.
- **FACE** is used to detect a face and returns a picture (bitmap).
**Note 1.6.** `MyIdCameraShape` contains **[CIRCLE](images/screen03.jpg)**
and **[ELLIPSE](images/screen04.jpg)** types.
### 2.2 MyIdClientDelegate
```swift
extension ViewController: MyIdClientDelegate {
func onSuccess(result: MyIdResult) {
// Get face bitmap and result code
if let code = result.code {
print(code)
}
if let image = result.image {
print(img)
}
}
func onError(exception: MyIdException) {
// Get error message and code
print(exception.code)
print(exception.message)
}
func onUserExited() {
// User left the SDK
}
}
```
| Method | Notes |
| -----|-------|
| `onSuccess` | `MyIdResult` contains information about the face captures made during the flow, result code and comparison value. |
| `onError` | Some error happened. `MyIdException` contains information about the error message and code |
| `onUserExited` | User left the SDK flow without completing it. |
## SDK error codes
The error code in the following list may appear during the call of SDK. The list below is for your
reference.
| Code | Error message
|:----------:|:-------------
| 2 | Паспортные данные введены неправильно
| 3 | Не удалось подтвердить жизненность
| 4 | Не удалось распознать
| 5 | Внешний сервис недоступен или работает некорректно
| 6 | Запрашиваемый пользовател скончался
| 7 | Фото с ресурсов не получено
| 8 | Внутренняя ошибка MyID
| 9 | Срок выполнения задачи истек
| 10 | Срок ожидания задачи в очереди истек
| 11 | Сервис MyID не может обработать запрос. Попробуйте повторить позже
| 12 | Сервис MyID не может обработать запрос. Попробуйте повторить позже
| 13 | Сервис MyID не может обработать запрос. Попробуйте повторить позже
| 14 | Не удалось подтвердить жизненность. Некорректная фотография
| 15 | Сервис MyID не может обработать запрос. Попробуйте повторить позже
| 16 | Сервис MyID не может обработать запрос. Попробуйте повторить позже
| 17 | Не удалось распознать. Некорректная фотография
| 18 | Сервис проверки жизненности не может обработать запрос
| 19 | Сервис распознования не может обработать запрос
| 20 | Размытая фотография
| 21 | Лицо не полностью изображено
| 22 | Обнаружено несколько лиц
| 23 | Представленное изображение в градациях серого, требуется цветное изображение
| 24 | Обнаружены затемненные очки
| 25 | Тип фотографии не поддерживается
| 26 | Глаза закрыты либо не видны
| 101 | Непредвиденная ошибка
| 102 | Доступ к камере запрещен
| 103 | Ошибка при получении данных с сервера
| 120 | Размытое фото обнаружено в SDK
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment