add qr code reader on iOS

This commit is contained in:
turnoffthiscomputer
2024-07-23 18:37:39 +02:00
parent 911bfc80b7
commit f05aefa200
8 changed files with 148 additions and 8 deletions

View File

@@ -41,7 +41,8 @@ target 'ProofOfPassport' do
pod 'NFCPassportReader', git: 'https://github.com/0xturboblitz/NFCPassportReader.git', commit: '310ecb519655d9ed8b1afc5eb490b2f51a4d3595'
pod 'QKMRZScanner'
pod 'RNFS', :path => '../node_modules/react-native-fs'
pod 'lottie-ios'
pod 'lottie-ios'
pod 'SwiftQRScanner', :git => 'https://github.com/vinodiOS/SwiftQRScanner'
use_react_native!(
:path => config[:reactNativePath],
@@ -80,4 +81,4 @@ target 'ProofOfPassport' do
)
__apply_Xcode_12_5_M1_post_install_workaround(installer)
end
end
end

View File

@@ -292,10 +292,14 @@ PODS:
- React-jsinspector (0.72.3)
- React-logger (0.72.3):
- glog
- react-native-date-picker (5.0.4):
- React-Core
- react-native-get-random-values (1.11.0):
- React-Core
- react-native-netinfo (11.3.1):
- React-Core
- react-native-nfc-manager (3.15.1):
- React-Core
- React-NativeModulesApple (0.72.3):
- React-callinvoker
- React-Core
@@ -420,6 +424,7 @@ PODS:
- SSZipArchive (~> 2.2)
- SocketRocket (0.6.1)
- SSZipArchive (2.4.3)
- SwiftQRScanner (1.1.6)
- SwiftyTesseract (3.1.3)
- Yoga (1.14.0)
@@ -449,8 +454,10 @@ DEPENDENCIES:
- React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
- React-logger (from `../node_modules/react-native/ReactCommon/logger`)
- react-native-date-picker (from `../node_modules/react-native-date-picker`)
- react-native-get-random-values (from `../node_modules/react-native-get-random-values`)
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
- react-native-nfc-manager (from `../node_modules/react-native-nfc-manager`)
- 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`)
@@ -474,6 +481,7 @@ DEPENDENCIES:
- RNKeychain (from `../node_modules/react-native-keychain`)
- RNSVG (from `../node_modules/react-native-svg`)
- RNZipArchive (from `../node_modules/react-native-zip-archive`)
- SwiftQRScanner (from `https://github.com/vinodiOS/SwiftQRScanner`)
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
SPEC REPOS:
@@ -533,10 +541,14 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/jsinspector"
React-logger:
:path: "../node_modules/react-native/ReactCommon/logger"
react-native-date-picker:
:path: "../node_modules/react-native-date-picker"
react-native-get-random-values:
:path: "../node_modules/react-native-get-random-values"
react-native-netinfo:
:path: "../node_modules/@react-native-community/netinfo"
react-native-nfc-manager:
:path: "../node_modules/react-native-nfc-manager"
React-NativeModulesApple:
:path: "../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios"
React-perflogger:
@@ -583,6 +595,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-svg"
RNZipArchive:
:path: "../node_modules/react-native-zip-archive"
SwiftQRScanner:
:git: https://github.com/vinodiOS/SwiftQRScanner
Yoga:
:path: "../node_modules/react-native/ReactCommon/yoga"
@@ -590,6 +604,9 @@ CHECKOUT OPTIONS:
NFCPassportReader:
:commit: 310ecb519655d9ed8b1afc5eb490b2f51a4d3595
:git: https://github.com/0xturboblitz/NFCPassportReader.git
SwiftQRScanner:
:commit: fddcabcb431cd6110cea0394660082661dbafa7e
:git: https://github.com/vinodiOS/SwiftQRScanner
SPEC CHECKSUMS:
amplitude-react-native: 43098dfcfe1dcd6f0e9426017258ba79289d7a21
@@ -619,8 +636,10 @@ SPEC CHECKSUMS:
React-jsiexecutor: 2c15ba1bace70177492368d5180b564f165870fd
React-jsinspector: b511447170f561157547bc0bef3f169663860be7
React-logger: c5b527272d5f22eaa09bb3c3a690fee8f237ae95
react-native-date-picker: 6891317e850deae5b53d51355226e07a495aba61
react-native-get-random-values: 21325b2244dfa6b58878f51f9aa42821e7ba3d06
react-native-netinfo: bdb108d340cdb41875c9ced535977cac6d2ff321
react-native-nfc-manager: 3134770f9afcb586c0ae859e747fda3106ec1f76
React-NativeModulesApple: 1d8e4abb2fc6d80bdd13dcf128ee548804eb4a24
React-perflogger: 6bd153e776e6beed54c56b0847e1220a3ff92ba5
React-RCTActionSheet: c0b62af44e610e69d9a2049a682f5dba4e9dff17
@@ -646,9 +665,10 @@ SPEC CHECKSUMS:
RNZipArchive: ef9451b849c45a29509bf44e65b788829ab07801
SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17
SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef
SwiftQRScanner: e85a25f9b843e9231dab89a96e441472fe54a724
SwiftyTesseract: 1f3d96668ae92dc2208d9842c8a59bea9fad2cbb
Yoga: 8796b55dba14d7004f980b54bcc9833ee45b28ce
PODFILE CHECKSUM: 0d076339cbbbe7ad7559e35aae50e0036863e47e
PODFILE CHECKSUM: ed2a230fe418418ecb7e6525cb769af59fc9dae2
COCOAPODS: 1.15.2

