I've got a custom file UTI attachment almost working in my App when sharing as a message. It embeds the file as an attachment with the correct file type of 'kitlist' in the message and is received on both iPads and iPhones. If you tap on the attachment from the normal message display nothing happens. However, if you tap on the info button at the top right corner and then choose Attachment, tap on the file and share this, the App appears as a possible destination. Choosing it will open the file successfully in my App. At the moment, choosing Mail as the share destination doesn't cause the attachment to appear in the email message; I don't know if this is relevant.I've also tried using sub-classing UIActivityItemProvider rather than implementing the protocol UIActivityItemSource sub-classing NSObject but with no difference. Airdropping to another iOS device works fine.
Here is the relevant fragment of my plist:
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeIconFiles</key>
<array/>
<key>CFBundleTypeName</key>
<string>KitList Transfer File Type</string>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>LSHandlerRank</key>
<string>Owner</string>
<key>LSItemContentTypes</key>
<array>
<string>co.SM.KitListFile.kitlist</string>
</array>
</dict>
</array>
<key>UTExportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>KitList Transfer File</string>
<key>UTTypeIdentifier</key>
<string>co.SM.KitListFile.kitlist</string>
<key>UTTypeSize320IconFile</key>
<string>BergenBig</string>
<key>UTTypeSize64IconFile</key>
<string>Bergen</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<string>kitlist</string>
</dict>
</dict>
</array>
The code to make the attachment is:
@interface SMCustomAttachmentTransfer()
@property (nonatomic, strong) NSMutableArray *images;
@end
@implementation SMCustomAttachmentTransfer
- (void)encodeWithCoder:(NSCoder *)aCoder
{
self.images = [NSMutableArray array];
[aCoder encodeObject:self.list forKey:@"list"];
[self walkTheList:[self.list valueForKey:keySubItems] withCoder:aCoder];
[aCoder encodeObject:self.images forKey:@"images"];
}
- (void)walkTheList:(NSDictionary *)items withCoder:(NSCoder *)aCoder
{
for (NSDictionary *item in items)
{
if ( [item valueForKey:keyDetailImage] )
{
[self.images addObject:[item valueForKey:keyDetailImage]];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *getImagePath = [documentsDirectory stringByAppendingPathComponent:[item valueForKey:keyDetailImage]];
[aCoder encodeObject:[NSData dataWithContentsOfFile:getImagePath] forKey:[item valueForKey:keyDetailImage]];
}
if ( [item valueForKey:keySubItems] )
{
[self walkTheList:[item valueForKey:keySubItems] withCoder:aCoder];
}
}
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self)
{
self.list = [aDecoder decodeObjectForKey:@"list"];
NSArray *images = [aDecoder decodeObjectForKey:@"images"];
for (NSString *image in images)
{
NSData *pngData = [aDecoder decodeObjectForKey:image];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
[pngData writeToFile:[documentsPath stringByAppendingPathComponent:image] atomically:YES];
}
}
return self;
}
- (id)activityViewControllerPlaceholderItem:(UIActivityViewController *)activityViewController
{
// must be data placeholder for attachment to be embedded in a message.
return [NSData data];
}
- (NSString *)activityViewController:(UIActivityViewController *)activityViewController subjectForActivityType:(NSString *)activityType
{
return [self.list valueForKey:keyName];
}
- (id)activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(UIActivityType)activityType
{
return [NSKeyedArchiver archivedDataWithRootObject:self];
}
- (NSString *)activityViewController:(UIActivityViewController *)activityViewController dataTypeIdentifierForActivityType:(NSString *)activityType
{
return @"co.SM.KitListFile.kitlist";
}
Update: This is how opening a custom attachment now works in iOS 15.6.
Touch the profile icon for the conversation. This either a picture or initials at the top of the screen. Scroll down to the attachments section. Open the attachment from there.