diff --git a/camera.xcodeproj/project.pbxproj b/camera.xcodeproj/project.pbxproj index d1f6fa2..415fc61 100644 --- a/camera.xcodeproj/project.pbxproj +++ b/camera.xcodeproj/project.pbxproj @@ -202,8 +202,9 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer: Luis Diniz (HUX544ZBSL)"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + "CODE_SIGN_ENTITLEMENTS[sdk=iphoneos*]" = ""; + CODE_SIGN_IDENTITY = "iPhone Developer: Natalia Terlecki (8B96NL57N3)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: Natalia Terlecki (8B96NL57N3)"; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -220,10 +221,10 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; - PROVISIONING_PROFILE = "4d0a483e-6fa4-454e-a019-6ce6d8c6f307"; + PROVISIONING_PROFILE = "c0db150a-581c-4aa9-bfc3-848f4eec3d08"; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; TARGETED_DEVICE_FAMILY = "1,2"; @@ -247,7 +248,8 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_IDENTITY = "iPhone Distribution: IndexSquare LDA (QM7HJTY23M)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: IndexSquare LDA (QM7HJTY23M)"; COPY_PHASE_STRIP = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -258,9 +260,9 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; - PROVISIONING_PROFILE = "4d0a483e-6fa4-454e-a019-6ce6d8c6f307"; + PROVISIONING_PROFILE = "3765a270-85d2-474b-9784-b02ccb687465"; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; @@ -271,12 +273,13 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_IDENTITY = ""; + CODE_SIGN_IDENTITY = "iPhone Developer: Natalia Terlecki (8B96NL57N3)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: Natalia Terlecki (8B96NL57N3)"; INFOPLIST_FILE = camera/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = ""; + PROVISIONING_PROFILE = "c0db150a-581c-4aa9-bfc3-848f4eec3d08"; }; name = Debug; }; @@ -284,12 +287,13 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_IDENTITY = "iPhone Distribution: IndexSquare LDA (QM7HJTY23M)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: IndexSquare LDA (QM7HJTY23M)"; INFOPLIST_FILE = camera/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = ""; + PROVISIONING_PROFILE = "3765a270-85d2-474b-9784-b02ccb687465"; }; name = Release; }; diff --git a/camera.xcodeproj/project.xcworkspace/xcuserdata/nataliaterlecka.xcuserdatad/UserInterfaceState.xcuserstate b/camera.xcodeproj/project.xcworkspace/xcuserdata/nataliaterlecka.xcuserdatad/UserInterfaceState.xcuserstate index 04295fb..bf1b732 100644 Binary files a/camera.xcodeproj/project.xcworkspace/xcuserdata/nataliaterlecka.xcuserdatad/UserInterfaceState.xcuserstate and b/camera.xcodeproj/project.xcworkspace/xcuserdata/nataliaterlecka.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/camera.xcodeproj/xcuserdata/nataliaterlecka.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/camera.xcodeproj/xcuserdata/nataliaterlecka.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index fe8b822..fe2b454 100644 --- a/camera.xcodeproj/xcuserdata/nataliaterlecka.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/camera.xcodeproj/xcuserdata/nataliaterlecka.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -2,22 +2,4 @@ - - - - - - diff --git a/camera/Base.lproj/Main.storyboard b/camera/Base.lproj/Main.storyboard index 34384f8..d7ee9af 100644 --- a/camera/Base.lproj/Main.storyboard +++ b/camera/Base.lproj/Main.storyboard @@ -1,7 +1,6 @@ - @@ -22,9 +21,6 @@ - + + - + - - + - + + + + + + + + - diff --git a/camera/CameraManager.swift b/camera/CameraManager.swift index 454f36d..52d9613 100644 --- a/camera/CameraManager.swift +++ b/camera/CameraManager.swift @@ -37,10 +37,13 @@ public class CameraManager: NSObject, AVCaptureFileOutputRecordingDelegate { /// Capture session to customize camera settings. public var captureSession: AVCaptureSession? - + /// Property to determine if the manager should show the error for the user. If you want to show the errors yourself set this to false. If you want to add custom error UI set showErrorBlock property. Default value is true. public var showErrorsToUsers = true - + + /// Property to determine if the manager should show the camera permission popup immediatly when it's needed or you want to show it manually. Default value is true. + public var showAccessPermissionPopupAutomatically = true + /// A block creating UI to present error message to the user. public var showErrorBlock:(erTitle: String, erMessage: String) -> Void = { (erTitle: String, erMessage: String) -> Void in UIAlertView(title: erTitle, message: erMessage, delegate: nil, cancelButtonTitle: "OK").show() @@ -59,7 +62,7 @@ public class CameraManager: NSObject, AVCaptureFileOutputRecordingDelegate { } } return false - }() + }() /// Property to change camera device between front and back. public var cameraDevice: CameraDevice { @@ -197,7 +200,7 @@ public class CameraManager: NSObject, AVCaptureFileOutputRecordingDelegate { } return NSURL(fileURLWithPath: tempPath!)! }() - + /// CameraManager singleton instance to use the camera. public class var sharedInstance: CameraManager { return _singletonSharedInstance @@ -214,7 +217,7 @@ public class CameraManager: NSObject, AVCaptureFileOutputRecordingDelegate { :param: view The view you want to add the preview layer to :param: cameraOutputMode The mode you want capturesession to run image / video / video and microphone - :returns: Current state of the camera: Ready / AccessDenied / NoDeviceFound. + :returns: Current state of the camera: Ready / AccessDenied / NoDeviceFound / NotDetermined. */ public func addPreviewLayerToView(view: UIView) -> CameraState { @@ -222,8 +225,7 @@ public class CameraManager: NSObject, AVCaptureFileOutputRecordingDelegate { } public func addPreviewLayerToView(view: UIView, newCameraOutputMode: CameraOutputMode) -> CameraState { - let currentCameraState = _checkIfCameraIsAvailable() - if currentCameraState == .Ready || currentCameraState == .NotDetermined { + if self._canLoadCamera() { if let validEmbedingView = self.embedingView? { if let validPreviewLayer = self.previewLayer? { validPreviewLayer.removeFromSuperlayer() @@ -239,7 +241,22 @@ public class CameraManager: NSObject, AVCaptureFileOutputRecordingDelegate { }) } } - return currentCameraState + return self._checkIfCameraIsAvailable() + } + + /** + Asks the user for camera permissions. Only works if the permissions are not yet determined. + + :param: completition Completition block with the result of permission request + */ + public func askUserForCameraPermissions(completition: Bool -> Void) + { + AVCaptureDevice.requestAccessForMediaType(AVMediaTypeVideo, completionHandler: { (alowedAccess) -> Void in + dispatch_sync(dispatch_get_main_queue(), { () -> Void in + completition(alowedAccess) + }) + }) + } /** @@ -262,7 +279,7 @@ public class CameraManager: NSObject, AVCaptureFileOutputRecordingDelegate { self._startFollowingDeviceOrientation() } } else { - if self._checkIfCameraIsAvailable() == .Ready || _checkIfCameraIsAvailable() == .NotDetermined { + if self._canLoadCamera() { if self.cameraIsSetup { self.stopAndRemoveCaptureSession() } @@ -364,6 +381,15 @@ public class CameraManager: NSObject, AVCaptureFileOutputRecordingDelegate { } } + /** + Current camera status. + + :returns: Current state of the camera: Ready / AccessDenied / NoDeviceFound / NotDetermined + */ + public func currentCameraStatus() -> CameraState + { + return self._checkIfCameraIsAvailable() + } // PRAGMA MARK - AVCaptureFileOutputRecordingDelegate @@ -482,6 +508,12 @@ public class CameraManager: NSObject, AVCaptureFileOutputRecordingDelegate { } } + private func _canLoadCamera() -> Bool + { + let currentCameraState = _checkIfCameraIsAvailable() + return currentCameraState == .Ready || (currentCameraState == .NotDetermined && self.showAccessPermissionPopupAutomatically) + } + private func _setupCamera(completition: Void -> Void) { self.captureSession = AVCaptureSession() @@ -541,7 +573,6 @@ public class CameraManager: NSObject, AVCaptureFileOutputRecordingDelegate { if userAgreedToUseIt { return .Ready } else if authorizationStatus == AVAuthorizationStatus.NotDetermined { - AVCaptureDevice.requestAccessForMediaType(AVMediaTypeVideo, completionHandler: { (alowedAccess) -> Void in }) return .NotDetermined } else { return .AccessDenied diff --git a/camera/Info.plist b/camera/Info.plist index 2586fbe..2691793 100644 --- a/camera/Info.plist +++ b/camera/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - + com.imaginarycloud.cameraManager166784567676879 CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/camera/ViewController.swift b/camera/ViewController.swift index c7ddf56..fd08fdd 100644 --- a/camera/ViewController.swift +++ b/camera/ViewController.swift @@ -17,25 +17,32 @@ class ViewController: UIViewController { // MARK: - @IBOutlets @IBOutlet weak var cameraView: UIView! - @IBOutlet weak var imageView: UIImageView! @IBOutlet weak var cameraButton: UIButton! + @IBOutlet weak var askForPermissionsButton: UIButton! + @IBOutlet weak var askForPermissionsLabel: UILabel! // MARK: - UIViewController override func viewDidLoad() { super.viewDidLoad() - let currentCameraState = self.cameraManager.addPreviewLayerToView(self.cameraView, newCameraOutputMode: CameraOutputMode.VideoOnly) + + self.cameraManager.showAccessPermissionPopupAutomatically = false + + self.askForPermissionsButton.hidden = true + self.askForPermissionsLabel.hidden = true + + let currentCameraState = self.cameraManager.currentCameraStatus() + if currentCameraState == .AccessDenied { UIAlertView(title: "Camera access denied", message: "You need to go to settings app and grant acces to the camera device to use it.", delegate: nil, cancelButtonTitle: "OK").show() - } else if (currentCameraState == .NoDeviceFound) { + } else if currentCameraState == .NoDeviceFound { UIAlertView(title: "Camera unavailable", message: "The device does not have a camera.", delegate: nil, cancelButtonTitle: "OK").show() - } - - self.cameraManager.cameraDevice = .Front - self.imageView.hidden = true - CameraManager.sharedInstance.showErrorBlock = { (erTitle: String, erMessage: String) -> Void in - UIAlertView(title: erTitle, message: erMessage, delegate: nil, cancelButtonTitle: "OK").show() + } else if currentCameraState == .NotDetermined { + self.askForPermissionsButton.hidden = false + self.askForPermissionsLabel.hidden = false + } else if (currentCameraState == .Ready) { + self.addCameraToView() } } @@ -53,6 +60,18 @@ class ViewController: UIViewController { self.cameraManager.stopCaptureSession() } + + // MARK: - ViewController + + private func addCameraToView() + { + self.cameraManager.addPreviewLayerToView(self.cameraView, newCameraOutputMode: CameraOutputMode.VideoWithMic) + self.cameraManager.cameraDevice = .Front + CameraManager.sharedInstance.showErrorBlock = { (erTitle: String, erMessage: String) -> Void in + UIAlertView(title: erTitle, message: erMessage, delegate: nil, cancelButtonTitle: "OK").show() + } + } + // MARK: - @IBActions @IBAction func changeFlashMode(sender: UIButton) @@ -121,6 +140,19 @@ class ViewController: UIViewController { sender.setTitle("Back", forState: UIControlState.Normal) } } + + @IBAction func askForCameraPermissions(sender: UIButton) + { + self.cameraManager.askUserForCameraPermissions({ permissionGranted in + self.askForPermissionsButton.hidden = true + self.askForPermissionsLabel.hidden = true + self.askForPermissionsButton.alpha = 0 + self.askForPermissionsLabel.alpha = 0 + if permissionGranted { + self.addCameraToView() + } + }) + } }