Skip to content
This repository was archived by the owner on Jun 26, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,5 @@ buck-out/

# General
.env

/resources/html/*.html
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ npm install

Once all dependencies are installed and your target development environments are setup (Xcode for iOS and Android Studio for Android), it should be possible to begin development with virtual devices.

Before starting the application, make sure to build required HTML file for Camera QR Webview with the following command:
```shell
npm run build:webview
```

**Important note about Node.js support**: Development for this project should be performed on Node version 8. Although it may work on versions 6 and newer, we will not be supporting issues raised for these versions. Similarly, we do not currently support NodeJS version 9.

### iOS development
Expand Down
3 changes: 3 additions & 0 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ android {
}
}
}
sourceSets {
main { assets.srcDirs = ['../../resources/html'] }
}
}

dependencies {
Expand Down
1 change: 1 addition & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />

<application
android:name=".MainApplication"
Expand Down
10 changes: 8 additions & 2 deletions ios/Buttercup.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1001,7 +1001,10 @@
);
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
OTHER_CFLAGS = "$(inherited) ";
OTHER_CFLAGS = (
"$(inherited)",
" ",
);
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
"-DFOLLY_NO_CONFIG",
Expand Down Expand Up @@ -1075,7 +1078,10 @@
"\"$(inherited)\"",
);
MTL_ENABLE_DEBUG_INFO = NO;
OTHER_CFLAGS = "$(inherited) ";
OTHER_CFLAGS = (
"$(inherited)",
" ",
);
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
"-DFOLLY_NO_CONFIG",
Expand Down
46 changes: 26 additions & 20 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -323,9 +323,11 @@ PODS:
- React-Core
- react-native-randombytes (3.6.1):
- React-Core
- react-native-safe-area-context (4.9.0):
- react-native-safe-area-context (4.7.4):
- React-Core
- react-native-slider (4.5.2):
- react-native-slider (4.4.3):
- React-Core
- react-native-webview (13.8.7):
- RCT-Folly (= 2021.07.22.00)
- React-Core
- React-NativeModulesApple (0.72.7):
Expand Down Expand Up @@ -438,25 +440,25 @@ PODS:
- React-jsi (= 0.72.7)
- React-logger (= 0.72.7)
- React-perflogger (= 0.72.7)
- ReactNativeFileAccess (3.1.0):
- ReactNativeFileAccess (3.0.4):
- React-Core
- ZIPFoundation
- RNCAsyncStorage (1.23.1):
- ZIPFoundation (= 0.9.11)
- RNCAsyncStorage (1.21.0):
- React-Core
- RNCClipboard (1.14.0):
- RNCClipboard (1.12.1):
- React-Core
- RNCMaskedView (0.1.11):
- React
- RNFS (2.20.0):
- React-Core
- RNGestureHandler (2.16.0):
- RNGestureHandler (2.14.0):
- RCT-Folly (= 2021.07.22.00)
- React-Core
- RNReanimated (3.8.1):
- RNReanimated (3.6.1):
- RCT-Folly (= 2021.07.22.00)
- React-Core
- ReactCommon/turbomodule/core
- RNScreens (3.30.1):
- RNScreens (3.27.0):
- RCT-Folly (= 2021.07.22.00)
- React-Core
- RNSVG (13.14.0):
Expand All @@ -465,7 +467,7 @@ PODS:
- TouchID (4.4.1):
- React
- Yoga (1.14.0)
- ZIPFoundation (0.9.19)
- ZIPFoundation (0.9.11)

DEPENDENCIES:
- boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`)
Expand Down Expand Up @@ -496,6 +498,7 @@ DEPENDENCIES:
- react-native-randombytes (from `../node_modules/react-native-randombytes`)
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
- "react-native-slider (from `../node_modules/@react-native-community/slider`)"
- react-native-webview (from `../node_modules/react-native-webview`)
- React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`)
- React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`)
- React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`)
Expand Down Expand Up @@ -586,6 +589,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-safe-area-context"
react-native-slider:
:path: "../node_modules/@react-native-community/slider"
react-native-webview:
:path: "../node_modules/react-native-webview"
React-NativeModulesApple:
:path: "../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios"
React-perflogger:
Expand Down Expand Up @@ -670,8 +675,9 @@ SPEC CHECKSUMS:
react-native-config: 86038147314e2e6d10ea9972022aa171e6b1d4d8
react-native-encrypted-storage: db300a3f2f0aba1e818417c1c0a6be549038deb7
react-native-randombytes: 421f1c7d48c0af8dbcd471b0324393ebf8fe7846
react-native-safe-area-context: b97eb6f9e3b7f437806c2ce5983f479f8eb5de4b
react-native-slider: 593253eb5fbc6ea519290e812bd477fc6abafd5a
react-native-safe-area-context: 2cd91d532de12acdb0a9cbc8d43ac72a8e4c897c
react-native-slider: 1cdd6ba29675df21f30544253bf7351d3c2d68c4
react-native-webview: fb0df3f6551616ac5a7ccb2bc77aca451f58373d
React-NativeModulesApple: b6868ee904013a7923128892ee4a032498a1024a
React-perflogger: 31ea61077185eb1428baf60c0db6e2886f141a5a
React-RCTActionSheet: 392090a3abc8992eb269ef0eaa561750588fc39d
Expand All @@ -689,20 +695,20 @@ SPEC CHECKSUMS:
React-runtimescheduler: 7649c3b46c8dee1853691ecf60146a16ae59253c
React-utils: 56838edeaaf651220d1e53cd0b8934fb8ce68415
ReactCommon: 5f704096ccf7733b390f59043b6fa9cc180ee4f6
ReactNativeFileAccess: e3b1a0a36b919d20279947aac31c2e939827c93b
RNCAsyncStorage: 826b603ae9c0f88b5ac4e956801f755109fa4d5c
RNCClipboard: 090462274cc05b02628bd158baf6d73c3abe8441
ReactNativeFileAccess: 4530e3be4d5069454c6c6389096d8cb78c897f2c
RNCAsyncStorage: 618d03a5f52fbccb3d7010076bc54712844c18ef
RNCClipboard: d77213bfa269013bf4b857b7a9ca37ee062d8ef1
RNCMaskedView: 0e1bc4bfa8365eba5fbbb71e07fbdc0555249489
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
RNGestureHandler: 69d0a928253547ef857a7be4f453220b9c472e07
RNReanimated: f4798af7dede23d41039f0bc372710ead86e90c7
RNScreens: bb06f14b5c352e603f2527caac02ca0d6398c6e5
RNGestureHandler: 32a01c29ecc9bb0b5bf7bc0a33547f61b4dc2741
RNReanimated: fdbaa9c964bbab7fac50c90862b6cc5f041679b9
RNScreens: 3c2d122f5e08c192e254c510b212306da97d2581
RNSVG: d00c8f91c3cbf6d476451313a18f04d220d4f396
SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17
TouchID: ba4c656d849cceabc2e4eef722dea5e55959ecf4
Yoga: 4c3aa327e4a6a23eeacd71f61c81df1bcdf677d5
ZIPFoundation: b8c29ea7ae353b309bc810586181fd073cb3312c
ZIPFoundation: b1f0de4eed33e74a676f76e12559ab6b75990197

PODFILE CHECKSUM: a6a5f55271d0d7c13871c95c595d44709d4e4543
PODFILE CHECKSUM: f0fab618667c092fc1a5d112093097166d1e624b

COCOAPODS: 1.15.2
29 changes: 29 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"scripts": {
"android": "react-native run-android",
"build:ios": "react-native bundle --entry-file='index.js' --bundle-output='./ios/main.jsbundle' --dev=false --platform='ios'",
"build:webview": "node ./scripts/build_qrview.js",
"format": "prettier --write \"{{source,test}/**/*.{js,ts,jsx,tsx},*.{js,ts,jsx,tsx}}\"",
"ios": "react-native run-ios --simulator=\"iPhone Xs\"",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
Expand Down Expand Up @@ -70,6 +71,7 @@
"react-native-touch-id": "^4.4.1",
"react-native-url-polyfill": "^1.3.0",
"react-native-uuid": "^2.0.1",
"react-native-webview": "^13.8.4",
"react-obstate": "^0.1.3",
"stream-browserify": "^3.0.0",
"url-join": "^4.0.1",
Expand All @@ -95,6 +97,7 @@
"eslint": "^8.55.0",
"eslint-plugin-prettier": "^5.0.1",
"jest": "^29.2.1",
"jsqr": "^1.4.0",
"metro-react-native-babel-preset": "^0.77.0",
"prettier": "^3.1.0",
"react-native-svg-transformer": "^1.1.0",
Expand Down
Empty file added resources/html/.gitkeep
Empty file.
81 changes: 81 additions & 0 deletions scripts/QRScanner.template.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OTP Scanner</title>
<style>
* {
margin: 0;
padding: 0;
overflow: hidden;
}

