New property to determine if you want the user to be asked about camera permissions automatically or manually.

This commit is contained in:
Natalia Terlecka 2015-03-20 11:59:51 +00:00
parent 0ea8751297
commit b0ebfcd94b
7 changed files with 128 additions and 60 deletions

View File

@ -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;
};

View File

@ -2,22 +2,4 @@
<Bucket
type = "1"
version = "2.0">
<Breakpoints>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "camera/ViewController.swift"
timestampString = "447356735.111942"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "93"
endingLineNumber = "93"
landmarkName = "outputModeButtonTapped(_:)"
landmarkType = "5">
</BreakpointContent>
</BreakpointProxy>
</Breakpoints>
</Bucket>

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6751" systemVersion="13F1066" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="bhK-VL-qY4">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6736"/>
</dependencies>
<scenes>
@ -22,9 +21,6 @@
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<color key="tintColor" red="0.54901963470000004" green="0.77647066119999997" blue="0.2470588386" alpha="1" colorSpace="deviceRGB"/>
</view>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="yyS-3g-UqL">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
</imageView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="sT4-CC-oh5">
<rect key="frame" x="496" y="20" width="88" height="33"/>
<color key="backgroundColor" red="0.98039221759999995" green="0.0078431377190000002" blue="0.52156865600000002" alpha="1" colorSpace="deviceRGB"/>
@ -80,38 +76,61 @@
<action selector="outputModeButtonTapped:" destination="BYZ-38-t0r" eventType="touchUpInside" id="Bgy-rQ-cfF"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="rd3-ei-B9P">
<rect key="frame" x="40" y="93" width="520" height="397"/>
<color key="backgroundColor" red="1" green="0.0" blue="0.46666669849999998" alpha="0.5" colorSpace="deviceRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="27"/>
<state key="normal">
<color key="titleColor" red="0.36078432199999999" green="0.36078432199999999" blue="0.36078432199999999" alpha="1" colorSpace="deviceRGB"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="askForCameraPermissions:" destination="BYZ-38-t0r" eventType="touchUpInside" id="gbn-Ql-Lnv"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Tap here to enable camera access and take great pictures" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2bK-wq-6Rf">
<rect key="frame" x="40" y="93" width="520" height="397"/>
<fontDescription key="fontDescription" type="system" pointSize="25"/>
<color key="textColor" red="0.36078432199999999" green="0.36078432199999999" blue="0.36078432199999999" alpha="1" colorSpace="deviceRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<gestureRecognizers/>
<constraints>
<constraint firstItem="yyS-3g-UqL" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" id="2RH-Jf-TPm"/>
<constraint firstItem="2bK-wq-6Rf" firstAttribute="top" secondItem="rd3-ei-B9P" secondAttribute="top" id="0KQ-L2-vRf"/>
<constraint firstItem="19j-xT-Ttb" firstAttribute="height" secondItem="3WP-Xo-FaJ" secondAttribute="height" id="3Fa-ID-yp6"/>
<constraint firstItem="19j-xT-Ttb" firstAttribute="width" secondItem="3WP-Xo-FaJ" secondAttribute="width" id="8aO-Xm-KH2"/>
<constraint firstItem="EI2-CK-oqA" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" id="E1I-Yh-igT"/>
<constraint firstItem="wfy-db-euE" firstAttribute="top" secondItem="yyS-3g-UqL" secondAttribute="bottom" id="INX-TM-tak"/>
<constraint firstAttribute="trailing" secondItem="yyS-3g-UqL" secondAttribute="trailing" id="JEu-x6-qah"/>
<constraint firstItem="2bK-wq-6Rf" firstAttribute="bottom" secondItem="rd3-ei-B9P" secondAttribute="bottom" id="J9p-Wn-xC4"/>
<constraint firstItem="wfy-db-euE" firstAttribute="top" secondItem="EI2-CK-oqA" secondAttribute="bottom" id="JW8-WC-69E"/>
<constraint firstItem="19j-xT-Ttb" firstAttribute="top" secondItem="y3c-jy-aDJ" secondAttribute="bottom" id="K6V-FG-8Ms"/>
<constraint firstItem="wfy-db-euE" firstAttribute="top" secondItem="FSo-n8-ZwV" secondAttribute="bottom" constant="20" id="KgN-t9-iTh"/>
<constraint firstAttribute="trailing" secondItem="sT4-CC-oh5" secondAttribute="trailing" constant="16" id="Q92-5b-7Z7"/>
<constraint firstItem="yyS-3g-UqL" firstAttribute="top" secondItem="8bC-Xf-vdC" secondAttribute="top" id="SyJ-SX-ooI"/>
<constraint firstItem="EI2-CK-oqA" firstAttribute="top" secondItem="8bC-Xf-vdC" secondAttribute="top" id="Y9T-eB-SQS"/>
<constraint firstItem="2bK-wq-6Rf" firstAttribute="trailing" secondItem="rd3-ei-B9P" secondAttribute="trailing" id="add-TX-ds6"/>
<constraint firstItem="3WP-Xo-FaJ" firstAttribute="top" secondItem="y3c-jy-aDJ" secondAttribute="bottom" id="aur-kS-Ri3"/>
<constraint firstAttribute="centerX" secondItem="3WP-Xo-FaJ" secondAttribute="centerX" id="c8T-oR-vKi"/>
<constraint firstAttribute="trailing" secondItem="rd3-ei-B9P" secondAttribute="trailing" constant="40" id="dJE-jw-ZNY"/>
<constraint firstAttribute="centerX" secondItem="FSo-n8-ZwV" secondAttribute="centerX" id="dQf-Ne-km4"/>
<constraint firstItem="19j-xT-Ttb" firstAttribute="width" secondItem="sT4-CC-oh5" secondAttribute="width" id="dei-D3-qWh"/>
<constraint firstItem="sT4-CC-oh5" firstAttribute="top" secondItem="y3c-jy-aDJ" secondAttribute="bottom" id="i1Z-3m-ytG"/>
<constraint firstItem="FSo-n8-ZwV" firstAttribute="top" secondItem="rd3-ei-B9P" secondAttribute="bottom" constant="40" id="kF0-CG-srv"/>
<constraint firstAttribute="trailing" secondItem="EI2-CK-oqA" secondAttribute="trailing" id="m1R-4g-dGU"/>
<constraint firstItem="19j-xT-Ttb" firstAttribute="height" secondItem="sT4-CC-oh5" secondAttribute="height" id="mpG-Ir-vxB"/>
<constraint firstItem="rd3-ei-B9P" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" constant="40" id="n5z-dZ-b1l"/>
<constraint firstItem="19j-xT-Ttb" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" constant="16" id="uuM-vU-IPX"/>
<constraint firstItem="2bK-wq-6Rf" firstAttribute="leading" secondItem="rd3-ei-B9P" secondAttribute="leading" id="vNM-yq-5jd"/>
<constraint firstItem="rd3-ei-B9P" firstAttribute="top" secondItem="3WP-Xo-FaJ" secondAttribute="bottom" constant="40" id="wmQ-Ff-zje"/>
</constraints>
</view>
<navigationItem key="navigationItem" id="EiR-i7-mkA"/>
<nil key="simulatedTopBarMetrics"/>
<connections>
<outlet property="askForPermissionsButton" destination="rd3-ei-B9P" id="Itb-t1-HpD"/>
<outlet property="askForPermissionsLabel" destination="2bK-wq-6Rf" id="GdV-Gq-uSS"/>
<outlet property="cameraButton" destination="FSo-n8-ZwV" id="ITk-de-2LY"/>
<outlet property="cameraView" destination="EI2-CK-oqA" id="bUS-Rk-omr"/>
<outlet property="imageView" destination="yyS-3g-UqL" id="CZo-cW-NXH"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>

View File

@ -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

View File

@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string></string>
<string>com.imaginarycloud.cameraManager166784567676879</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>

View File

@ -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()
}
})
}
}