Skip to content

Commit

Permalink
fix: Fix location permission not resolving on iOS (#2672)
Browse files Browse the repository at this point in the history
* fix: Fix location permission not resolving on iOS

* fix: Remove unused code

* fix: Ignore first call

* Use `GlobalReferenceHolder`
  • Loading branch information
mrousavy authored Mar 21, 2024
1 parent 73e3c44 commit a255c24
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 51 deletions.
9 changes: 4 additions & 5 deletions package/ios/CameraViewManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,10 @@ final class CameraViewManager: RCTViewManager {
}

@objc
final func requestLocationPermission(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
let manager = CLLocationManager()
let promise = Promise(resolver: resolve, rejecter: reject)
let delegate = LocationManagerDelegate(promise: promise)
manager.requestWhenInUseAuthorization()
final func requestLocationPermission(_ resolve: @escaping RCTPromiseResolveBlock, reject _: @escaping RCTPromiseRejectBlock) {
CLLocationManager.requestAccess(for: .whenInUse) { status in
resolve(status.descriptor)
}
}

// MARK: Private
Expand Down
3 changes: 2 additions & 1 deletion package/ios/Core/CameraSession+Location.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import Foundation

extension CameraSession {
func configureLocationOutput(configuration: CameraConfiguration) throws {
if configuration.enableLocation {
let locationServicesEnabled = CLLocationManager.locationServicesEnabled()
if configuration.enableLocation && locationServicesEnabled {
let locationProvider = LocationProvider()
guard locationProvider.hasPermission else {
// Location permission has been denied
Expand Down
11 changes: 4 additions & 7 deletions package/ios/Core/PhotoCaptureDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,9 @@

import AVFoundation

// Keeps a strong reference on delegates, as the AVCapturePhotoOutput only holds a weak reference.
private var delegatesReferences: [NSObject] = []

// MARK: - PhotoCaptureDelegate

class PhotoCaptureDelegate: NSObject, AVCapturePhotoCaptureDelegate {
class PhotoCaptureDelegate: GlobalReferenceHolder, AVCapturePhotoCaptureDelegate {
private let promise: Promise
private let enableShutterSound: Bool
private let cameraSessionDelegate: CameraSessionDelegate?
Expand All @@ -28,7 +25,7 @@ class PhotoCaptureDelegate: NSObject, AVCapturePhotoCaptureDelegate {
self.metadataProvider = metadataProvider
self.cameraSessionDelegate = cameraSessionDelegate
super.init()
delegatesReferences.append(self)
makeGlobal()
}

func photoOutput(_: AVCapturePhotoOutput, willCapturePhotoFor _: AVCaptureResolvedPhotoSettings) {
Expand All @@ -43,7 +40,7 @@ class PhotoCaptureDelegate: NSObject, AVCapturePhotoCaptureDelegate {

func photoOutput(_: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
defer {
delegatesReferences.removeAll(where: { $0 == self })
removeGlobal()
}
if let error = error as NSError? {
promise.reject(error: .capture(.unknown(message: error.description)), cause: error)
Expand Down Expand Up @@ -80,7 +77,7 @@ class PhotoCaptureDelegate: NSObject, AVCapturePhotoCaptureDelegate {

func photoOutput(_: AVCapturePhotoOutput, didFinishCaptureFor _: AVCaptureResolvedPhotoSettings, error: Error?) {
defer {
delegatesReferences.removeAll(where: { $0 == self })
removeGlobal()
}
if let error = error as NSError? {
if error.code == -11807 {
Expand Down
58 changes: 58 additions & 0 deletions package/ios/Extensions/CLLocationManager+requestAccess.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//
// CLLocationManager+requestAccess.swift
// VisionCamera
//
// Created by Marc Rousavy on 21.03.24.
//

import CoreLocation
import Foundation

extension CLLocationManager {
enum AccessType {
case whenInUse
case always
}

static func requestAccess(for accessType: AccessType, _ callback: @escaping (_ status: CLAuthorizationStatus) -> Void) {
let manager = CLLocationManager()
let delegate = CLLocationManagerCallbackDelegate(locationManager: manager, callback: callback)
manager.delegate = delegate
switch accessType {
case .whenInUse:
manager.requestWhenInUseAuthorization()
case .always:
manager.requestAlwaysAuthorization()
}
}

private class CLLocationManagerCallbackDelegate: GlobalReferenceHolder, CLLocationManagerDelegate {
private let locationManager: CLLocationManager
private let callback: (_ status: CLAuthorizationStatus) -> Void

init(locationManager: CLLocationManager, callback: @escaping (_ status: CLAuthorizationStatus) -> Void) {
self.locationManager = locationManager
self.callback = callback
super.init()
makeGlobal()
}

private var authorizationStatus: CLAuthorizationStatus {
if #available(iOS 14.0, *) {
return locationManager.authorizationStatus
} else {
return CLLocationManager.authorizationStatus()
}
}

func locationManagerDidChangeAuthorization(_: CLLocationManager) {
if authorizationStatus == .notDetermined {
// This method is called once on init with status "notDetermined", ignore the first call.
return
}

removeGlobal()
callback(authorizationStatus)
}
}
}
38 changes: 0 additions & 38 deletions package/ios/LocationManagerDelegate.swift

This file was deleted.

20 changes: 20 additions & 0 deletions package/ios/React Utils/GlobalReferenceHolder.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// GlobalReferenceHolder.swift
// VisionCamera
//
// Created by Marc Rousavy on 21.03.24.
//

import Foundation

class GlobalReferenceHolder: NSObject {
private static var references: [GlobalReferenceHolder] = []

func makeGlobal() {
GlobalReferenceHolder.references.append(self)
}

func removeGlobal() {
GlobalReferenceHolder.references.removeAll(where: { $0 == self })
}
}

0 comments on commit a255c24

Please sign in to comment.