iOS10 UIImageWriteToSavedPhotosAlbum TCC__CRASHING_DUE_TO_PRIVACY_VIOLATION
iOS10 UIImageWriteToSavedPhotosAlbum TCC__CRASHING_DUE_TO_PRIVACY_VIOLATION
我想在 iOS10 中创建并保存一个 UIImage
。我可以通过拍摄 UIView
快照或使用 UIGraphicsImageRenderer
(如下所示)。
- (UIView *)createIcon
{
UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:CGSizeMake(200, 200)];
UIImage *image = [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull context) {
[[UIColor darkGrayColor] setStroke];
[context strokeRect:renderer.format.bounds];
[[UIColor colorWithRed:158/255.0 green:215/255.0 blue:245/255.0 alpha:0.5] setFill];
[context fillRect:CGRectMake(30, 30, 140, 140)];
[[UIColor colorWithRed:243/255.0 green:122/255.0 blue:216/255.0 alpha:0.3] setFill];
CGContextFillEllipseInRect(context.CGContext, CGRectMake(30, 30, 120, 120));
}];
UIImageView *showImage = [[UIImageView alloc] initWithImage:image];
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
return showImage;
}
但是,当我尝试通过包含倒数第二个语句使用 UIImageWriteToSavedPhotosAlbum
进行保存时,Xcode 进入调试并显示以下错误报告
(lldb) bt
* thread #5, queue = 'com.apple.root.default-qos', stop reason = signal SIGABRT
* frame #0: 0x00000001101611a6 libsystem_kernel.dylib`__abort_with_payload + 10
frame #1: 0x000000011015b86e libsystem_kernel.dylib`abort_with_payload_wrapper_internal + 89
frame #2: 0x000000011015b89b libsystem_kernel.dylib`abort_with_payload + 9
frame #3: 0x0000000108ab3af7 TCC`__CRASHING_DUE_TO_PRIVACY_VIOLATION__ + 182
frame #4: 0x0000000108ab3a41 TCC`__TCCAccessRequest_block_invoke.77 + 665
frame #5: 0x0000000108ab7273 TCC`__tccd_send_block_invoke + 274
所以虽然不是用相机拍的,但是存到相册里是侵犯隐私的行为(嘘,嘘)!我知道可以设置 但是否有更明智的选择?
澄清
我希望将渲染图像(或视图快照)用作应用程序中的资产。那么,除了 ,还有更明智的选择吗?
也许我应该问
是否有其他地方可以保存图像(即保存为 PNG 或 JPG 文件)以便隐私不成问题?
您可以将任何 UIImage 保存到相册,但首先您必须征得用户的同意才能这样做,因为这确实是一个隐私问题。如果他们不给你访问权限,那么你根本无法保存图像。
最明智的方法是将所需的私钥添加到 info.plist。
这是 info.plist xml 定义,尽管在 属性 列表中添加键更容易:
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Message requesting the ability to add to the photo library</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Message requestion the ability to access the photo library</string>
如果您添加这些,那么当您第一次尝试访问或添加到照片库时,将显示一个弹出窗口,其中包含您的消息,允许用户决定他们是否希望您的应用程序具有访问权限。
将它放在 info.plist 文件中的一个很好的理由是所有访问请求都在一个容易看到的地方,而不是项目中随机的地方。
编辑
以下是如何在不引起隐私问题的文档中保存图像:
NSData *imageData = UIImagePNGRepresentation(image);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0]; //Get the docs directory
NSString *filePath = [documentsPath stringByAppendingPathComponent:@"image.png"]; //Add the file name
[imageData writeToFile:filePath atomically:YES]; //Write the file
如果您想要 jpg 而不是 png,请改用此格式:
NSData *imageData = UIImageJPEGRepresentation(image, 0.9); // Use whatever compression ratio you want instead of 0.9
遵循此代码:
#import <Photos/Photos.h>
pragma mark - 在相册中保存图片
- (void)addImageToCameraRoll:(UIImage *)image {
NSString *albumName = @"Your app name";
void (^saveBlock)(PHAssetCollection *assetCollection) = ^void(PHAssetCollection *assetCollection) {
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetChangeRequest *assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
PHAssetCollectionChangeRequest *assetCollectionChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:assetCollection];
[assetCollectionChangeRequest addAssets:@[[assetChangeRequest placeholderForCreatedAsset]]];
} completionHandler:^(BOOL success, NSError *error) {
if (!success) {
NSLog(@"Error creating asset: %@", error);
}
}];
};
PHFetchOptions *fetchOptions = [[PHFetchOptions alloc] init];
fetchOptions.predicate = [NSPredicate predicateWithFormat:@"localizedTitle = %@", albumName];
PHFetchResult *fetchResult = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAny options:fetchOptions];
if (fetchResult.count > 0) {
saveBlock(fetchResult.firstObject);
} else {
__block PHObjectPlaceholder *albumPlaceholder;
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetCollectionChangeRequest *changeRequest = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:albumName];
albumPlaceholder = changeRequest.placeholderForCreatedAssetCollection;
} completionHandler:^(BOOL success, NSError *error) {
if (success) {
PHFetchResult *fetchResult = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[albumPlaceholder.localIdentifier] options:nil];
if (fetchResult.count > 0) {
saveBlock(fetchResult.firstObject);
}
} else {
NSLog(@"Error creating album: %@", error);
}
}];
}
}
我想在 iOS10 中创建并保存一个 UIImage
。我可以通过拍摄 UIView
快照或使用 UIGraphicsImageRenderer
(如下所示)。
- (UIView *)createIcon
{
UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:CGSizeMake(200, 200)];
UIImage *image = [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull context) {
[[UIColor darkGrayColor] setStroke];
[context strokeRect:renderer.format.bounds];
[[UIColor colorWithRed:158/255.0 green:215/255.0 blue:245/255.0 alpha:0.5] setFill];
[context fillRect:CGRectMake(30, 30, 140, 140)];
[[UIColor colorWithRed:243/255.0 green:122/255.0 blue:216/255.0 alpha:0.3] setFill];
CGContextFillEllipseInRect(context.CGContext, CGRectMake(30, 30, 120, 120));
}];
UIImageView *showImage = [[UIImageView alloc] initWithImage:image];
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
return showImage;
}
但是,当我尝试通过包含倒数第二个语句使用 UIImageWriteToSavedPhotosAlbum
进行保存时,Xcode 进入调试并显示以下错误报告
(lldb) bt
* thread #5, queue = 'com.apple.root.default-qos', stop reason = signal SIGABRT
* frame #0: 0x00000001101611a6 libsystem_kernel.dylib`__abort_with_payload + 10
frame #1: 0x000000011015b86e libsystem_kernel.dylib`abort_with_payload_wrapper_internal + 89
frame #2: 0x000000011015b89b libsystem_kernel.dylib`abort_with_payload + 9
frame #3: 0x0000000108ab3af7 TCC`__CRASHING_DUE_TO_PRIVACY_VIOLATION__ + 182
frame #4: 0x0000000108ab3a41 TCC`__TCCAccessRequest_block_invoke.77 + 665
frame #5: 0x0000000108ab7273 TCC`__tccd_send_block_invoke + 274
所以虽然不是用相机拍的,但是存到相册里是侵犯隐私的行为(嘘,嘘)!我知道可以设置
澄清
我希望将渲染图像(或视图快照)用作应用程序中的资产。那么,除了 ,还有更明智的选择吗?
也许我应该问
是否有其他地方可以保存图像(即保存为 PNG 或 JPG 文件)以便隐私不成问题?
您可以将任何 UIImage 保存到相册,但首先您必须征得用户的同意才能这样做,因为这确实是一个隐私问题。如果他们不给你访问权限,那么你根本无法保存图像。
最明智的方法是将所需的私钥添加到 info.plist。
这是 info.plist xml 定义,尽管在 属性 列表中添加键更容易:
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Message requesting the ability to add to the photo library</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Message requestion the ability to access the photo library</string>
如果您添加这些,那么当您第一次尝试访问或添加到照片库时,将显示一个弹出窗口,其中包含您的消息,允许用户决定他们是否希望您的应用程序具有访问权限。
将它放在 info.plist 文件中的一个很好的理由是所有访问请求都在一个容易看到的地方,而不是项目中随机的地方。
编辑
以下是如何在不引起隐私问题的文档中保存图像:
NSData *imageData = UIImagePNGRepresentation(image);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0]; //Get the docs directory
NSString *filePath = [documentsPath stringByAppendingPathComponent:@"image.png"]; //Add the file name
[imageData writeToFile:filePath atomically:YES]; //Write the file
如果您想要 jpg 而不是 png,请改用此格式:
NSData *imageData = UIImageJPEGRepresentation(image, 0.9); // Use whatever compression ratio you want instead of 0.9
遵循此代码:
#import <Photos/Photos.h>
pragma mark - 在相册中保存图片
- (void)addImageToCameraRoll:(UIImage *)image {
NSString *albumName = @"Your app name";
void (^saveBlock)(PHAssetCollection *assetCollection) = ^void(PHAssetCollection *assetCollection) {
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetChangeRequest *assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
PHAssetCollectionChangeRequest *assetCollectionChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:assetCollection];
[assetCollectionChangeRequest addAssets:@[[assetChangeRequest placeholderForCreatedAsset]]];
} completionHandler:^(BOOL success, NSError *error) {
if (!success) {
NSLog(@"Error creating asset: %@", error);
}
}];
};
PHFetchOptions *fetchOptions = [[PHFetchOptions alloc] init];
fetchOptions.predicate = [NSPredicate predicateWithFormat:@"localizedTitle = %@", albumName];
PHFetchResult *fetchResult = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAny options:fetchOptions];
if (fetchResult.count > 0) {
saveBlock(fetchResult.firstObject);
} else {
__block PHObjectPlaceholder *albumPlaceholder;
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetCollectionChangeRequest *changeRequest = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:albumName];
albumPlaceholder = changeRequest.placeholderForCreatedAssetCollection;
} completionHandler:^(BOOL success, NSError *error) {
if (success) {
PHFetchResult *fetchResult = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[albumPlaceholder.localIdentifier] options:nil];
if (fetchResult.count > 0) {
saveBlock(fetchResult.firstObject);
}
} else {
NSLog(@"Error creating album: %@", error);
}
}];
}
}