Skip to content

Instantly share code, notes, and snippets.

@sma
Last active August 31, 2018 14:12
Show Gist options
  • Save sma/4564031 to your computer and use it in GitHub Desktop.
Save sma/4564031 to your computer and use it in GitHub Desktop.
Open In... - Dateien senden in iOS-Apps

Open In... - Dateien senden in iOS-Apps

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.

Preview

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.

Preview & Open In...

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;
}

Alles automatisch

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment