diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index b3222a68b4..4fc44cae01 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -32,6 +32,7 @@ #if HOCKEYSDK_FEATURE_FEEDBACK #import +#import #import "HockeySDKPrivate.h" @@ -55,6 +56,8 @@ NSString *const kBITFeedbackUpdateAttachmentThumbnail = @"BITFeedbackUpdateAttachmentThumbnail"; +typedef void (^BITLatestImageFetchCompletionBlock)(UIImage *latestImage); + @interface BITFeedbackManager() @property (nonatomic, strong) UITapGestureRecognizer *tapRecognizer; @@ -1153,25 +1156,83 @@ NSString *const kBITFeedbackUpdateAttachmentThumbnail = @"BITFeedbackUpdateAttac } -(void)extractLastPictureFromLibraryAndLaunchFeedback { - ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init]; + [self requestLatestImageWithCompletionHandler:^(UIImage *latestImage) { + [self showFeedbackComposeViewWithPreparedItems:@[latestImage]]; + }]; +} + +- (void)requestLatestImageWithCompletionHandler:(BITLatestImageFetchCompletionBlock)completionHandler { + if (!completionHandler) { return; } +// Only available from iOS 8 up + id phimagemanagerClass = NSClassFromString(@"PHImageManager"); + if (phimagemanagerClass) { + [self fetchLatestImageUsingPhotoLibraryWithCompletionHandler:completionHandler]; + } else { + [self fetchLatestImageUsingAssetsLibraryWithCompletionHandler:completionHandler]; + } +} + +- (void)fetchLatestImageUsingAssetsLibraryWithCompletionHandler:(BITLatestImageFetchCompletionBlock)completionHandler { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init]; [library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) { - - [group setAssetsFilter:[ALAssetsFilter allPhotos]]; - - [group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *alAsset, NSUInteger index, BOOL *innerStop) { + + [group setAssetsFilter:[ALAssetsFilter allPhotos]]; + + [group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *alAsset, NSUInteger index, BOOL *innerStop) { + + if (alAsset) { + ALAssetRepresentation *representation = [alAsset defaultRepresentation]; + UIImage *latestPhoto = [UIImage imageWithCGImage:[representation fullScreenImage]]; + + completionHandler(latestPhoto); + + *stop = YES; + *innerStop = YES; + } + }]; + } failureBlock: nil]; +#pragma clang diagnostic pop +} + +- (void)fetchLatestImageUsingPhotoLibraryWithCompletionHandler:(BITLatestImageFetchCompletionBlock)completionHandler { + [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { + if ((status == PHAuthorizationStatusDenied) || (status == PHAuthorizationStatusRestricted)) { + BITHockeyLog(@"INFO: The latest image could not be fetched, not permissions."); + completionHandler(nil); - if (alAsset) { - ALAssetRepresentation *representation = [alAsset defaultRepresentation]; - UIImage *latestPhoto = [UIImage imageWithCGImage:[representation fullScreenImage]]; - - *stop = YES; - *innerStop = YES; - - [self showFeedbackComposeViewWithPreparedItems:@[latestPhoto]]; + } else if (status == PHAuthorizationStatusAuthorized) { + + PHImageManager *imageManager = PHImageManager.defaultManager; + + PHFetchOptions *fetchOptions = [PHFetchOptions new]; + fetchOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]]; + + PHFetchResult *fetchResult = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:fetchOptions]; + + if (fetchResult.count > 0) { + PHAsset *latestImageAsset = (PHAsset *)fetchResult.lastObject; + if (latestImageAsset) { + PHImageRequestOptions *options = [PHImageRequestOptions new]; + options.version = PHImageRequestOptionsVersionCurrent; + options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat; + options.resizeMode = PHImageRequestOptionsResizeModeNone; + + [imageManager requestImageDataForAsset:latestImageAsset options:options resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) { + if (imageData) { + completionHandler([UIImage imageWithData:imageData]); + return; + } + }]; + } + } else { + BITHockeyLog(@"INFO: The latest image could not be fetched, the fetch result was empty."); } - }]; - } failureBlock: nil]; + completionHandler(nil); + } + }]; } - (void)screenshotTripleTap:(UITapGestureRecognizer *)tapRecognizer { diff --git a/HockeySDK-Source.podspec b/HockeySDK-Source.podspec index 6c7d4cec58..ae92372c70 100644 --- a/HockeySDK-Source.podspec +++ b/HockeySDK-Source.podspec @@ -22,7 +22,7 @@ Pod::Spec.new do |s| s.source_files = 'Classes' s.requires_arc = true - s.frameworks = 'AssetsLibrary', 'CoreGraphics', 'CoreTelephony', 'CoreText', 'MobileCoreServices', 'QuartzCore', 'QuickLook', 'Security', 'SystemConfiguration', 'UIKit' + s.frameworks = 'AssetsLibrary', 'CoreGraphics', 'CoreTelephony', 'CoreText', 'MobileCoreServices', 'Photos', 'QuartzCore', 'QuickLook', 'Security', 'SystemConfiguration', 'UIKit' s.libraries = 'c++', 'z' s.ios.vendored_frameworks = 'Vendor/CrashReporter.framework' s.pod_target_xcconfig = {'GCC_PREPROCESSOR_DEFINITIONS' => %{$(inherited) BITHOCKEY_VERSION="@\\"#{s.version}\\"" BITHOCKEY_C_VERSION="\\"#{s.version}\\"" BITHOCKEY_BUILD="@\\"51\\"" BITHOCKEY_C_BUILD="\\"51\\""} } diff --git a/HockeySDK.podspec b/HockeySDK.podspec index 2aa223ccd3..8e7a073fc2 100644 --- a/HockeySDK.podspec +++ b/HockeySDK.podspec @@ -42,7 +42,7 @@ Pod::Spec.new do |s| s.subspec 'AllFeaturesLib' do |ss| ss.resource_bundle = { 'HockeySDKResources' => ['HockeySDK-iOS/HockeySDK.embeddedframework/HockeySDK.framework/Versions/A/Resources/HockeySDKResources.bundle/*.png', 'HockeySDK-iOS/HockeySDK.embeddedframework/HockeySDK.framework/Versions/A/Resources/HockeySDKResources.bundle/*.lproj'] } - ss.frameworks = 'AssetsLibrary', 'CoreGraphics', 'CoreText', 'CoreTelephony', 'MobileCoreServices', 'QuartzCore', 'QuickLook', 'UIKit' + ss.frameworks = 'AssetsLibrary', 'CoreGraphics', 'CoreText', 'CoreTelephony', 'MobileCoreServices', 'Photos,'QuartzCore', 'QuickLook', 'UIKit' ss.libraries = 'z' ss.vendored_frameworks = 'HockeySDK-iOS/HockeySDK.embeddedframework/HockeySDK.framework' end diff --git a/README.md b/README.md index a9af63d60b..c69eb8d85d 100644 --- a/README.md +++ b/README.md @@ -148,10 +148,12 @@ If you are working with an older project which doesn't support clang modules yet + `MobileCoreServices` + `QuartzCore` + `QuickLook` + + `Photos` + `Security` + `SystemConfiguration` + `UIKit` + `libc++` + + `libz` 2. Crash reporting only: + `Foundation` + `Security` diff --git a/Support/HockeySDK.xcconfig b/Support/HockeySDK.xcconfig index 399cc5c8ad..3b76709d85 100644 --- a/Support/HockeySDK.xcconfig +++ b/Support/HockeySDK.xcconfig @@ -1,3 +1,3 @@ -OTHER_LDFLAGS=$(inherited) -framework CrashReporter -framework CoreTelephony -framework CoreText -framework CoreGraphics -framework Foundation -framework QuartzCore -framework SystemConfiguration -framework UIKit -framework Security -framework AssetsLibrary -framework MobileCoreServices -framework QuickLook -lc++ -lz +OTHER_LDFLAGS=$(inherited) -framework CrashReporter -framework AssetsLibrary -framework CoreTelephony -framework CoreText -framework CoreGraphics -framework Foundation -framework MobileCoreServices -framework Photos -framework QuartzCore -framework QuickLook -framework Security -framework SystemConfiguration -framework UIKit -lc++ -lz HOCKEYSDK_DOCSET_NAME=HockeySDK-iOS GCC_PREPROCESSOR_DEFINITIONS=$(inherited) CONFIGURATION_$(CONFIGURATION) diff --git a/Support/module.modulemap b/Support/module.modulemap index ff2e41f468..25943023a4 100644 --- a/Support/module.modulemap +++ b/Support/module.modulemap @@ -10,6 +10,7 @@ framework module HockeySDK { link framework "CoreGraphics" link framework "Foundation" link framework "MobileCoreServices" + link framework "Photos" link framework "QuartzCore" link framework "QuickLook" link framework "Security" diff --git a/docs/Guide-Installation-Setup-template.md b/docs/Guide-Installation-Setup-template.md index a69ca0d83a..fab85ebff5 100644 --- a/docs/Guide-Installation-Setup-template.md +++ b/docs/Guide-Installation-Setup-template.md @@ -130,12 +130,14 @@ If you are working with an older project which doesn't support clang modules yet + `CoreGraphics` + `Foundation` + `MobileCoreServices` + + `Photos` + `QuartzCore` + `QuickLook` + `Security` + `SystemConfiguration` + `UIKit` + `libc++` + + `libz` 2. Crash reporting only: + `Foundation` + `Security`