ios - 使用共享扩展将图像保存到文档文件夹
问题描述
我的目标(除了学习如何编写 iOS 应用程序扩展)是允许用户使用包括照片在内的各种应用程序的共享按钮共享图像并自动重命名它们。最后,我想将图像保存到应用程序的“文档”文件夹中以供进一步使用。
我在尝试使实际didSelectPost
部分正常工作时遇到了一些问题,因为与我见过的 Objective-C 示例不同,该loadItem
操作似乎返回 aNSURL
而不是UIImage
. 尝试将 NSUrl 复制到我的应用程序文档文件夹时,出现错误:
Error Domain=NSCocoaErrorDomain Code=260 "无法打开文件“IMG_0941.JPG”,因为没有这样的文件。" UserInfo={NSFilePath=file:///var/mobile/Media/PhotoData/OutgoingTemp/B79263E5-9512-4317-9C5D-817D7EBEFA9A/RenderedPhoto/IMG_0941.JPG, NSUnderlyingError=0x283f89080 {Error Domain=NSPOSIXErrorDomain Code=2“没有这个文件或目录"}}
当我在“照片”应用程序中按下照片上的分享按钮,点击我的扩展程序,然后按下“发布”按钮时,就会发生这种情况。
无论它是在模拟器还是真实设备中运行,我都会收到相同的错误。
到目前为止,这是我共同取得的进展:
override func didSelectPost() {
// This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments.
let inputItem = extensionContext?.inputItems.first as! NSExtensionItem
let attachment = inputItem.attachments!.first!
if attachment.hasItemConformingToTypeIdentifier(kUTTypeJPEG as String) {
attachment.loadItem(forTypeIdentifier: kUTTypeJPEG as String, options: nil) { data, error in
var image: UIImage?
if let someUrl = data as? NSURL {
do {
// a ends up being nil in both of these cases
let a = NSData(contentsOfFile: someUrl.absoluteString!)
image = UIImage(data: a as! Data)
// let a = try Data(contentsOf: someUrl)
// image = UIImage(contentsOfFile: someUrl.absoluteString)
} catch {
print(error)
}
} else if let someImage = data as? UIImage {
image = someImage
}
if let someImage = image {
guard let compressedImagePath = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first?.appendingPathComponent("theimage.jpg", isDirectory: false) else {
return
}
let compressedImageData = someImage.jpegData(compressionQuality: 1)
guard (try? compressedImageData?.write(to: compressedImagePath)) != nil else {
return
}
} else {
print("Bad share data")
}
}
}
// Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super's -didSelectPost, which will similarly complete the extension context.
self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
}
请注意,我将img
变量转换为NSURL
. 我试图将其转换为 a UIImage
,但这会引发异常。
我还有其他一些我想对图像做的事情,比如读取它的 EXIF 数据,但现在这就是我所拥有的。任何建议都会很棒,因为我真的很难绕开我的脑袋并学习这个环境。
我尝试过类似但不成功的帖子,请注意它们都是Objective-C:
[编辑]匹配更好答案之一的布局,仍然没有运气。
解决方案
我有同样的问题。我能够实施的解决方案:
- 获取图像的 URL。这个 URL 没用,因为我在尝试使用这个 URL 加载图像时遇到 260 错误。有趣的是,这是在最近的一些更新之后发生的,因为它之前有效
- 从此 URL 获取带扩展名的文件名
- 遍历用户照片库中的所有图像并从 ULR 中找到图像名称 == 名称
- 提取图像数据
- (void)didSelectPost {
for (NSItemProvider* itemProvider in ((NSExtensionItem*)self.extensionContext.inputItems[0]).attachments ) {
// get type of file extention (jpeg, file, url, png ...)
NSArray *registeredTypeIdentifiers = itemProvider.registeredTypeIdentifiers;
if ([itemProvider hasItemConformingToTypeIdentifier:registeredTypeIdentifiers.firstObject]) {
[itemProvider loadItemForTypeIdentifier:registeredTypeIdentifiers.firstObject options:nil completionHandler:^(id<NSSecureCoding> item, NSError *error) {
NSData *imgData;
NSString* imgPath = ((NSURL*) item).absoluteString;
if(imgPath == nil)
imgPath = [NSString stringWithFormat:@"%@", item];
NSCharacterSet* set = [NSCharacterSet URLHostAllowedCharacterSet];
NSString* imgPathEscaped = [imgPath stringByAddingPercentEncodingWithAllowedCharacters:set];
NSString* fileName = [imgPath lastPathComponent];
NSError* error2 = nil;
//try load from file path
__block NSData* data2 = [NSData dataWithContentsOfFile:imgPath options: NSDataReadingUncached error:&error2];
if(data2 == nil) //try load as URL
data2 = [NSData dataWithContentsOfURL:[NSURL URLWithString:imgPath] options: NSDataReadingUncached error:&error2];
if(data2 == nil) //all failed so try hacky way
{
NSString* searchFilename = [fileName lowercaseString];
PHFetchResult *results = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:nil];
[results enumerateObjectsUsingBlock:^(PHAsset *obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSArray* resources = [PHAssetResource assetResourcesForAsset:obj];
NSString* fileName2 = [NSString stringWithFormat:@"%@", ((PHAssetResource*)resources[0]).originalFilename].lowercaseString;
if ([fileName2 isEqual:searchFilename])
{
NSLog(@"found %@", fileName2);
PHImageManager* mgr = [PHImageManager defaultManager];
PHImageRequestOptions * options = [PHImageRequestOptions alloc];
options.synchronous = YES;
[mgr requestImageDataForAsset:obj options:options resultHandler:^(NSData * _Nullable imageData33, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info)
{
//imageData33 is your image
data2 = imageData33;
}];
}
}];
}
}];
}
}
// Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super's -didSelectPost, which will similarly complete the extension context.
[self.extensionContext completeRequestReturningItems:@[] completionHandler:nil];
}
推荐阅读
- python - 使用 Python 初始化和自定义 QML 组件
- firebase-authentication - AngularFire:如何仅在经过身份验证后访问 Firestore
- keras - 标记列中的单词并创建嵌入向量
- nlp - 词向量空间中的“线性子结构”是什么意思?
- angular - Angular Material Table 中仅显示 3 列
- python - python selenium - 我如何才能准确地找出警报发生的时间?
- xquery - MLCP 能否根据条件读取输入
- c++ - 如何在类的所有实例之间不共享的类方法中声明静态变量?
- amazon-ec2 - 如何解决错误Service role EMR_DefaultRole has enough EC2 permissions
- kubernetes - 如何从容器访问所有物理主机网络接口?