Commit 9d97b218 authored by Javokhir's avatar Javokhir
Browse files

chore: replace demo app with react-native library scaffold

Repo becomes the myid-sdk npm package: library at root, RN 0.86.2 vanilla
example app in example/, Turbo Module codegen enabled, yarn 4 workspace.

The previous demo app targeted MyID SDK 2.x (clientId, withPassportData,
MyIdBuildMode), an API that no longer exists in 3.x, so it is removed rather
than migrated. Recoverable via the pre-rewrite tag.
parent 6511c69e
{
"name": "myid-sdk-example",
"version": "0.0.1",
"private": true,
"scripts": {
"android": "react-native run-android",
"ios": "react-native run-ios",
"start": "react-native start",
"build:android": "react-native build-android --extra-params \"--no-daemon --console=plain -PreactNativeArchitectures=arm64-v8a\"",
"build:ios": "react-native build-ios --mode Debug"
},
"dependencies": {
"react": "19.2.3",
"react-native": "0.86.2"
},
"devDependencies": {
"@babel/core": "^7.25.2",
"@babel/preset-env": "^7.25.3",
"@babel/runtime": "^7.25.0",
"@react-native-community/cli": "20.1.0",
"@react-native-community/cli-platform-android": "20.1.0",
"@react-native-community/cli-platform-ios": "20.1.0",
"@react-native/babel-preset": "0.86.2",
"@react-native/jest-preset": "0.86.2",
"@react-native/metro-config": "0.86.2",
"@react-native/typescript-config": "0.86.2",
"@types/react": "^19.2.0",
"react-native-builder-bob": "^0.43.1",
"react-native-monorepo-config": "^0.4.0"
},
"engines": {
"node": ">= 22.11.0"
}
}
const path = require('path');
const pkg = require('../package.json');
module.exports = {
project: {
ios: {
automaticPodsInstallation: true,
},
},
dependencies: {
[pkg.name]: {
root: path.join(__dirname, '..'),
platforms: {
// Codegen script incorrectly fails without this
// So we explicitly specify the platforms with empty object
ios: {},
android: {},
},
},
},
};
import { Text, View, StyleSheet } from 'react-native';
import { multiply } from 'myid-sdk';
const result = multiply(3, 7);
export default function App() {
return (
<View style={styles.container}>
<Text>Result: {result}</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
/**
* @format
*/
import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';
AppRegistry.registerComponent(appName, () => App);
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:MyID.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>
<?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>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
#import <RCTAppDelegate.h>
#import <UIKit/UIKit.h>
@interface AppDelegate : RCTAppDelegate
@end
#import "AppDelegate.h"
#import <React/RCTBundleURLProvider.h>
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.moduleName = @"MyID";
// You can add your custom initial props in the dictionary below.
// They will be passed down to the ViewController used by React Native.
self.initialProps = @{};
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
return [self bundleURL];
}
- (NSURL *)bundleURL
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
#else
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}
@end
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char *argv[])
{
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
<?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>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
#import <React/RCTLog.h>
#import <React/RCTRootView.h>
#define TIMEOUT_SECONDS 600
#define TEXT_TO_LOOK_FOR @"Welcome to React"
@interface MyIDTests : XCTestCase
@end
@implementation MyIDTests
- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL (^)(UIView *view))test
{
if (test(view)) {
return YES;
}
for (UIView *subview in [view subviews]) {
if ([self findSubviewInView:subview matching:test]) {
return YES;
}
}
return NO;
}
- (void)testRendersWelcomeScreen
{
UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController];
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
BOOL foundElement = NO;
__block NSString *redboxError = nil;
#ifdef DEBUG
RCTSetLogFunction(
^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
if (level >= RCTLogLevelError) {
redboxError = message;
}
});
#endif
while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
[[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
[[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
foundElement = [self findSubviewInView:vc.view
matching:^BOOL(UIView *view) {
if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
return YES;
}
return NO;
}];
}
#ifdef DEBUG
RCTSetLogFunction(RCTDefaultLogFunction);
#endif
XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
}
@end
//
// MyIdModule.m
// MyID
//
// Created by Kamronbek Juraev on 23/07/24.
//
#import <Foundation/Foundation.h>
#import "React/RCTBridgeModule.h"
#import "React/RCTEventEmitter.h"
@interface RCT_EXTERN_MODULE(MyIdModule, RCTEventEmitter)
//RCT_EXTERN_METHOD(startMyId)
RCT_EXTERN_METHOD(startMyId:(NSString *)clientId
clientHash:(NSString *)clientHash
clientHashId:(NSString *)clientHashId
passportData:(NSString *)passportData
dateOfBirth:(NSString *)dateOfBirth
buildMode:(NSString *)buildMode)
@end
// @interface MyIdModule : RCTEventEmitter <RCTBridgeModule>
// @end
//
// MyIdModule.swift
// MyID
//
// Created by Kamronbek Juraev on 23/07/24.
//
import Foundation
import React
import MyIdSDK
@objc(MyIdModule)
class MyIdModule: RCTEventEmitter {
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
}()
@objc
static func constantsToExport() -> [String: Any] {
return ["initialCount": 0]
}
@objc
override static func requiresMainQueueSetup() -> Bool {
return true
}
@objc
override func supportedEvents() -> [String]! {
return ["onSuccess", "onError", "onUserExited"]
}
@objc(startMyId:clientHash:clientHashId:passportData:dateOfBirth:buildMode:)
func startMyId(clientId: String, clientHash: String, clientHashId: String, passportData: String, dateOfBirth: String, buildMode: String) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
let config = MyIdConfig()
config.clientId = clientId
config.clientHash = clientHash
config.clientHashId = clientHashId
config.passportData = passportData
config.dateOfBirth = dateOfBirth
let mode = buildMode == "PRODUCTION" ? MyIdBuildMode.PRODUCTION : MyIdBuildMode.DEBUG
config.buildMode = mode
config.withPhoto = true
config.entryType = MyIdEntryType.FACE
MyIdClient.start(withConfig: config, withDelegate: self)
}
}
}
extension MyIdModule: MyIdClientDelegate {
func onSuccess(result: MyIdSDK.MyIdResult) {
// Assuming `result.image` is a UIImage
if let image = result.image {
if let imageData = image.jpegData(compressionQuality: 1) { // Compression quality can be adjusted
let base64String = imageData.base64EncodedString(options: .lineLength64Characters)
sendEvent(withName: "onSuccess", body: ["code": result.code, "comparison": result.comparisonValue, "image": base64String])
} else {
// Handle failure to get image data
sendEvent(withName: "onError", body: ["message": "Failed to convert image to Data", "code": 0])
}
} else {
// Handle the case where there is no image
sendEvent(withName: "onError", body: ["message": "No image available", "code": 0])
}
}
func onError(exception: MyIdSDK.MyIdException) {
sendEvent(
withName: "onError",
body: [
"message": exception.message,
"code": exception.code
]
)
}
func onUserExited() {
sendEvent(
withName: "onUserExited",
body: [
"message": "exited"
]
)
}
}
#import <MyidSdkSpec/MyidSdkSpec.h>
@interface MyidSdk : NSObject <NativeMyidSdkSpec>
@end
#import "MyidSdk.h"
@implementation MyidSdk
- (NSNumber *)multiply:(double)a b:(double)b {
NSNumber *result = @(a * b);
return result;
}
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
(const facebook::react::ObjCTurboModule::InitParams &)params
{
return std::make_shared<facebook::react::NativeMyidSdkSpecJSI>(params);
}
+ (NSString *)moduleName
{
return @"MyidSdk";
}
@end
This diff is collapsed.
const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
/**
* Metro configuration
* https://reactnative.dev/docs/metro
*
* @type {import('metro-config').MetroConfig}
*/
const config = {};
module.exports = mergeConfig(getDefaultConfig(__dirname), config);
{
"name": "MyID",
"version": "0.0.1",
"private": true,
"name": "myid-sdk",
"version": "0.1.0",
"description": "React Native wrapper for the MyID identity verification SDK",
"main": "./lib/module/index.js",
"types": "./lib/typescript/src/index.d.ts",
"exports": {
".": {
"myid-sdk-source": "./src/index.tsx",
"types": "./lib/typescript/src/index.d.ts",
"default": "./lib/module/index.js"
},
"./package.json": "./package.json"
},
"files": [
"src",
"lib",
"android",
"ios",
"cpp",
"*.podspec",
"react-native.config.js",
"!ios/build",
"!android/build",
"!android/gradle",
"!android/gradlew",
"!android/gradlew.bat",
"!android/local.properties",
"!**/__tests__",
"!**/__fixtures__",
"!**/__mocks__",
"!**/.*"
],
"scripts": {
"android": "react-native run-android",
"ios": "react-native run-ios",
"lint": "eslint .",
"start": "react-native start",
"ios:pod:reset": "cd ios && pod deintegrate && pod setup && pod install --verbose && cd ..",
"test": "jest",
"adb": "adb reverse tcp:8081 tcp:8081"
},
"dependencies": {
"react": "18.2.0",
"react-native": "0.74.3"
"example": "yarn workspace myid-sdk-example",
"clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib",
"prepare": "bob build",
"typecheck": "tsc",
"lint": "eslint \"**/*.{js,ts,tsx}\""
},
"keywords": [
"react-native",
"ios",
"android"
],
"repository": {
"type": "git",
"url": "git+https://gitlab.aigroup.uz/myid-public-code/myid-rn-sdk.git"
},
"author": "MyID <javokhirdev@gmail.com> (https://myid.uz)",
"license": "MIT",
"bugs": {
"url": "https://gitlab.aigroup.uz/myid-public-code/myid-rn-sdk/issues"
},
"homepage": "https://gitlab.aigroup.uz/myid-public-code/myid-rn-sdk#readme",
"publishConfig": {
"registry": "https://registry.npmjs.org/"
},
"devDependencies": {
"@babel/core": "^7.20.0",
"@babel/preset-env": "^7.20.0",
"@babel/runtime": "^7.20.0",
"@react-native/babel-preset": "0.74.85",
"@react-native/eslint-config": "0.74.85",
"@react-native/metro-config": "0.74.85",
"@react-native/typescript-config": "0.74.85",
"@types/react": "^18.2.6",
"@types/react-test-renderer": "^18.0.0",
"babel-jest": "^29.6.3",
"eslint": "^8.19.0",
"jest": "^29.6.3",
"prettier": "2.8.8",
"react-test-renderer": "18.2.0",
"typescript": "5.0.4"
},
"engines": {
"node": ">=18"
},
"packageManager": "yarn@3.6.4"
"@eslint/compat": "^2.1.0",
"@eslint/eslintrc": "^3.3.6",
"@eslint/js": "^9.39.5",
"@react-native/babel-preset": "0.86.2",
"@react-native/eslint-config": "0.86.2",
"@types/react": "^19.2.0",
"del-cli": "^7.0.0",
"eslint": "^9.39.5",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-ft-flow": "^3.0.11",
"eslint-plugin-prettier": "^5.5.6",
"prettier": "^3.9.6",
"react": "19.2.3",
"react-native": "0.86.2",
"react-native-builder-bob": "^0.43.1",
"turbo": "^2.10.8",
"typescript": "^6.0.3"
},
"peerDependencies": {
"react": "*",
"react-native": "*"
},
"workspaces": [
"example"
],
"packageManager": "yarn@4.11.0",
"react-native-builder-bob": {
"source": "src",
"output": "lib",
"targets": [
[
"module",
{
"esm": true
}
],
[
"typescript",
{
"project": "tsconfig.build.json"
}
]
]
},
"codegenConfig": {
"name": "MyidSdkSpec",
"type": "modules",
"jsSrcsDir": "src",
"android": {
"javaPackageName": "com.myidsdk"
}
},
"prettier": {
"quoteProps": "consistent",
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"useTabs": false
},
"create-react-native-library": {
"type": "turbo-module",
"languages": "kotlin-objc",
"tools": [
"eslint"
],
"version": "0.63.1"
}
}
import { TurboModuleRegistry, type TurboModule } from 'react-native';
export interface Spec extends TurboModule {
multiply(a: number, b: number): number;
}
export default TurboModuleRegistry.getEnforcing<Spec>('MyidSdk');
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