De IOS 2 à IOS 9, lorsque vous envoyiez un fichier dans une application (par exemple à partir d'un fichier attaché en mail), cela lançait l'application et la fonction openURL du délégateur de l'application :
openURL:(NSURL *)url {
Si vous retourniez YES, le fichier était considéré comme lu.
Ensuite de IOS 4.2 à 9.0, Apple à ajouté la possibilité de connaître l'application source du fichier.
openURL:(nonnull NSURL *)url
Ensuite, avec IOS 9, Apple a ajouté des options afin d'y mettre l'application source, les annotations, mais aussi tout ce qu'ils pourrait vouloir dans le futur. On met un dictionnaire à la place de paramètre, et on évitera ainsi de multiplier les fonctions.
-(BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
options:(nonnull NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
Puis IOS 10 à ajouté un handler (et oui, on croit avoir pensé à tout, et puis on a oublié quelque chose). Cela allait dans le sens des processeurs multi-cœurs, et du système toujours plus multi-tâche.
- (void)openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenExternalURLOptionsKey, id> *)options
completionHandler:(void (^)(BOOL success))completion {
Pour être compatible entre les différentes version d'IOS, il vaut mieux avoir toutes les version (les unes se servant de la première à moins d'avoir besoin des options).
Mais cela ne suffisait pas ! IOS 13 introduit les UIScene. En effet, l'iPad ne permettait jusqu'à lors que d'avoir une seule application active, avec une seule fenêtre prenant tout l'écran. Or, Apple veut plusieurs écrans, et plusieurs fenêtre dans un seul écran. On doit pouvoir faire un drag and drop entre fenêtre d'applications différentes... C'est donc la fenêtre inclue dans la scène qui devient le point d'entrée (et pas l'application en elle-même... Et voilà qu'arrive OpenURL dans le délégateur de la scène.
- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts {
for(UIOpenURLContext *context in [URLContexts allObjects]) {
[self application:UIApplication.sharedApplication
openURL:context.URL
options:@{}];
}
}
On peut maintenant recevoir plusieurs fichiers, et on appelle simplement le OpenURL du delegate de l'application. À partir du moment où l'on gère les UIScene, les fonctions de UIApplication ne sont plus appelées, tout passe par les UIScene.
Mais un cas n'est plus pris en compte. Si l'application n'est pas encore lancée, qu'il n'y a pas encore de UIScene, OpenURLContexts ne sera pas appelée. Donc si l'application tourne, tout fonctionne, mais si elle n'est pas encore lancée, l'envoi d'un fichier lance l'application mais sans lire le fichier.
La solution est dans une autre fonction, WillConnectToSession :
-(void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
UIWindowScene *windowScene = (UIWindowScene *)scene;
self.window = [[UIWindow alloc] initWithWindowScene:windowScene];
self.window.backgroundColor = UIColor.systemBackgroundColor;
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"main" bundle:nil];
self.window.rootViewController = [mainStoryboard instantiateInitialViewController];
[self.window makeKeyAndVisible];
if(connectionOptions.URLContexts) {
[self scene:scene openURLContexts:connectionOptions.URLContexts];
}
}
Dans les options de WillConnectToSession, vous avez le URLContexts, et vous pouvez appeler OpenURLContexts avec. Cerise sur le gâteau, vous êtes donc certain, dans OpenURLContexts que la scène est bien initialisée, qu'il y a une fenêtre et un rootViewController pour afficher vos alertes.
Commentaires