qrdnicapacitor 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Package.swift +34 -0
- package/Qrdnicapacitor.podspec +18 -0
- package/README.md +106 -0
- package/android/build.gradle +64 -0
- package/android/src/main/AndroidManifest.xml +16 -0
- package/android/src/main/java/com/cqesolutions/qrdnicapacitor/QrCodeScanner.java +84 -0
- package/android/src/main/java/com/cqesolutions/qrdnicapacitor/jj2000/ImgStreamWriter.java +483 -0
- package/android/src/main/java/com/cqesolutions/qrdnicapacitor/jj2000/J2kStreamDecoder.java +116 -0
- package/android/src/main/java/com/cqesolutions/qrdnicapacitor/jj2000/MyFileFormatReader.java +204 -0
- package/android/src/main/java/com/cqesolutions/qrdnicapacitor/qrdni.java +130 -0
- package/android/src/main/java/com/cqesolutions/qrdnicapacitor/qrdniPlugin.java +109 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/dist/docs.json +255 -0
- package/dist/esm/definitions.d.ts +44 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web.d.ts +14 -0
- package/dist/esm/web.js +18 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +32 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +35 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Sources/qrdniPlugin/ScannerViewController.swift +170 -0
- package/ios/Sources/qrdniPlugin/qrdni.swift +111 -0
- package/ios/Sources/qrdniPlugin/qrdniPlugin.swift +105 -0
- package/ios/Tests/qrdniPluginTests/qrdniTests.swift +15 -0
- package/package.json +80 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export interface qrdniPlugin {
|
|
2
|
+
configure(options: {
|
|
3
|
+
license: string;
|
|
4
|
+
certs?: {
|
|
5
|
+
[key: string]: string;
|
|
6
|
+
};
|
|
7
|
+
}): Promise<EstadoLicencia>;
|
|
8
|
+
validaMiDNIQR(options: {
|
|
9
|
+
data: string;
|
|
10
|
+
}): Promise<MiDNIData>;
|
|
11
|
+
abrirEscaner(): Promise<any>;
|
|
12
|
+
}
|
|
13
|
+
export interface EstadoLicencia {
|
|
14
|
+
descripcion: string;
|
|
15
|
+
APIKeyValida: boolean;
|
|
16
|
+
lecturaQRHabilitada: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface MiDNIData {
|
|
19
|
+
dni: string;
|
|
20
|
+
name: string;
|
|
21
|
+
surnames: string;
|
|
22
|
+
birthDate: string;
|
|
23
|
+
expiryDate: string;
|
|
24
|
+
gender: string;
|
|
25
|
+
address: string;
|
|
26
|
+
nationality: string;
|
|
27
|
+
parents: string;
|
|
28
|
+
supportNumber: string;
|
|
29
|
+
birthPlace1: string;
|
|
30
|
+
birthPlace2: string;
|
|
31
|
+
birthPlace3: string;
|
|
32
|
+
photoData: string;
|
|
33
|
+
isAdult?: boolean;
|
|
34
|
+
rawSignature: string;
|
|
35
|
+
signedData: string;
|
|
36
|
+
certificateRef: string;
|
|
37
|
+
type?: number;
|
|
38
|
+
verificationResult: {
|
|
39
|
+
status: 'VALID' | 'INVALID' | 'NO_CERTIFICATES' | 'INVALID_QR' | 'EXPIRED_QR' | 'UNKNOWN';
|
|
40
|
+
certificate?: string;
|
|
41
|
+
};
|
|
42
|
+
qrDataExpiry: string;
|
|
43
|
+
fullBirthPlace: string;
|
|
44
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["export interface qrdniPlugin {\n configure(options: { license: string, certs?: { [key: string]: string } }): Promise<EstadoLicencia>;\n validaMiDNIQR(options: { data: string }): Promise<MiDNIData>;\n abrirEscaner(): Promise<any>;\n}\n\nexport interface EstadoLicencia {\n descripcion: string;\n APIKeyValida: boolean;\n lecturaQRHabilitada: boolean;\n}\n\nexport interface MiDNIData {\n dni: string;\n name: string;\n surnames: string;\n birthDate: string;\n expiryDate: string;\n gender: string;\n\n address: string;\n nationality: string;\n parents: string;\n supportNumber: string;\n \n birthPlace1: string;\n birthPlace2: string;\n birthPlace3: string;\n \n photoData: string; // Base64\n isAdult?: boolean;\n \n rawSignature: string;\n signedData: string;\n certificateRef: string;\n type?: number;\n verificationResult: {\n status: 'VALID' | 'INVALID' | 'NO_CERTIFICATES' | 'INVALID_QR' | 'EXPIRED_QR' | 'UNKNOWN';\n certificate?: string; // Solo presente si el status es VALID\n }; \n qrDataExpiry: string;\n\n fullBirthPlace: string;\n}"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,KAAK,GAAG,cAAc,CAAc,OAAO,EAAE;IACjD,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;CACzD,CAAC,CAAC;AAEH,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,KAAK,EAAE,CAAC","sourcesContent":["import { registerPlugin } from '@capacitor/core';\n\nimport type { qrdniPlugin } from './definitions';\n\nconst qrdni = registerPlugin<qrdniPlugin>('qrdni', {\n web: () => import('./web').then((m) => new m.qrdniWeb()),\n});\n\nexport * from './definitions';\nexport { qrdni };\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { WebPlugin } from '@capacitor/core';
|
|
2
|
+
import type { qrdniPlugin, EstadoLicencia, MiDNIData } from './definitions';
|
|
3
|
+
export declare class qrdniWeb extends WebPlugin implements qrdniPlugin {
|
|
4
|
+
abrirEscaner(): Promise<any>;
|
|
5
|
+
configure(options: {
|
|
6
|
+
license: string;
|
|
7
|
+
certs?: {
|
|
8
|
+
[key: string]: string;
|
|
9
|
+
};
|
|
10
|
+
}): Promise<EstadoLicencia>;
|
|
11
|
+
validaMiDNIQR(options: {
|
|
12
|
+
data: string;
|
|
13
|
+
}): Promise<MiDNIData>;
|
|
14
|
+
}
|
package/dist/esm/web.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { WebPlugin } from '@capacitor/core';
|
|
2
|
+
export class qrdniWeb extends WebPlugin {
|
|
3
|
+
abrirEscaner() {
|
|
4
|
+
console.log("NOT IMPLEMENTED");
|
|
5
|
+
throw new Error('Method not implemented.');
|
|
6
|
+
}
|
|
7
|
+
configure(options) {
|
|
8
|
+
console.log("NOT IMPLEMENTED");
|
|
9
|
+
console.log(options);
|
|
10
|
+
throw new Error('Method not implemented.');
|
|
11
|
+
}
|
|
12
|
+
validaMiDNIQR(options) {
|
|
13
|
+
console.log("NOT IMPLEMENTED");
|
|
14
|
+
console.log(options);
|
|
15
|
+
throw new Error('Method not implemented.');
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=web.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C,MAAM,OAAO,QAAS,SAAQ,SAAS;IACrC,YAAY;QACV,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IACD,SAAS,CAAC,OAAiE;QACzE,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;QAC/B,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IACD,aAAa,CAAC,OAA0B;QACtC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;QAC/B,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;CACF","sourcesContent":["import { WebPlugin } from '@capacitor/core';\n\nimport type { qrdniPlugin, EstadoLicencia, MiDNIData } from './definitions';\n\nexport class qrdniWeb extends WebPlugin implements qrdniPlugin {\n abrirEscaner(): Promise<any> {\n console.log(\"NOT IMPLEMENTED\");\n throw new Error('Method not implemented.');\n }\n configure(options: { license: string; certs?: { [key: string]: string; }; }): Promise<EstadoLicencia> {\n console.log(\"NOT IMPLEMENTED\");\n console.log(options);\n throw new Error('Method not implemented.');\n }\n validaMiDNIQR(options: { data: string; }): Promise<MiDNIData> {\n console.log(\"NOT IMPLEMENTED\");\n console.log(options);\n throw new Error('Method not implemented.');\n }\n}\n"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var core = require('@capacitor/core');
|
|
4
|
+
|
|
5
|
+
const qrdni = core.registerPlugin('qrdni', {
|
|
6
|
+
web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.qrdniWeb()),
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
class qrdniWeb extends core.WebPlugin {
|
|
10
|
+
abrirEscaner() {
|
|
11
|
+
console.log("NOT IMPLEMENTED");
|
|
12
|
+
throw new Error('Method not implemented.');
|
|
13
|
+
}
|
|
14
|
+
configure(options) {
|
|
15
|
+
console.log("NOT IMPLEMENTED");
|
|
16
|
+
console.log(options);
|
|
17
|
+
throw new Error('Method not implemented.');
|
|
18
|
+
}
|
|
19
|
+
validaMiDNIQR(options) {
|
|
20
|
+
console.log("NOT IMPLEMENTED");
|
|
21
|
+
console.log(options);
|
|
22
|
+
throw new Error('Method not implemented.');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
var web = /*#__PURE__*/Object.freeze({
|
|
27
|
+
__proto__: null,
|
|
28
|
+
qrdniWeb: qrdniWeb
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
exports.qrdni = qrdni;
|
|
32
|
+
//# sourceMappingURL=plugin.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst qrdni = registerPlugin('qrdni', {\n web: () => import('./web').then((m) => new m.qrdniWeb()),\n});\nexport * from './definitions';\nexport { qrdni };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class qrdniWeb extends WebPlugin {\n abrirEscaner() {\n console.log(\"NOT IMPLEMENTED\");\n throw new Error('Method not implemented.');\n }\n configure(options) {\n console.log(\"NOT IMPLEMENTED\");\n console.log(options);\n throw new Error('Method not implemented.');\n }\n validaMiDNIQR(options) {\n console.log(\"NOT IMPLEMENTED\");\n console.log(options);\n throw new Error('Method not implemented.');\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;AACK,MAAC,KAAK,GAAGA,mBAAc,CAAC,OAAO,EAAE;AACtC,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;AAC5D,CAAC;;ACFM,MAAM,QAAQ,SAASC,cAAS,CAAC;AACxC,IAAI,YAAY,GAAG;AACnB,QAAQ,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;AACtC,QAAQ,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC;AAClD,IAAI;AACJ,IAAI,SAAS,CAAC,OAAO,EAAE;AACvB,QAAQ,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;AACtC,QAAQ,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;AAC5B,QAAQ,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC;AAClD,IAAI;AACJ,IAAI,aAAa,CAAC,OAAO,EAAE;AAC3B,QAAQ,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;AACtC,QAAQ,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;AAC5B,QAAQ,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC;AAClD,IAAI;AACJ;;;;;;;;;"}
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
var capacitorqrdni = (function (exports, core) {
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const qrdni = core.registerPlugin('qrdni', {
|
|
5
|
+
web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.qrdniWeb()),
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
class qrdniWeb extends core.WebPlugin {
|
|
9
|
+
abrirEscaner() {
|
|
10
|
+
console.log("NOT IMPLEMENTED");
|
|
11
|
+
throw new Error('Method not implemented.');
|
|
12
|
+
}
|
|
13
|
+
configure(options) {
|
|
14
|
+
console.log("NOT IMPLEMENTED");
|
|
15
|
+
console.log(options);
|
|
16
|
+
throw new Error('Method not implemented.');
|
|
17
|
+
}
|
|
18
|
+
validaMiDNIQR(options) {
|
|
19
|
+
console.log("NOT IMPLEMENTED");
|
|
20
|
+
console.log(options);
|
|
21
|
+
throw new Error('Method not implemented.');
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
var web = /*#__PURE__*/Object.freeze({
|
|
26
|
+
__proto__: null,
|
|
27
|
+
qrdniWeb: qrdniWeb
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
exports.qrdni = qrdni;
|
|
31
|
+
|
|
32
|
+
return exports;
|
|
33
|
+
|
|
34
|
+
})({}, capacitorExports);
|
|
35
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst qrdni = registerPlugin('qrdni', {\n web: () => import('./web').then((m) => new m.qrdniWeb()),\n});\nexport * from './definitions';\nexport { qrdni };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class qrdniWeb extends WebPlugin {\n abrirEscaner() {\n console.log(\"NOT IMPLEMENTED\");\n throw new Error('Method not implemented.');\n }\n configure(options) {\n console.log(\"NOT IMPLEMENTED\");\n console.log(options);\n throw new Error('Method not implemented.');\n }\n validaMiDNIQR(options) {\n console.log(\"NOT IMPLEMENTED\");\n console.log(options);\n throw new Error('Method not implemented.');\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;AACK,UAAC,KAAK,GAAGA,mBAAc,CAAC,OAAO,EAAE;IACtC,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC5D,CAAC;;ICFM,MAAM,QAAQ,SAASC,cAAS,CAAC;IACxC,IAAI,YAAY,GAAG;IACnB,QAAQ,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IACtC,QAAQ,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC;IAClD,IAAI;IACJ,IAAI,SAAS,CAAC,OAAO,EAAE;IACvB,QAAQ,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IACtC,QAAQ,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;IAC5B,QAAQ,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC;IAClD,IAAI;IACJ,IAAI,aAAa,CAAC,OAAO,EAAE;IAC3B,QAAQ,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IACtC,QAAQ,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;IAC5B,QAAQ,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC;IAClD,IAAI;IACJ;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
//
|
|
2
|
+
// ScannerViewController.swift
|
|
3
|
+
// ValidAge
|
|
4
|
+
//
|
|
5
|
+
// Created by Diego Cid Merino on 8/1/24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import AVFoundation
|
|
9
|
+
import UIKit
|
|
10
|
+
|
|
11
|
+
class ScannerViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
|
|
12
|
+
var captureSession: AVCaptureSession!
|
|
13
|
+
var previewLayer: AVCaptureVideoPreviewLayer!
|
|
14
|
+
var returnString: Bool = true
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
public func inicializa(returnString: Bool) {
|
|
18
|
+
self.returnString = returnString
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
override func viewDidLoad() {
|
|
22
|
+
super.viewDidLoad()
|
|
23
|
+
view.backgroundColor = .black
|
|
24
|
+
|
|
25
|
+
// Creamos la sesión
|
|
26
|
+
captureSession = AVCaptureSession()
|
|
27
|
+
|
|
28
|
+
// Ejecutamos la configuración pesada en segundo plano
|
|
29
|
+
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
|
|
30
|
+
guard let self = self else { return }
|
|
31
|
+
|
|
32
|
+
guard let videoCaptureDevice = AVCaptureDevice.default(for: .video) else { return }
|
|
33
|
+
let videoInput: AVCaptureDeviceInput
|
|
34
|
+
|
|
35
|
+
do {
|
|
36
|
+
videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice)
|
|
37
|
+
} catch {
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (self.captureSession.canAddInput(videoInput)) {
|
|
42
|
+
self.captureSession.addInput(videoInput)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let metadataOutput = AVCaptureMetadataOutput()
|
|
46
|
+
|
|
47
|
+
if (self.captureSession.canAddOutput(metadataOutput)) {
|
|
48
|
+
self.captureSession.addOutput(metadataOutput)
|
|
49
|
+
metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
|
|
50
|
+
metadataOutput.metadataObjectTypes = [.qr]
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// La UI sí se actualiza en el Main Thread
|
|
54
|
+
DispatchQueue.main.async {
|
|
55
|
+
self.previewLayer = AVCaptureVideoPreviewLayer(session: self.captureSession)
|
|
56
|
+
self.previewLayer.frame = self.view.layer.bounds
|
|
57
|
+
self.previewLayer.videoGravity = .resizeAspectFill
|
|
58
|
+
self.view.layer.addSublayer(self.previewLayer)
|
|
59
|
+
|
|
60
|
+
// Iniciamos la sesión fuera del hilo principal de nuevo
|
|
61
|
+
DispatchQueue.global(qos: .userInitiated).async {
|
|
62
|
+
self.captureSession.startRunning()
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
func failed() {
|
|
69
|
+
let ac = UIAlertController(title: "Scanning not supported", message: "Your device does not support scanning a code from an item. Please use a device with a camera.", preferredStyle: .alert)
|
|
70
|
+
ac.addAction(UIAlertAction(title: "OK", style: .default))
|
|
71
|
+
present(ac, animated: true)
|
|
72
|
+
captureSession = nil
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
override func viewWillAppear(_ animated: Bool) {
|
|
76
|
+
super.viewWillAppear(animated)
|
|
77
|
+
|
|
78
|
+
if (captureSession?.isRunning == false) {
|
|
79
|
+
captureSession.startRunning()
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
override func viewWillDisappear(_ animated: Bool) {
|
|
84
|
+
super.viewWillDisappear(animated)
|
|
85
|
+
|
|
86
|
+
if (captureSession?.isRunning == true) {
|
|
87
|
+
captureSession.stopRunning()
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/*
|
|
91
|
+
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
|
|
92
|
+
captureSession.stopRunning()
|
|
93
|
+
|
|
94
|
+
var parametros: [String: Any] = [String: Any] ()
|
|
95
|
+
if(self.returnString)
|
|
96
|
+
{
|
|
97
|
+
if let metadataObject = metadataObjects.first {
|
|
98
|
+
guard let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject else { return }
|
|
99
|
+
guard let stringValue = readableObject.stringValue else { return }
|
|
100
|
+
AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
|
|
101
|
+
parametros["qrcode"] = stringValue
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
if let metadataObject = metadataObjects.first as? AVMetadataMachineReadableCodeObject {
|
|
106
|
+
|
|
107
|
+
// IMPORTANTE: Accedemos al descriptor, no al stringValue.
|
|
108
|
+
// El descriptor contiene los bytes crudos (RAW) del QR.
|
|
109
|
+
if let descriptor = metadataObject.descriptor as? CIQRCodeDescriptor {
|
|
110
|
+
|
|
111
|
+
let rawPayload = descriptor.errorCorrectedPayload
|
|
112
|
+
//print("Datos brutos: \(rawPayload.toPrettyHexString())")
|
|
113
|
+
parametros["qrcodeData"] = rawPayload
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "lecturaQR"), object: nil, userInfo: parametros)
|
|
119
|
+
}
|
|
120
|
+
*/
|
|
121
|
+
|
|
122
|
+
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
|
|
123
|
+
|
|
124
|
+
// 1. Detenemos la sesión inmediatamente para evitar múltiples lecturas
|
|
125
|
+
// startRunning/stopRunning siempre fuera del hilo principal si es posible
|
|
126
|
+
DispatchQueue.global(qos: .userInitiated).async {
|
|
127
|
+
if self.captureSession.isRunning {
|
|
128
|
+
self.captureSession.stopRunning()
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// 2. Procesamos los datos
|
|
133
|
+
guard let metadataObject = metadataObjects.first as? AVMetadataMachineReadableCodeObject,
|
|
134
|
+
let descriptor = metadataObject.descriptor as? CIQRCodeDescriptor else {
|
|
135
|
+
// Si falla, reiniciamos sesión
|
|
136
|
+
DispatchQueue.global(qos: .userInitiated).async { self.captureSession.startRunning() }
|
|
137
|
+
return
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
let rawPayload = descriptor.errorCorrectedPayload
|
|
141
|
+
let base64String = rawPayload.base64EncodedString()
|
|
142
|
+
|
|
143
|
+
// Feedback táctico
|
|
144
|
+
AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
|
|
145
|
+
|
|
146
|
+
// 3. TODO el proceso pesado de validación y cierre debe ir fuera del hilo UI
|
|
147
|
+
// pero el 'dismiss' debe volver al Main para no congelar la pantalla
|
|
148
|
+
DispatchQueue.main.async {
|
|
149
|
+
let parametros: [String: Any] = ["qrcode": base64String]
|
|
150
|
+
|
|
151
|
+
// Notificamos al Plugin
|
|
152
|
+
NotificationCenter.default.post(
|
|
153
|
+
name: NSNotification.Name(rawValue: "lecturaQR"),
|
|
154
|
+
object: nil,
|
|
155
|
+
userInfo: parametros
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
// Cerramos la cámara
|
|
159
|
+
self.dismiss(animated: true, completion: nil)
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
override var prefersStatusBarHidden: Bool {
|
|
164
|
+
return true
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
|
|
168
|
+
return .portrait
|
|
169
|
+
}
|
|
170
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import iQRDNI
|
|
3
|
+
import UIKit
|
|
4
|
+
|
|
5
|
+
@objc public class qrdni: NSObject {
|
|
6
|
+
|
|
7
|
+
public func configure(_ license: String, _ certConfig: [String: String]? = nil) -> EstadoLicencia {
|
|
8
|
+
return iQRDNI.configure(apiKey: license, certConfig: certConfig)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
public func validaMiDNIQR(datosQR: Data) -> [String: Any]? {
|
|
12
|
+
guard let miDNIData = iQRDNI.validaMiDNIQR(qrRawData: datosQR) else {
|
|
13
|
+
return nil
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
var json: [String: Any] = [:]
|
|
17
|
+
json["dni"] = miDNIData.dni ?? ""
|
|
18
|
+
json["name"] = miDNIData.name ?? ""
|
|
19
|
+
json["surnames"] = miDNIData.surnames ?? ""
|
|
20
|
+
json["birthDate"] = miDNIData.birthDate ?? ""
|
|
21
|
+
json["expiryDate"] = miDNIData.expiryDate ?? ""
|
|
22
|
+
json["gender"] = miDNIData.gender ?? ""
|
|
23
|
+
json["address"] = miDNIData.address ?? ""
|
|
24
|
+
json["nationality"] = miDNIData.nationality ?? ""
|
|
25
|
+
json["parents"] = miDNIData.parents ?? ""
|
|
26
|
+
json["supportNumber"] = miDNIData.supportNumber ?? ""
|
|
27
|
+
json["birthPlace1"] = miDNIData.birthPlace1 ?? ""
|
|
28
|
+
json["birthPlace2"] = miDNIData.birthPlace2 ?? ""
|
|
29
|
+
json["birthPlace3"] = miDNIData.birthPlace3 ?? ""
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
if(miDNIData.photoData != nil)
|
|
34
|
+
{
|
|
35
|
+
if let photoImage = UIImage(data:miDNIData.photoData!)
|
|
36
|
+
{
|
|
37
|
+
let base64String = convertImageToBase64(image: photoImage)
|
|
38
|
+
json["photoData"] = base64String
|
|
39
|
+
}
|
|
40
|
+
else
|
|
41
|
+
{
|
|
42
|
+
json["photoData"] = ""
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else
|
|
46
|
+
{
|
|
47
|
+
json["photoData"] = ""
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if(miDNIData.isAdult != nil)
|
|
51
|
+
{
|
|
52
|
+
json["isAdult"] = miDNIData.isAdult
|
|
53
|
+
}
|
|
54
|
+
else
|
|
55
|
+
{
|
|
56
|
+
json["isAdult"] = false
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
json["rawSignature"] = miDNIData.rawSignature?.base64EncodedString() ?? ""
|
|
60
|
+
json["signedData"] = miDNIData.signedData?.base64EncodedString() ?? ""
|
|
61
|
+
json["certificateRef"] = miDNIData.certificateRef ?? ""
|
|
62
|
+
|
|
63
|
+
if(miDNIData.type != nil)
|
|
64
|
+
{
|
|
65
|
+
switch miDNIData.type!.rawValue as Int{
|
|
66
|
+
case 0:
|
|
67
|
+
json["type"] = "EDAD"
|
|
68
|
+
case 1:
|
|
69
|
+
json["type"] = "SIMPLE"
|
|
70
|
+
case 2:
|
|
71
|
+
json["type"] = "COMPLETO"
|
|
72
|
+
default:
|
|
73
|
+
json["type"] = ""
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if let result = miDNIData.verificationResult {
|
|
78
|
+
var verificationJson: [String: Any] = [:]
|
|
79
|
+
|
|
80
|
+
switch result {
|
|
81
|
+
case .valid(let certificateName):
|
|
82
|
+
verificationJson["status"] = "VALID"
|
|
83
|
+
verificationJson["certificate"] = certificateName
|
|
84
|
+
case .invalid:
|
|
85
|
+
verificationJson["status"] = "INVALID"
|
|
86
|
+
case .noCertificates:
|
|
87
|
+
verificationJson["status"] = "NO_CERTIFICATES"
|
|
88
|
+
case .invalidQR:
|
|
89
|
+
verificationJson["status"] = "INVALID_QR"
|
|
90
|
+
case .expiratedQR:
|
|
91
|
+
verificationJson["status"] = "EXPIRED_QR"
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
json["verificationResult"] = verificationJson
|
|
95
|
+
} else {
|
|
96
|
+
json["verificationResult"] = ["status": "UNKNOWN"]
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
json["qrDataExpiry"] = miDNIData.qrDataExpiry ?? ""
|
|
100
|
+
|
|
101
|
+
json["fullBirthPlace"] = miDNIData.fullBirthPlace ?? ""
|
|
102
|
+
|
|
103
|
+
return json
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
public func convertImageToBase64(image: UIImage) -> String {
|
|
107
|
+
let imageData = image.pngData()!
|
|
108
|
+
return imageData.base64EncodedString(options: Data.Base64EncodingOptions.lineLength64Characters)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import Capacitor
|
|
3
|
+
|
|
4
|
+
@objc(qrdniPlugin)
|
|
5
|
+
public class qrdniPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
6
|
+
public let identifier = "qrdniPlugin"
|
|
7
|
+
public let jsName = "qrdni"
|
|
8
|
+
public let pluginMethods: [CAPPluginMethod] = [
|
|
9
|
+
CAPPluginMethod(name: "configure", returnType: CAPPluginReturnPromise),
|
|
10
|
+
CAPPluginMethod(name: "validaMiDNIQR", returnType: CAPPluginReturnPromise),
|
|
11
|
+
CAPPluginMethod(name: "abrirEscaner", returnType: CAPPluginReturnPromise),
|
|
12
|
+
]
|
|
13
|
+
private let implementation = qrdni()
|
|
14
|
+
|
|
15
|
+
// PROPIEDAD PARA GUARDAR LA LLAMADA (Plan B)
|
|
16
|
+
private var scanCall: CAPPluginCall?
|
|
17
|
+
|
|
18
|
+
@objc func configure(_ call: CAPPluginCall) {
|
|
19
|
+
let license = call.getString("license") ?? ""
|
|
20
|
+
let certs = call.getObject("certs") as? [String: String]
|
|
21
|
+
let resultado = implementation.configure(license, certs)
|
|
22
|
+
|
|
23
|
+
var json: [String: Any] = [:]
|
|
24
|
+
json["descripcion"] = resultado.descripcion
|
|
25
|
+
json["APIKeyValida"] = resultado.APIKeyValida
|
|
26
|
+
json["lecturaQRHabilitada"] = resultado.lecturaQRHabilitada
|
|
27
|
+
|
|
28
|
+
call.resolve(json)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@objc func validaMiDNIQR(_ call: CAPPluginCall) {
|
|
32
|
+
guard let qrBase64 = call.getString("data") else {
|
|
33
|
+
call.reject("No se proporcionó el QR")
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if let qrData = Data(base64Encoded: qrBase64) {
|
|
38
|
+
if let resultadoJson = implementation.validaMiDNIQR(datosQR: qrData) {
|
|
39
|
+
call.resolve(resultadoJson)
|
|
40
|
+
} else {
|
|
41
|
+
call.reject("La validación del DNI falló o el QR es inválido")
|
|
42
|
+
}
|
|
43
|
+
} else {
|
|
44
|
+
call.reject("Formato Base64 inválido")
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@objc func abrirEscaner(_ call: CAPPluginCall) {
|
|
49
|
+
// 1. Guardamos la llamada en nuestra variable local
|
|
50
|
+
self.scanCall = call
|
|
51
|
+
|
|
52
|
+
// 2. También la guardamos en el bridge por seguridad
|
|
53
|
+
self.bridge?.saveCall(call)
|
|
54
|
+
|
|
55
|
+
DispatchQueue.main.async {
|
|
56
|
+
let scannerVC = ScannerViewController()
|
|
57
|
+
scannerVC.modalPresentationStyle = .fullScreen
|
|
58
|
+
scannerVC.inicializa(returnString: false)
|
|
59
|
+
|
|
60
|
+
NotificationCenter.default.addObserver(self, selector: #selector(self.handleScannerResult(_:)), name: NSNotification.Name("lecturaQR"), object: nil)
|
|
61
|
+
|
|
62
|
+
self.bridge?.viewController?.present(scannerVC, animated: true)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@objc func handleScannerResult(_ notification: Notification) {
|
|
67
|
+
NotificationCenter.default.removeObserver(self, name: NSNotification.Name("lecturaQR"), object: nil)
|
|
68
|
+
|
|
69
|
+
// 3. RECUPERAMOS LA LLAMADA DESDE NUESTRA VARIABLE
|
|
70
|
+
guard let call = self.scanCall else {
|
|
71
|
+
print("ERROR: La referencia local a la llamada es nil")
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
guard let userInfo = notification.userInfo,
|
|
76
|
+
let qrBase64 = userInfo["qrcode"] as? String else {
|
|
77
|
+
call.reject("Error al obtener datos")
|
|
78
|
+
self.scanCall = nil // Limpiamos
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
|
|
83
|
+
guard let self = self else { return }
|
|
84
|
+
|
|
85
|
+
if let qrData = Data(base64Encoded: qrBase64) {
|
|
86
|
+
if let resultadoJson = self.implementation.validaMiDNIQR(datosQR: qrData) {
|
|
87
|
+
DispatchQueue.main.async {
|
|
88
|
+
call.resolve(resultadoJson)
|
|
89
|
+
self.scanCall = nil // Limpieza final
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
DispatchQueue.main.async {
|
|
93
|
+
call.reject("Fallo en validación")
|
|
94
|
+
self.scanCall = nil
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
DispatchQueue.main.async {
|
|
99
|
+
call.reject("Base64 corrupto")
|
|
100
|
+
self.scanCall = nil
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import XCTest
|
|
2
|
+
@testable import qrdniPlugin
|
|
3
|
+
|
|
4
|
+
class qrdniTests: XCTestCase {
|
|
5
|
+
func testEcho() {
|
|
6
|
+
// This is an example of a functional test case for a plugin.
|
|
7
|
+
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
|
8
|
+
|
|
9
|
+
let implementation = qrdni()
|
|
10
|
+
let value = "Hello, World!"
|
|
11
|
+
let result = implementation.echo(value)
|
|
12
|
+
|
|
13
|
+
XCTAssertEqual(value, result)
|
|
14
|
+
}
|
|
15
|
+
}
|