main {
height: 100vh;
width: 100%;
border-radius: 15px;
}

#preview {
width: 100%;
height: 100%;
position: relative;
}

video {
width: 100%;
height: 100%;
object-fit: cover;

}
</style>
<script>
{ { jsQRScript } }
</script>
</head>

<body>
<main>
<div id="preview">
<video id="video" autoplay muted loop playsinline></video>
<canvas id="canvas" hidden></canvas>
</div>
</main>
<script>
const video = document.getElementById('video');
const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' } })
.then(function (stream) {
video.srcObject = stream;
video.play();
requestAnimationFrame(tick);
});
function tick() {
if (video.readyState === video.HAVE_ENOUGH_DATA) {
canvas.height = video.videoHeight;
canvas.width = video.videoWidth;

context.drawImage(video, 0, 0, canvas.width, canvas.height);

var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
var code = jsQR(imageData.data, imageData.width, imageData.height, {
inversionAttempts: "dontInvert",
});

if (code) {
console.log("Found QR code", code.data);
if (window.ReactNativeWebView) {
window.ReactNativeWebView.postMessage(code.data)
}
}
}

requestAnimationFrame(tick);
}
</script>
</body>

</html>
17 changes: 17 additions & 0 deletions scripts/build_qrview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const fs = require("fs");
const path = require("path");

const htmlPath = path.join(__dirname, "./QRScanner.template.html");

const qrViewPath = path.join(__dirname, "../resources/html/OTPScanner.html");

async function buildQrView() {
const jsqr = fs.readFileSync(require.resolve("jsqr/dist/jsQr.js"));
const html = fs.readFileSync(htmlPath, "utf8");

const qrView = html.replace("{ { jsQRScript } }", jsqr);

fs.writeFileSync(qrViewPath, qrView);
}

buildQrView();
Loading