hotpocket/services/apple/Shared (Share Extension)/HPShareExtensionHelper.m

103 lines
4.8 KiB
Objective-C

//
// HPShareExtensionHelper.m
// HotPocket
//
// Created by Tomek Wójcik on 27/09/2025.
//
#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
#import "HPShareExtensionHelper.h"
#import "HPSharedItem.h"
#import "HPSharedItemsContainer.h"
@implementation HPShareExtensionHelper (HPShareExtensionHelperPrivate)
@end
@implementation HPShareExtensionHelper
-(instancetype)initWithContext:(NSExtensionContext *)context {
if (self = [super init]) {
self.context = context;
self.items = [[HPSharedItemsContainer alloc] init];
}
return self;
}
-(void)processItems:(HPShareExtensionHelperHandleItemsCompletionHandler)completionHandler {
// Depending on the app, the URL might be stored in `public.url` attachment or elsewhere.
// For example, the YouTube app passes it in `public.plain-text`. Because of course it does.
// Furthermore, for some bizarre reason the recommended way of extracting the URL when sharing from a browser
// is to run a JS snippet and examine its output.
// This method will iterate through all the shared items and their attachments and attempt to extract
// the URL candidates.
//
// Also note that handler for `public.url` explicitly requests the payload to be corced to `NSURL *`. Leaving it
// at `NSData *` would cause iOS to, wait for it!, fetch the URL and dump the response body in the payload :D.
//
// This is so _so_ *so* dumb. But hey, at least I learned how to to "chords" in CGD ¯\_(ツ)_/¯
UTType *propertyListType = [UTType typeWithFilenameExtension:@"plist"];
dispatch_group_t dispatchGroup = dispatch_group_create();
dispatch_queue_t queue = dispatch_queue_create("HPShareExtensionHelper.processItems.queue", DISPATCH_QUEUE_SERIAL);
for (NSExtensionItem *inputItem in self.context.inputItems) {
#ifdef DEBUG
NSLog(@"-[HPShareExtensionHelper processItems:] inputItem.userInfo=`%@`", inputItem);
#endif
[inputItem.attachments enumerateObjectsUsingBlock:^(NSItemProvider *attachment, NSUInteger index, BOOL *stop) {
dispatch_group_enter(dispatchGroup);
if ([attachment hasItemConformingToTypeIdentifier:propertyListType.identifier] == YES) {
[attachment loadItemForTypeIdentifier:propertyListType.identifier
options:nil
completionHandler:^(NSDictionary *payload, NSError *error) {
dispatch_async(queue, ^{
self.items.primaryItem = [[HPSharedItem alloc] initWithPayload:payload
typeIdentifier:propertyListType.identifier
error:error];
dispatch_group_leave(dispatchGroup);
});
}];
} else if ([attachment hasItemConformingToTypeIdentifier:@"public.url"] == YES) {
[attachment loadItemForTypeIdentifier:@"public.url"
options:nil
completionHandler:^(NSURL *payload, NSError *error) {
dispatch_async(queue, ^{
[self.items.candidateItems addObject:[[HPSharedItem alloc] initWithPayload:payload
typeIdentifier:@"public.url"
error:error]];
dispatch_group_leave(dispatchGroup);
});
}];
} else if ([attachment hasItemConformingToTypeIdentifier:@"public.plain-text"] == YES) {
[attachment loadItemForTypeIdentifier:@"public.plain-text"
options:nil
completionHandler:^(NSString *payload, NSError *error) {
dispatch_async(queue, ^{
[self.items.candidateItems addObject:[[HPSharedItem alloc] initWithPayload:payload
typeIdentifier:@"public.plain-text"
error:error]];
dispatch_group_leave(dispatchGroup);
});
}];
} else {
dispatch_group_leave(dispatchGroup);
}
}];
dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{
NSURL *result = [self.items resolveURL];
completionHandler(result);
});
}
}
@end