View File

@@ -27,6 +27,9 @@
165E76BF2B8DC53A0000FA90 /* MRZScannerModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 165E76BE2B8DC53A0000FA90 /* MRZScannerModule.m */; };
165E76C32B8DC8370000FA90 /* ScannerHostingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 165E76C22B8DC8370000FA90 /* ScannerHostingController.swift */; };
1686F0DA2C4EA0F600841CDE /* passport.json in Resources */ = {isa = PBXBuildFile; fileRef = 1686F0D92C4EA0F600841CDE /* passport.json */; };
1686F0DC2C500F3800841CDE /* QRScannerBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1686F0DB2C500F3800841CDE /* QRScannerBridge.swift */; };
1686F0DE2C500F4F00841CDE /* QRScannerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1686F0DD2C500F4F00841CDE /* QRScannerViewController.swift */; };
1686F0E02C500FBD00841CDE /* QRScannerBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 1686F0DF2C500FBD00841CDE /* QRScannerBridge.m */; };
16E0838A2C4E7AF100CE8DB2 /* LottieView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16E083892C4E7AF100CE8DB2 /* LottieView.swift */; };
16E6646E2B8D292500FDD6A0 /* QKMRZScannerViewRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16E6646D2B8D292500FDD6A0 /* QKMRZScannerViewRepresentable.swift */; };
1BA25F26C91C45F697D55099 /* Inter-ExtraLight.otf in Resources */ = {isa = PBXBuildFile; fileRef = 568162F4DC4B4CDC8B341853 /* Inter-ExtraLight.otf */; };
@@ -93,6 +96,9 @@
165E76BE2B8DC53A0000FA90 /* MRZScannerModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MRZScannerModule.m; sourceTree = "<group>"; };
165E76C22B8DC8370000FA90 /* ScannerHostingController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScannerHostingController.swift; sourceTree = "<group>"; };
1686F0D92C4EA0F600841CDE /* passport.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = passport.json; path = ../../../FreedomTool/FreedomTools/Resources/Animations/passport.json; sourceTree = "<group>"; };
1686F0DB2C500F3800841CDE /* QRScannerBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRScannerBridge.swift; sourceTree = "<group>"; };
1686F0DD2C500F4F00841CDE /* QRScannerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRScannerViewController.swift; sourceTree = "<group>"; };
1686F0DF2C500FBD00841CDE /* QRScannerBridge.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = QRScannerBridge.m; sourceTree = "<group>"; };
16E083892C4E7AF100CE8DB2 /* LottieView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LottieView.swift; sourceTree = "<group>"; };
16E6646D2B8D292500FDD6A0 /* QKMRZScannerViewRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QKMRZScannerViewRepresentable.swift; sourceTree = "<group>"; };
1CA9D245CD5A439D88F01D4F /* Inter-ThinItalic.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Inter-ThinItalic.otf"; path = "../node_modules/@tamagui/font-inter/otf/Inter-ThinItalic.otf"; sourceTree = "<group>"; };
@@ -182,6 +188,9 @@
165E76BC2B8DC4A00000FA90 /* MRZScannerModule.swift */,
165E76BE2B8DC53A0000FA90 /* MRZScannerModule.m */,
16E6646D2B8D292500FDD6A0 /* QKMRZScannerViewRepresentable.swift */,
1686F0DB2C500F3800841CDE /* QRScannerBridge.swift */,
1686F0DF2C500FBD00841CDE /* QRScannerBridge.m */,
1686F0DD2C500F4F00841CDE /* QRScannerViewController.swift */,
);
name = ProofOfPassport;
sourceTree = "<group>";
@@ -530,7 +539,10 @@
buildActionMask = 2147483647;
files = (
13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */,
1686F0DE2C500F4F00841CDE /* QRScannerViewController.swift in Sources */,
1686F0E02C500FBD00841CDE /* QRScannerBridge.m in Sources */,
05EDEDC72B52D25D00AA51AD /* Prover.swift in Sources */,
1686F0DC2C500F3800841CDE /* QRScannerBridge.swift in Sources */,
13B07FC11A68108700A75B9A /* main.m in Sources */,
905B70072A72774000AFA232 /* PassportReader.m in Sources */,
16E6646E2B8D292500FDD6A0 /* QKMRZScannerViewRepresentable.swift in Sources */,

View File

@@ -1,6 +1,8 @@
#import "AppDelegate.h"
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <React/RCTBridge.h>
@implementation AppDelegate
@@ -23,4 +25,4 @@
#endif
}
@end
@end

