Developers / Open In
Open In
UIDocumentInteractionControllerforScore 10.4
On iOS and iPadOS, apps can allow users to share content in a variety of ways. To copy a single file to another app, UIDocumentInteractionController is commonly used. This class makes a user’s file available to any other apps on their device that support the same file type, and as such it’s often helpful to use popular formats whenever possible for maximum compatibility.
If a developer wants to share a file while also providing additional information about that file, they must generally do one of two things: embed that information into the file and rewrite it on disk before sharing it (if the file type can contain the kind of information they’re trying to send), or they can wrap the original file’s data into a custom format. The first option is resource-intensive and not always possible, while the second option significantly reduces compatibility with other apps.
iOS and iPadOS’ sharing protocols allow for a third way of transmitting this information, however, by using UIDocumentInteractionController’s annotation property to store a dictionary of keys and values. In forScore we adopt the following kinds of information if found:
Keyword | forScore Value | Format |
---|---|---|
title | Title | NSString |
composers | Composers | NSString (one or more comma-separated values) |
genres | Genres | |
tags | Tags | |
labels | Labels | |
rating | Rating | NSNumber or NSString representing a whole number between 0 and 5 |
difficulty | Difficulty | NSNumber or NSString representing a whole number between 0 and 3 |
duration | Duration | NSNumber or NSString representing a non-negative whole number (in seconds) |
keysf | Key | NSNumber or NSString representing a whole number between -7 and 7* |
keymi | NSNumber or NSString representing 0 (major) or 1 (minor)* |
*Key is stored as two MIDI-style values, learn more about these values here.
This method is perfect for sending sheet music to forScore. It allows apps to provide standard formats while also including helpful information—like a score’s duration—without permanently embedding that information into PDF metadata fields that weren’t designed for that purpose. The receiving app can take advantage of this information if desired, otherwise the user’s experience remains completely unchanged and compatibility is not diminished in any way.
Examples
Supplying Annotations
NSMutableDictionary *annotation = [[NSMutableDictionary alloc] init];
// Title may be provided, otherwise the filename (minus the .pdf extension) will be used
annotation[@"title"] = @"Nocturne Op. 90 № 2";
// These four keys can contain any number of comma-separated values as NSStrings
// Extra leading/trailing whitespace is trimmed automatically
annotation[@"composers"] = @"Frédéric Chopin";
annotation[@"genres"] = @"My Genre";
annotation[@"tags"] = @"My Tag";
annotation[@"labels"] = @"Label One, Label Two, Label Three";
// These values can be provided as NSNumbers or as digit-only NSStrings
annotation[@"difficulty"] = @(2); // between 0 and 3
annotation[@"rating"] = @(5); // between 0 and 5
// Provide duration as a whole number of seconds: n = (minutes*60)+seconds
// stored as either NSNumber or NSString
annotation[@"duration"] = @(72);
annotation[@"keysf"] = @(0); // follows MIDI formatting; -7 (flats) through +7 (sharps)
annotation[@"keymi"] = @(0); // follows MIDI formatting; 0=major, 1=minor
// This must be stored as an instance variable or it will be deallocated prematurely and not appear
documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:shareURL];
documentInteractionController.annotation = annotation;
// Present with a source view and rectangle; sender here is the button tapped to call this method
[documentInteractionController presentOpenInMenuFromRect:sender.frame inView:sender.superview animated:YES];
Reading Annotations
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options {
// Assuming here that the file is a PDF; a complete implementation
// should check if the URL's NSURLTypeIdentifierKey conforms to kUTTypePDF
// if possible or fall back on checking the url path's file extension
// import the file by copying or moving to your preferred location
[[NSFileManager defaultManager] moveItemAtURL:url toURL:myTargetURL error:nil];
// retrieve the annotation object and use it if it's present and in the format we expect
id obj = options[UIApplicationOpenURLOptionsAnnotationKey];
if ([obj isKindOfClass:[NSDictionary class]]) {
NSDictionary *dictionary = (NSDictionary *)obj;
NSString *title = dictionary[@"title"];
// continue retrieving desired values and save as needed
}
return YES;
}
Processing Comma-Separated Values (Composers, Genres, Tags, and Labels)
NSArray *componentArray = [dictionaryValue componentsSeparatedByString:@","];
NSCharacterSet *charSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
for (NSString *separatedValue in componentArray) {
NSString *cleanedValue = [separatedValue stringByTrimmingCharactersInSet:charSet];
// save this new value as needed
}
Processing Number Values (Rating, Difficulty, Duration, and Key)
// certain values may be either NSString or NSNumber objects
id durationObject = dictionary[@"duration"];
if (durationObject) {
NSInteger seconds = [durationObject integerValue];
// save as needed
}