Hello how are you? I hope you can help me, I have a big problem.
I just got my first job as an iOS developer and I’m adjusting new features to the project I’m in charge of.
Before I joined the project there was another developer in my place who started the project and he is now not in the project.
I have this code that works to open the front camera, on the screen it puts a mask that is used to tell the user to place his face in that mask that is actually a guide, take a selfie photo, save it on the device and take said photo to send to the server via ‘manager.sendSelfieToken(parameters: params, file: “selfie.png”)’ found in the ’ sendSelfieToken()’ function.
There is another driver that instead of taking a selfie, records a video. So my task is to capture the selfie. In the controller where the video is recorded take the following extension and with its function
extension SelfieTokenViewController: ServiceManagerDelegate{ func returnStringResponse(response: String){
Which, I think, works to read the response from the server and so the controller acts on it.
I attach the code of my controller ‘SelfieTokenViewController’:
override func viewDidLoad() {
super.viewDidLoad()
if AVCaptureDevice.authorizationStatus(for: .video) == .authorized{
self.setPlayer()
}else{
AVCaptureDevice.requestAccess(for: .video) { (granted:Bool) in
if granted{
self.performSelector(onMainThread: #selector(self.setPlayer), with: nil, waitUntilDone: false)
}else{
let message = "Para continuar el proceso necesitamos acceso a tu cámara. Otorga a Dicio la opción de acceder a tu cámara dentro de Configuración."
self.performSelector(onMainThread: #selector(self.showAlert(message:)), with: message, waitUntilDone: false)
}
}
}
// crear observador en caso de que el usuario acepte los permisos en segundo plano
observer = NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: .main, using: { [unowned self] notification in
if AVCaptureDevice.authorizationStatus(for: .video) == .authorized {
self.performSelector(onMainThread: #selector(self.setPlayer), with: nil, waitUntilDone: false)
} else {
let message = "Para continuar el proceso necesitamos acceso a tu cámara. Otorga a Dicio la opción de acceder a tu cámara dentro de Configuración."
self.performSelector(onMainThread: #selector(self.showAlert(message:)), with: message, waitUntilDone: false)
}
})
// Configurar la sesión de captura
captureSession = AVCaptureSession()
captureSession?.sessionPreset = .photo
// Buscar la cámara frontal
frontCamera = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .front)
// Configurar la entrada de la cámara frontal
if let frontCamera = frontCamera {
do {
let input = try AVCaptureDeviceInput(device: frontCamera)
if captureSession?.canAddInput(input) == true {
captureSession?.addInput(input)
}
} catch {
print("Error al configurar la entrada de la cámara frontal: \(error.localizedDescription)")
}
}
// Configurar la máscara de guía
self.animacion?.isHidden = false
self.maskImage?.image = UIImage(named: "face_green")
// Configurar la vista previa de la cámara
previewLayer = AVCaptureVideoPreviewLayer(session: captureSession!)
previewLayer?.videoGravity = .resizeAspectFill
previewLayer?.frame = view.layer.bounds
view.layer.insertSublayer(previewLayer!, at: 0)
// Comenzar la sesión de captura
DispatchQueue.global(qos: .background).async {
self.captureSession?.startRunning()
}
}
@objc func nextScreen() {
let descripcion = "{\\\"coincidencia\\\":true,\\\"speech\\\":true}"
let jsonLifeCycle = Util.createLifeCycleJson(status: "OK", description: descripcion, step: "captura_video_token", stepEvent: "captura_video_token", nombreOtorgante: AppConfig.shared.nombreCorto, nombreCompleto: AppConfig.shared.name, telefono: "", correo: "", bandera: "", finished: false, typeId: AppConfig.shared.IDTypeName.lowercased())
self.lifecycleRequest = jsonLifeCycle
let manager = ServiceManager()
manager.delegate = self
DispatchQueue.global(qos: .background).async {
manager.updateLifeCycle(parameters: jsonLifeCycle)
}
// Update Score
let parameters = ["createScore" : "true" as Any,
"uuid" : AppConfig.shared.uuid as Any,
"transaccion": AppConfig.shared.idTransaction as Any]
manager.updateInfoScore(parameters: parameters)
// End Update Score
self.blurView?.removeBlurFromView()
self.activityIndicator?.stopAnimating()
self.activityView?.isHidden = true
self.performSegue(withIdentifier: "TerminarViewController", sender: self)
}
@objc func stopSelfie() {
self.animacion?.isHidden = true
self.maskImage?.image = UIImage(named: "face_yellow")
self.session.stopRunning()
blurView?.addBlurToView()
if self.activityView == nil {
activityView = UIView(frame: CGRect(x: (self.view.frame.width / 2) - 50, y: (self.view.frame.height / 2) - 50, width: 100, height: 100))
activityView!.backgroundColor = UIColor(red:0 , green: 0, blue: 0, alpha: 0.8)
activityView!.layer.cornerRadius = 4
activityIndicator = UIActivityIndicatorView(frame: CGRect(x: (activityView!.frame.width / 2) - 15, y: (activityView!.frame.height / 2) - 15, width: 30, height: 30))
if #available(iOS 13.0, *) {
activityIndicator!.style = .large
activityIndicator?.color = .white
} else {
activityIndicator?.style = .whiteLarge
}
activityView!.addSubview(activityIndicator!)
self.view.addSubview(activityView!)
}
activityIndicator?.startAnimating()
activityView?.isHidden = false
self.view.isUserInteractionEnabled = false
//consumir servicio
DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) {
DispatchQueue.global(qos: .background).async {
self.idServicio = 1
self.sendSelfieToken()
}
}
}
@objc func captureButtonTapped() {
// guard let captureSession = captureSession else { return }
if intentosRealizados == 1 {
if session.canAddOutput(self.photoOutput) {
session.addOutput(self.photoOutput)
}
}
let settings = AVCapturePhotoSettings()
if let connection = photoOutput.connection(with: .video) {
// Ajustar la orientación a vertical
connection.videoOrientation = .portrait
}
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let fileUrl = paths[0].appendingPathComponent("selfie.png")
try? FileManager.default.removeItem(at: fileUrl)
photoOutput.capturePhoto(with: settings, delegate: self)
DispatchQueue.main.asyncAfter(deadline: .now() + 6.0){
self.performSelector(onMainThread: #selector(self.stopSelfie), with: nil, waitUntilDone: false)
}
}
// Función para capturar una foto
func sendSelfieToken(){
var isPasaporte = "false"
if AppConfig.shared.IDType == 2 {
isPasaporte = "true"
}
let params = [
[
"key": "uuidUser",
"value": AppConfig.shared.uuid as Any,
"type": "text"
],
[
"key": "service_call",
"value": "videotoken-embedding",
"type": "text"
],
[
"key": "created",
"value": "0",
"type": "text"
],
[
"key": "expire",
"value": "0",
"type": "text"
], [
"key": "identificacion_pasaporte",
"value": isPasaporte as Any,
"type": "text"
],
[
"key": "originOS",
"value": "ios_native",
"type": "text"
]
] as [[String : Any]]
manager.sendSelfieToken(parameters: params, file: "selfie.png")
// print("SE ENVIÓ LA SELFIE")
}
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
self.animacion?.isHidden = true
blurView?.addBlurToView()
if self.activityView == nil {
activityView = UIView(frame: CGRect(x: (self.view.frame.width / 2) - 50, y: (self.view.frame.height / 2) - 50, width: 100, height: 100))
activityView!.backgroundColor = UIColor(red:0 , green: 0, blue: 0, alpha: 0.8)
activityView!.layer.cornerRadius = 4
activityIndicator = UIActivityIndicatorView(frame: CGRect(x: (activityView!.frame.width / 2) - 15, y: (activityView!.frame.height / 2) - 15, width: 30, height: 30))
if #available(iOS 13.0, *) {
activityIndicator!.style = .large
activityIndicator?.color = .white
} else {
activityIndicator?.style = .whiteLarge
}
activityView!.addSubview(activityIndicator!)
self.view.addSubview(activityView!)
}
self.maskImage?.image = UIImage(named: "face_yellow")
if let imageData = photo.fileDataRepresentation(), let image = UIImage(data: imageData) {
let compressedData = image.jpegData(compressionQuality: 0.5)
if let compressedImage = UIImage(data: compressedData ?? Data()){
if let compressedData = compressImage(image: compressedImage, maxSizeInBytes: 1 * 1024 * 1024) {
let rotatedImage = UIImage(data: compressedData)?.rotate(radians: .pi / 0.5)
let pngData = rotatedImage?.jpegData(compressionQuality: 1.0)
let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let fileURL = documentDirectory.appendingPathComponent("selfie.png")
if let data = pngData {
blurView?.addBlurToView()
activityIndicator?.startAnimating()
activityView?.isHidden = false
self.blurView?.addBlurToView()
self.view.isUserInteractionEnabled = false
do {
try data.write(to: fileURL)
print("Se guardó la imagen en: \(fileURL)")
activityIndicator?.startAnimating()
activityView?.isHidden = false
self.view.isUserInteractionEnabled = false
} catch {
print("Error al guardar la imagen: \(error.localizedDescription)")
}
}
}
}
}
}
extension SelfieTokenViewController: ServiceManagerDelegate{
func returnStringResponse(response: String) {
self.performSelector(onMainThread: #selector(self.stopSelfie), with: nil, waitUntilDone: false)
print(response)
let responseV = VideoTokenResponse.init(JSONString: response)
AppConfig.shared.faceApi = responseV
if responseV?.liveness == “Vivo” && responseV?.match == true {
var payload: [String: Any]?
do {
let data = response.data(using: .utf8)!
let json = try JSONSerialization.jsonObject(with: data) as! Dictionary<String, Any>
payload = json["payload"] as? [String: Any]
}
catch {
print("json serialization error")
}
var payloadString = Util.json(from: payload as Any)
payloadString = payloadString?.replacingOccurrences(of: "\"", with: "\\\"")
payloadString = payloadString?.replacingOccurrences(of: "\\\\\"", with: "\\\"")
payloadString = payloadString?.replacingOccurrences(of: "\\\"[", with: "[")
payloadString = payloadString?.replacingOccurrences(of: "]\\\"", with: "]")
self.createEventSuccess(paso: "Captura Video Token", status: 200, payload: payloadString!)
self.performSelector(onMainThread: #selector(self.nextScreen), with: nil, waitUntilDone: false)
} else if responseV!.status > 0 && responseV?.status != 200 {
let payload = "\\\"" + (responseV?.message)! + "\\\""
self.createEventSuccess(paso: "Captura Video Token", status: (responseV?.status)!, payload: payload)
self.messageFail = (responseV?.message)!
self.statusFail = (responseV?.status)!
self.performSelector(onMainThread: #selector(self.showMessageError(message:)), with: responseV?.message, waitUntilDone: false)
} else {
let payload = "\\\"" + (responseV?.message)! + "\\\""
self.createEventSuccess(paso: "Captura Video Token", status: (responseV?.status)!, payload: payload)
self.messageFail = (responseV?.message)!
self.statusFail = (responseV?.status)!
self.performSelector(onMainThread: #selector(self.showMessageError(message:)), with: responseV?.message, waitUntilDone: false)
}
}
func returnResponseOTP(response: String, status: Int) {
var payload = ""
let tokens = OTPToken.init(JSONString: response)
if tokens != nil && tokens?.codes != nil && tokens!.codes!.count > 0{
payload = "{\"codes\":" + (tokens?.codes!.toJSONString())! + "}"
payload = payload.replacingOccurrences(of: "\"", with: "\\\"")
self.createEventSuccess(paso: "OTP", status: status, payload: payload)
// self.tokenArray = tokens
self.performSelector(onMainThread: #selector(self.captureButtonTapped), with: nil, waitUntilDone: false)
//self.performSelector(onMainThread: #selector(self.showToken), with: nil, waitUntilDone: false)
} else {
payload = "\\\"" + (tokens?.message_client)! + "\\\""
self.createEventSuccess(paso: "OTP", status: status, payload: payload)
let mensaje = "Por favor ubica tu rostro en el área marcada para continuar."
self.performSelector(onMainThread: #selector(self.errorOnOTP(message:)), with: mensaje, waitUntilDone: false)
}
}
func returnLifeCycleResponse(response: String, status: Int) {
self.statusResponse = status
self.createEventLifeCycle()
}
func error() {
let mensaje = "No ha sido posible ubicar tu rostro o se perdió la conexión."
self.performSelector(onMainThread: #selector(self.errorOnOTP(message:)), with: mensaje, waitUntilDone: false)
}
}
extension SelfieTokenViewController: AVCaptureVideoDataOutputSampleBufferDelegate {//AVCaptureVideoDataOutputSampleBufferDelegate {
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection){
if getFrame{
DispatchQueue.main.async { [unowned self] in
guard let outputImage = self.imageFromSampleBuffer(sampleBuffer: sampleBuffer) else { return }
let rotatedImage = outputImage.rotate(radians: .pi * 0.5)
self.saveImageInSB(image: rotatedImage)
}
getFrame = false
}
}
}
I hope to have your help, I thank you in advance!
Greetings.
Read the response from the server after the file has been sent and act on the response.