# myid-sdk React Native wrapper for the [MyID](https://myid.uz) identity verification SDK. Wraps MyID Android `3.1.9` and iOS `3.1.3` behind one promise-based API. ```ts const result = await start({ config: { sessionId, clientHash, clientHashId }, }); ``` ## Requirements | | | |---|---| | React Native | New Architecture enabled (`newArchEnabled=true`, the default since 0.76). Verified against 0.86.2. | | Android | `minSdkVersion` 24+, `compileSdk` 36 | | iOS | Deployment target 15.1+ (RN 0.86's floor; the MyID SDK itself needs 13.0) | `sessionId` is issued by **your backend** through the MyID API. This library never talks to the MyID backend itself — it only launches the SDK. ## Installation ```sh npm install myid-sdk # or yarn add myid-sdk ``` ### iOS ```sh cd ios && pod install ``` Add a camera usage description to `ios//Info.plist` — the app is rejected at review without it, and the SDK cannot capture a face: ```xml NSCameraUsageDescription Camera is used to verify your identity. ``` ### Android No Gradle changes are needed in the common case. MyID artifacts are not on Maven Central, so this library registers the two required repositories (`artifactory.aigroup.uz` for the SDK, `developer.huawei.com` for the Huawei integrity dependency) on all projects. Both are publicly readable — no credentials, no tokens. See [Android troubleshooting](#android-troubleshooting) if your app manages repositories centrally or defines custom build types. ## Usage ```tsx import { start, isMyIdError, MyIdErrorCode } from 'myid-sdk'; async function verify() { try { const result = await start({ config: { sessionId, // from your backend clientHash, // from the MyID sales team clientHashId, environment: 'PRODUCTION', locale: 'UZBEK', }, iosAppearance: { colorPrimary: '#2F6FED', buttonCornerRadius: 12, }, }); // result.code === '100' on success // result.base64 is a base64 JPEG portrait, without a data-URI prefix return result; } catch (error) { if (isMyIdError(error) && error.code === MyIdErrorCode.USER_CANCELLED) { return null; // user backed out — usually not worth surfacing } throw error; } } ``` `start()` rejects for **every** non-success path, including the user simply dismissing the flow. Always handle `101`. ## Configuration Only `sessionId`, `clientHash` and `clientHashId` are required. Every omitted option keeps the SDK's own default — this library never substitutes one of its own. Options not supported by a platform are ignored there rather than throwing. | Option | Values | Default | Platform | |---|---|---|---| | `sessionId` | string | — | both | | `clientHash` | string | — | both | | `clientHashId` | string | — | both | | `minAge` | number | `16` | both | | `distance` | number (0..1) | `0.65` circle / `0.6` ellipse | both | | `residency` | `USER_DEFINED` `RESIDENT` `NON_RESIDENT` | `RESIDENT` | both | | `environment` | `PRODUCTION` `DEBUG` | `PRODUCTION` | both | | `entryType` | `IDENTIFICATION` `VIDEO_IDENTIFICATION` `FACE_DETECTION` | `IDENTIFICATION` | both | | `locale` | `UZBEK` `UZBEK_CYRILLIC` `KARAKALPAK` `TAJIK` `ENGLISH` `RUSSIAN` | `UZBEK` | see note | | `cameraShape` | `CIRCLE` `ELLIPSE` | `CIRCLE` | both | | `cameraSelector` | `FRONT` `BACK` | `FRONT` | both | | `cameraResolution` | `LOW` `HIGH` | `LOW` | android | | `imageFormat` | `JPEG` `PNG` | `JPEG` | android | | `screenOrientation` | `PORTRAIT` `LANDSCAPE` `FULL` | `PORTRAIT` | android | | `withSoundGuides` | boolean | `true` | android | | `huaweiAppId` | string | — | android | | `presentationStyle` | `SHEET` `FULL` | `FULL` | ios | | `showErrorScreen` | boolean | `true` | both | | `organizationDetails` | `{ phone, logo }` | — | both | **Locale note.** iOS supports only `UZBEK`, `ENGLISH` and `RUSSIAN`. `UZBEK_CYRILLIC`, `KARAKALPAK` and `TAJIK` fall back to `UZBEK` there. **`VIDEO_IDENTIFICATION`** is marked experimental by the Android SDK. Treat it as unstable. **`organizationDetails.logo`** is the name of a *native* asset — an Android drawable or an iOS image set — not a path, URL or `require()`. It should fit roughly 240x60. `phone` replaces MyID's call-centre number on the error screen. The SDK replaces the whole details object rather than merging it, so passing `organizationDetails` with only a `logo` clears the default call-centre number (`712022202`). Pass `phone` alongside `logo` if a number should still appear. ## Theming iOS theming is runtime, via `iosAppearance`: `colorPrimary`, `colorOnPrimary`, `colorError`, `colorOnError`, `colorOutline`, `colorDivider`, `colorSuccess`, `colorButtonContainer`, `colorButtonContainerDisabled`, `colorButtonContent`, `colorButtonContentDisabled`, `colorScanButtonContainer` (all `#RRGGBB` or `RRGGBB`), plus `buttonCornerRadius`. Android theming is **not** runtime — the Android SDK is themed by overriding its resources. Declare the same names in your app to replace them: ```xml #2F6FED ``` `iosAppearance` is ignored on Android. ## Error codes Rejections are `MyIdError` with a string `code`. | Code | Meaning | |---|---| | `100` | Success (returned as `result.code`, not an error) | | `101` | User cancelled the flow | | `102` | Camera permission denied | | `103` | SDK, server or wrapper failure | | `122` | User banned | The SDK also emits liveness advice codes (`3`, `14`, `20`–`28`). Compare against `error.code` directly rather than assuming the list above is exhaustive — see the [MyID error code docs](https://docs.myid.uz/#/ru/embedded?id=javob-kodlar-uz-result_code). ```ts import { MyIdError, isMyIdError, MyIdErrorCode } from 'myid-sdk'; ``` ## Android troubleshooting **The app defines build types other than `debug`/`release`.** This library ships a non-obfuscated debug artifact and an obfuscated release one, wired per build type. Custom build types fail to resolve unless they declare a fallback: ```gradle buildTypes { staging { initWith release matchingFallbacks = ["release"] } } ``` **The app manages repositories centrally.** If your `settings.gradle` sets `repositoriesMode = FAIL_ON_PROJECT_REPOS`, this library's repository registration will be rejected. Opt out and declare them yourself: ```properties # android/gradle.properties myIdSkipRepositoryInjection=true ``` ```gradle // android/settings.gradle dependencyResolutionManagement { repositories { maven { url "https://artifactory.aigroup.uz/artifactory/myid/" } maven { url "https://developer.huawei.com/repo/" } } } ``` **The screen never returns and every later call rejects with `103`.** In a brownfield app that hosts React Native inside your own activity or fragment, the host must forward `onActivityResult` to React (`ReactActivityDelegate.onActivityResult` / `ReactInstanceManager.onActivityResult`). Without it the result never arrives, the first `start()` hangs forever, and every subsequent call rejects with "already in progress" for the rest of the session. Apps using the standard `ReactActivity` get this for free. **The app crashes on an emulator.** The MyID SDK ships native libraries for `arm64-v8a` and `armeabi-v7a` only. On an x86/x86_64 emulator the app installs but crashes when the SDK loads its native library. Test on a physical device or an arm64 emulator image. **Pinning a different SDK version.** ```gradle // android/build.gradle ext { myIdCaptureSdkVersion = "3.1.9" } ``` **Huawei devices.** Devices without Google Play Services need a Huawei App ID. The integrity dependency is already included transitively — pass `huaweiAppId` and add the App ID from AppGallery Connect to your manifest: ```xml ``` ## iOS troubleshooting **`use_frameworks!`.** `MyIdSDK` is distributed as a binary XCFramework and works under both static and dynamic linkage. **The SDK does not appear.** It presents from the key window's root view controller. If your app already has a modal presented, dismiss it before calling `start()`. ## Example The `example/` app in this repository is a runnable demo. Credentials are typed in at runtime rather than committed. ```sh yarn yarn example ios # or: yarn example android ``` ## License MIT