From 9e575d2e5b58d5cdac0dca7aa68fdaa2f2176e86 Mon Sep 17 00:00:00 2001 From: Adam Law <> Date: Tue, 16 Feb 2021 17:57:35 +0000 Subject: [PATCH] Fixes for App Store submission warning -"ITMS-90683: Missing Purpose String in Info.plist" * Added compiler flag `GALLERY_USE_LOCATION` which is used to partition usage of `CoreLocation`. If the flag isn't set then the option within `Camera` to record the location is not available. * This change forces consumers of the framework to define `GALLERY_USE_LOCATION` should they wish to compliment photos with location information. * By introducing this compiler flag we're able to conditionally remove dependencies on `CoreLocation` when we're not interested in using location information. This in turn avoids the needles requirement to set a `NSLocationWhenInUseUsageDescription` key in the Apps plist file regardless. * By having a better way to address this warning this will avoid future App Store rejections when Apple make the inclusion of a `NSLocationWhenInUseUsageDescription` string mandatory when using `CoreLocation`. * Up-versioned to `2.5.0` as this will be a breaking change for consumers using the `recordLocation` property on `Camera`. * Updated `README.md` --- Gallery.podspec | 2 +- Gallery.xcodeproj/project.pbxproj | 24 +++++++++++++++---- README.md | 23 ++++++++++++++++++ Sources/Gallery/Camera/CameraController.swift | 7 ++++-- Sources/Gallery/Camera/CameraMan.swift | 14 +++++------ Sources/Gallery/Utils/Config.swift | 2 ++ .../{ => Location}/LocationManager.swift | 11 ++++++--- .../Utils/Location/LocationManaging.swift | 6 +++++ .../Utils/Location/LocationProviding.swift | 15 ++++++++++++ 9 files changed, 87 insertions(+), 17 deletions(-) rename Sources/Gallery/Utils/{ => Location}/LocationManager.swift (74%) create mode 100644 Sources/Gallery/Utils/Location/LocationManaging.swift create mode 100644 Sources/Gallery/Utils/Location/LocationProviding.swift diff --git a/Gallery.podspec b/Gallery.podspec index 0100c191..d09466f8 100644 --- a/Gallery.podspec +++ b/Gallery.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "Gallery" s.summary = "Something good about gallery" - s.version = "2.4.0" + s.version = "2.5.0" s.homepage = "https://github.com/hyperoslo/Gallery" s.license = 'MIT' s.author = { "Hyper Interaktiv AS" => "ios@hyper.no" } diff --git a/Gallery.xcodeproj/project.pbxproj b/Gallery.xcodeproj/project.pbxproj index f21d7731..60842ce8 100644 --- a/Gallery.xcodeproj/project.pbxproj +++ b/Gallery.xcodeproj/project.pbxproj @@ -56,9 +56,11 @@ 3605647F25837D3F00B9F493 /* Permission.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3605644A25837D3F00B9F493 /* Permission.swift */; }; 3605648025837D3F00B9F493 /* PermissionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3605644B25837D3F00B9F493 /* PermissionView.swift */; }; 3605648125837D3F00B9F493 /* PermissionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3605644C25837D3F00B9F493 /* PermissionController.swift */; }; - 3605648225837D3F00B9F493 /* LocationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3605644D25837D3F00B9F493 /* LocationManager.swift */; }; 3605648325837D3F00B9F493 /* PagesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3605644F25837D3F00B9F493 /* PagesController.swift */; }; 3605648425837D3F00B9F493 /* PageIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3605645025837D3F00B9F493 /* PageIndicator.swift */; }; + 5346BEF825DC00D7008494CE /* LocationProviding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5346BEF425DC00D7008494CE /* LocationProviding.swift */; }; + 5346BEFA25DC00D7008494CE /* LocationManaging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5346BEF625DC00D7008494CE /* LocationManaging.swift */; }; + 5346BEFB25DC00D7008494CE /* LocationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5346BEF725DC00D7008494CE /* LocationManager.swift */; }; D27B72ED1D6EEEC80093318F /* Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27B72EC1D6EEEC80093318F /* Tests.swift */; }; D2D1A6F41F84F4DB0083D4C5 /* GalleryController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D1A6C31F84F4DB0083D4C5 /* GalleryController.swift */; }; D5B2E8AA1C3A780C00C0327D /* Gallery.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D5B2E89F1C3A780C00C0327D /* Gallery.framework */; }; @@ -124,9 +126,11 @@ 3605644A25837D3F00B9F493 /* Permission.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Permission.swift; sourceTree = ""; }; 3605644B25837D3F00B9F493 /* PermissionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PermissionView.swift; sourceTree = ""; }; 3605644C25837D3F00B9F493 /* PermissionController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PermissionController.swift; sourceTree = ""; }; - 3605644D25837D3F00B9F493 /* LocationManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationManager.swift; sourceTree = ""; }; 3605644F25837D3F00B9F493 /* PagesController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PagesController.swift; sourceTree = ""; }; 3605645025837D3F00B9F493 /* PageIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PageIndicator.swift; sourceTree = ""; }; + 5346BEF425DC00D7008494CE /* LocationProviding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationProviding.swift; sourceTree = ""; }; + 5346BEF625DC00D7008494CE /* LocationManaging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationManaging.swift; sourceTree = ""; }; + 5346BEF725DC00D7008494CE /* LocationManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationManager.swift; sourceTree = ""; }; D27B72EC1D6EEEC80093318F /* Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Tests.swift; sourceTree = ""; }; D27B730C1D6EF04D0093318F /* Cartography.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cartography.framework; path = Carthage/Build/iOS/Cartography.framework; sourceTree = ""; }; D2D1A6C31F84F4DB0083D4C5 /* GalleryController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GalleryController.swift; sourceTree = ""; }; @@ -228,8 +232,8 @@ 3605644625837D3F00B9F493 /* Fetcher.swift */, 3605644725837D3F00B9F493 /* Utils.swift */, 3605644825837D3F00B9F493 /* OrientationMan.swift */, + 5346BEF325DC00D7008494CE /* Location */, 3605644925837D3F00B9F493 /* Permission */, - 3605644D25837D3F00B9F493 /* LocationManager.swift */, 3605644E25837D3F00B9F493 /* Pages */, ); path = Utils; @@ -299,6 +303,16 @@ path = Pages; sourceTree = ""; }; + 5346BEF325DC00D7008494CE /* Location */ = { + isa = PBXGroup; + children = ( + 5346BEF425DC00D7008494CE /* LocationProviding.swift */, + 5346BEF625DC00D7008494CE /* LocationManaging.swift */, + 5346BEF725DC00D7008494CE /* LocationManager.swift */, + ); + path = Location; + sourceTree = ""; + }; D27B730E1D6EF0640093318F /* Frameworks */ = { isa = PBXGroup; children = ( @@ -481,9 +495,9 @@ files = ( 3605647B25837D3F00B9F493 /* GridView.swift in Sources */, 3605647C25837D3F00B9F493 /* Fetcher.swift in Sources */, - 3605648225837D3F00B9F493 /* LocationManager.swift in Sources */, 3605646725837D3F00B9F493 /* DropdownController.swift in Sources */, 3605648425837D3F00B9F493 /* PageIndicator.swift in Sources */, + 5346BEF825DC00D7008494CE /* LocationProviding.swift in Sources */, 3605648025837D3F00B9F493 /* PermissionView.swift in Sources */, 3605647725837D3F00B9F493 /* EmptyView.swift in Sources */, 3605646B25837D3F00B9F493 /* VideoEditor.swift in Sources */, @@ -519,6 +533,7 @@ 3605647125837D3F00B9F493 /* UIImageView+Extensions.swift in Sources */, 3605646225837D3F00B9F493 /* ImageCell.swift in Sources */, 3605645425837D3F00B9F493 /* VideoBox.swift in Sources */, + 5346BEFA25DC00D7008494CE /* LocationManaging.swift in Sources */, 3605646125837D3F00B9F493 /* Cart.swift in Sources */, 3605646525837D3F00B9F493 /* UIBlurEffect+Style.swift in Sources */, 3605648325837D3F00B9F493 /* PagesController.swift in Sources */, @@ -528,6 +543,7 @@ 3605647925837D3F00B9F493 /* AlbumCell.swift in Sources */, 3605647A25837D3F00B9F493 /* ArrowButton.swift in Sources */, 3605645A25837D3F00B9F493 /* CameraMan.swift in Sources */, + 5346BEFB25DC00D7008494CE /* LocationManager.swift in Sources */, 3605645825837D3F00B9F493 /* CameraController.swift in Sources */, 3605645225837D3F00B9F493 /* VideosLibrary.swift in Sources */, 3605647625837D3F00B9F493 /* UIScrollView+Extensions.swift in Sources */, diff --git a/README.md b/README.md index 8e50ac8c..4b553f49 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ The delegate methods give you `Image` and `Video`, which are just wrappers aroun `Gallery` handles permissions for you. It checks and askes for photo and camera usage permissions at first launch. As of iOS 10, we need to explicitly declare usage descriptions in plist files +### Madatory ```xml NSCameraUsageDescription This app requires access to camera @@ -71,6 +72,14 @@ The delegate methods give you `Image` and `Video`, which are just wrappers aroun This app requires access to photo library ``` +### Optional +If defining the `GALLERY_USE_LOCATION` compiler flag for the purposes of recording location information then the following usage string is required: + +```xml +NSLocationWhenInUseUsageDescription +This app requires location when in use +``` + ### Configuration There are lots of customization points in `Config` structs. For example @@ -82,6 +91,20 @@ Config.Camera.recordLocation = true Config.tabsToShow = [.imageTab, .cameraTab] ``` +Note: When utilising the `recordLocation` property, `GALLERY_USE_LOCATION` needs defining first in order to expose this functionality. If using Cocoapods this can be done with the usage of post install hook as follows: + +```ruby +post_install do |installer| + installer.pods_project.targets.each do |target| + if target.name == 'Gallery' + target.build_configurations.each do |config| + config.build_settings['OTHER_SWIFT_FLAGS'] = '-DGALLERY_USE_LOCATION' + end + end + end +end +``` + ### Video Editor `Gallery` cares more about video with its editing functionalities. We have `VideoEditor` and `AdvancedVideoEditor` to trim, resize, scale and define quality of the selected video diff --git a/Sources/Gallery/Camera/CameraController.swift b/Sources/Gallery/Camera/CameraController.swift index a89bda95..3c255154 100644 --- a/Sources/Gallery/Camera/CameraController.swift +++ b/Sources/Gallery/Camera/CameraController.swift @@ -3,7 +3,7 @@ import AVFoundation class CameraController: UIViewController { - var locationManager: LocationManager? + var locationManager: LocationManaging? lazy var cameraMan: CameraMan = self.makeCameraMan() lazy var cameraView: CameraView = self.makeCameraView() let once = Once() @@ -68,9 +68,11 @@ class CameraController: UIViewController { } func setupLocation() { + #if GALLERY_USE_LOCATION if Config.Camera.recordLocation { locationManager = LocationManager() } + #endif } // MARK: - Action @@ -117,7 +119,8 @@ class CameraController: UIViewController { }) self.cameraView.stackView.startLoading() - cameraMan.takePhoto(previewLayer, location: locationManager?.latestLocation) { [weak self] asset in + + self.cameraMan.takePhoto(previewLayer, locationProvider: locationManager?.latestLocationProvider) { [weak self] asset in guard let strongSelf = self else { return } diff --git a/Sources/Gallery/Camera/CameraMan.swift b/Sources/Gallery/Camera/CameraMan.swift index 46af5e1b..99676a4d 100644 --- a/Sources/Gallery/Camera/CameraMan.swift +++ b/Sources/Gallery/Camera/CameraMan.swift @@ -15,7 +15,6 @@ class CameraMan { let session = AVCaptureSession() let queue = DispatchQueue(label: "no.hyper.Gallery.Camera.SessionQueue", qos: .background) let savingQueue = DispatchQueue(label: "no.hyper.Gallery.Camera.SavingQueue", qos: .background) - let orientationMan = OrientationMan() var backCamera: AVCaptureDeviceInput? var frontCamera: AVCaptureDeviceInput? @@ -127,11 +126,10 @@ class CameraMan { } } - func takePhoto(_ previewLayer: AVCaptureVideoPreviewLayer, location: CLLocation?, completion: @escaping ((PHAsset?) -> Void)) { + func takePhoto(_ previewLayer: AVCaptureVideoPreviewLayer, locationProvider: LocationProviding?, completion: @escaping ((PHAsset?) -> Void)) { guard let connection = stillImageOutput?.connection(with: .video) else { return } - // It should be set the image orientation with the device current orientation - connection.videoOrientation = self.orientationMan.videoOrientation() + connection.videoOrientation = Utils.videoOrientation() queue.async { self.stillImageOutput?.captureStillImageAsynchronously(from: connection) { @@ -147,12 +145,12 @@ class CameraMan { return } - self.savePhoto(image, location: location, completion: completion) + self.savePhoto(image, locationProvider: locationProvider, completion: completion) } } } - func savePhoto(_ image: UIImage, location: CLLocation?, completion: @escaping ((PHAsset?) -> Void)) { + func savePhoto(_ image: UIImage, locationProvider: LocationProviding?, completion: @escaping ((PHAsset?) -> Void)) { var localIdentifier: String? savingQueue.async { @@ -162,7 +160,9 @@ class CameraMan { localIdentifier = request.placeholderForCreatedAsset?.localIdentifier request.creationDate = Date() - request.location = location + #if GALLERY_USE_LOCATION + request.location = locationProvider?.location + #endif } DispatchQueue.main.async { diff --git a/Sources/Gallery/Utils/Config.swift b/Sources/Gallery/Utils/Config.swift index 081f41e1..095d20d0 100644 --- a/Sources/Gallery/Utils/Config.swift +++ b/Sources/Gallery/Utils/Config.swift @@ -39,7 +39,9 @@ public struct Config { public struct Camera { + #if GALLERY_USE_LOCATION public static var recordLocation: Bool = false + #endif public struct ShutterButton { public static var numberColor: UIColor = UIColor(red: 54/255, green: 56/255, blue: 62/255, alpha: 1) diff --git a/Sources/Gallery/Utils/LocationManager.swift b/Sources/Gallery/Utils/Location/LocationManager.swift similarity index 74% rename from Sources/Gallery/Utils/LocationManager.swift rename to Sources/Gallery/Utils/Location/LocationManager.swift index dae86fb0..30dadaf9 100644 --- a/Sources/Gallery/Utils/LocationManager.swift +++ b/Sources/Gallery/Utils/Location/LocationManager.swift @@ -1,9 +1,10 @@ +#if GALLERY_USE_LOCATION import Foundation import CoreLocation -class LocationManager: NSObject, CLLocationManagerDelegate { +class LocationManager: NSObject, LocationManaging, CLLocationManagerDelegate { var locationManager = CLLocationManager() - var latestLocation: CLLocation? + var latestLocationProvider: LocationProviding? override init() { super.init() @@ -24,7 +25,9 @@ class LocationManager: NSObject, CLLocationManagerDelegate { func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { // Pick the location with best (= smallest value) horizontal accuracy - latestLocation = locations.sorted { $0.horizontalAccuracy < $1.horizontalAccuracy }.first + if let location = locations.sorted { $0.horizontalAccuracy < $1.horizontalAccuracy }.first { + latestLocationProvider = LocationProvider(location: location) + } } func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { @@ -35,3 +38,5 @@ class LocationManager: NSObject, CLLocationManagerDelegate { } } } + +#endif diff --git a/Sources/Gallery/Utils/Location/LocationManaging.swift b/Sources/Gallery/Utils/Location/LocationManaging.swift new file mode 100644 index 00000000..298a5cb6 --- /dev/null +++ b/Sources/Gallery/Utils/Location/LocationManaging.swift @@ -0,0 +1,6 @@ +protocol LocationManaging { + + func start() + func stop() + var latestLocationProvider: LocationProviding? { get } +} diff --git a/Sources/Gallery/Utils/Location/LocationProviding.swift b/Sources/Gallery/Utils/Location/LocationProviding.swift new file mode 100644 index 00000000..794f4784 --- /dev/null +++ b/Sources/Gallery/Utils/Location/LocationProviding.swift @@ -0,0 +1,15 @@ +#if GALLERY_USE_LOCATION +import CoreLocation +#endif + +protocol LocationProviding { + #if GALLERY_USE_LOCATION + var location: CLLocation { get } + #endif +} + +struct LocationProvider: LocationProviding { + #if GALLERY_USE_LOCATION + let location: CLLocation + #endif +}