15
app/ios/QRScannerBridge.m Normal file
View File

@@ -0,0 +1,15 @@
//
// QRScannerBridge.m
// ProofOfPassport
//
// Created by Rémi Colin on 23/07/2024.
//
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
@interface RCT_EXTERN_MODULE(QRScannerBridge, NSObject)
RCT_EXTERN_METHOD(scanQRCode:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
@end

View File

@@ -0,0 +1,30 @@
//
// QRScannerBridge.swift
// ProofOfPassport
//
// Created by Rémi Colin on 23/07/2024.
//
import Foundation
import SwiftQRScanner
import React
@objc(QRScannerBridge)
class QRScannerBridge: NSObject {
@objc
static func requiresMainQueueSetup() -> Bool {
return false
}
@objc
func scanQRCode(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
DispatchQueue.main.async {
let rootViewController = UIApplication.shared.keyWindow?.rootViewController
let qrScannerViewController = QRScannerViewController()
qrScannerViewController.completionHandler = { result in
resolve(result)
}
rootViewController?.present(qrScannerViewController, animated: true, completion: nil)
}
}
}

View File

@@ -0,0 +1,45 @@
//
// QRScannerViewController.swift
// ProofOfPassport
//
// Created by Rémi Colin on 23/07/2024.
//
import Foundation
import UIKit
import SwiftQRScanner
class QRScannerViewController: UIViewController, QRScannerCodeDelegate {
var completionHandler: ((String) -> Void)?
override func viewDidLoad() {
super.viewDidLoad()
var configuration = QRScannerConfiguration()
configuration.cameraImage = UIImage(named: "camera")
configuration.flashOnImage = UIImage(named: "flash-on")
configuration.galleryImage = UIImage(named: "photos")
let scanner = QRCodeScannerController(qrScannerConfiguration: configuration)
scanner.delegate = self
addChild(scanner)
view.addSubview(scanner.view)
scanner.view.frame = view.bounds
scanner.didMove(toParent: self)
}
func qrScanner(_ controller: UIViewController, didScanQRCodeWithResult result: String) {
completionHandler?(result)
dismiss(animated: true, completion: nil)
}
func qrScanner(_ controller: UIViewController, didFailWithError error: QRCodeError) {
print("QR Scanner Error: \(error.localizedDescription)")
dismiss(animated: true, completion: nil)
}
func qrScannerDidCancel(_ controller: UIViewController) {
dismiss(animated: true, completion: nil)
}
}

View File

@@ -13,13 +13,14 @@ import { BadgeCheck, Binary, LockKeyhole, QrCode, ShieldCheck, Smartphone, UserP
import { bgBlue, bgGreen, separatorColor, textBlack } from '../utils/colors';
import { orange } from '@tamagui/colors';
import useUserStore from '../stores/userStore';
import { NativeModules } from 'react-native';
const AppScreen: React.FC = () => {
const {
selectedApp,
update,
selectedTab,
setSelectedTab
setSelectedTab,
toast
} = useNavigationStore();
const {
@@ -110,7 +111,21 @@ const AppScreen: React.FC = () => {
<XStack f={1} minHeight="$1" />
{registered ? <CustomButton text="Scan QR code" onPress={() => setRegistered(false)} Icon={<QrCode size={18} color={textBlack} />} /> :
<CustomButton text="Register" onPress={() => { setSelectedTab("start"); setRegistered(true); }} Icon={<UserPlus size={18} color={textBlack} />} />}
<CustomButton text="Scan QR Code" onPress={() => {
NativeModules.QRScannerBridge.scanQRCode()
.then((result: string) => {
toast.show('QR Code result', {
message: result,
customData: {
type: "success",
},
});
// Handle the scanned QR code result here
})
.catch((error: any) => {
console.error('QR Scanner Error:', error);
});
}} Icon={<QrCode size={18} color={textBlack} />} />}
{/* <YStack my="$8" gap="$5" px="$5" jc="center" alignItems='center'>
{
cardsData.map(app => (
@@ -132,4 +147,4 @@ const AppScreen: React.FC = () => {
);
}
export default AppScreen;
export default AppScreen;