Eine iOS-Anwendung kann eine Datei an eine andere App übergeben, z.B. damit diese angezeigt oder anderweitig verarbeitet wird. Die Datei wird dabei allerdings kopiert, weil iOS es nicht erlaubt, dass sich Apps Ressourcen teilen.
Hier ist ein Beispiel, wie es geht:
@interface ViewController ()
@property (nonatomic, copy) NSURL *URL;
@property (nonatomic, strong) UIDocumentInteractionController *dic;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.dic = [UIDocumentInteractionController interactionControllerWithURL:self.URL];
}
- (IBAction)openIn:(UIButton *)sender {
if (![self.dic presentOpenInMenuFromRect:sender.bounds inView:sender animated:YES]) {
NSLog(@"No apps installed to display %@", self.dic.URL);
}
}
@end
Ich initialisiere einen UIDocumentInteractionController
mit einem NSURL
-Objekt, welches die zu übergebende Datei repräsentiert. Ich muss mir den Controller merken, da er länger leben muss, als die Methode, in der ich ihn erzeuge. Daher mache ich dieses einmal in viewDidLoad
. Danach kann ich im einfachsten Fall presentOpenInMenuFromRect:inView:animated:
aufrufen und iOS zeigt über dem Button, mit dem ich openIn:
im Interface Builder verknüpft habe, ein Popup-Menü mit einer Liste der Apps, die behaupten, mit der Ressource etwas anfangen zu können. Bei einem PDF bieten sich bei mir z.B. iBook und der Acrobat Reader an. Gibt es keine einzige App, liefert der Aufruf der Methode NO
als Ergebnis, worauf ich reagieren sollte.
So kann ich mitbekommen, ob eine andere App ausgewählt wurde:
@interface ViewController () <UIDocumentInteractionControllerDelegate>
...
- (void)viewDidLoad {
[super viewDidLoad];
self.dic = [UIDocumentInteractionController interactionControllerWithURL:self.URL];
self.dic = self;
}
- (void)documentInteractionController:(UIDocumentInteractionController *)controller
willBeginSendingToApplication:(NSString *)application {
NSLog(@"copy %@ over to %@", controller.URL, application);
}
- (void)documentInteractionController:(UIDocumentInteractionController *)controller
didEndSendingToApplication:(NSString *)application {
NSLog(@"done copying");
}
Dazu mache ich meinen ViewController
zu einem UIDocumentInteractionControllerDelegate
und bekomme so die Informationen, dass eine andere App mit meiner Datei geöffnet werden soll bzw. geöffnet wurde. Ich kann diese beiden Benachrichtigungen z.B. dazu nutzen, um einen UIActivityIndicator
oder ähnliches in meinem ViewController
anzuzeigen.
Für einige Dateitypen kann der UIDocumentInteractionController
auch eine Preview anzeigen, ohne dass eine andere App bemüht werden muss:
- (void)preview:(id)sender {
if (![self.dic presentPreviewAnimated:YES]) {
NSLog(@"No preview for %@", self.dic.URL);
}
}
- (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *)controller {
return self;
}
Damit eine Preview möglich ist, muss ein Delegate zugewiesen und die Methode documentInteractionControllerViewControllerForPreview:
implementiert werden. Sie liefert den Controller, der als Vater des modalen Preview Controllers benutzt werden soll – bei mir also mein eigener und einziger View Controller. Aus der Preview heraus kann der Benutzer ebenfalls die Datei in einer anderen App öffnen.
Will man beide Funktionen kombinieren, bietet sich an, erst einmal das Options-Menü zu öffnen:
- (IBAction)openIn:(UIButton *)sender {
if (![self.dic presentOptionsMenuFromRect:sender.bounds inView:sender animated:YES]) {
NSLog(@"No apps installed to display %@", self.dic.URL);
}
}
Statt presentOpenInMenuFromRect:inView:animated:
wird nun presentOptionsMenuFromRect:inView:animated:
benutzt, um ein Popup-Menü zu öffnen, das sowohl eine Preview-Funktion (wenn möglich) anbietet, als auch andere Funktionen wie z.B. das Drucken, Kopieren oder das Öffnen in iBook (was iOS offenbar gleicher als alle anderen Apps behandelt). Schließlich bietet das Options-Menü eine Möglichkeit, auch ein anderes Programm zu öffnen.
Implementiere ich die folgenden beiden Methoden (eine allein reicht nicht), kann ich beeinflussen, ob und wie das Drucken oder Kopieren funktionieren soll:
- (BOOL)documentInteractionController:(UIDocumentInteractionController *)controller
canPerformAction:(SEL)action {
return @selector(print:) == action;
}
- (BOOL)documentInteractionController:(UIDocumentInteractionController *)controller
performAction:(SEL)action {
if (action == @selector(print:)) {
...
return YES;
}
return NO;
}
Ein nettes Feature ist noch, dass ich die obigen beiden Funktionen auch mit einer einzige Zeile an ein UI-Element (hier URLView
genannt) hängen kann, das z.B. durch ein Bild die Datei repräsentiert:
- (void)viewDidLoad {
...
self.URLView.gestureRecognizers = self.dic.gestureRecognizers;
}
Dadurch öffnet sich die Preview bei einem einfachen Antippen des UI-Elements und das Options-Menü ein einem längeren Antippen. Der UIDocumentInteractionController
bietet damit eine einfach zu benutzende Möglichkeit, Dateien an andere Apps zu übergeben und auf diese Weise z.B. beliebige Inhalte der Dropbox-App zu übergeben.
Stefan