web-dev-qa-db-fra.com

Contrôle de la capture d'écran dans le sélecteur multitâche iOS 7

J'ai essayé de trouver des informations sur le nouveau commutateur multitâche dans iOS 7 et en particulier sur la capture d'écran prise par le système d'exploitation lorsque l'application passait en veille prolongée.

enter image description here

Est-il possible de désactiver complètement cette fonctionnalité ou cette capture d'écran? Ou puis-je cacher l'application du sélecteur? L'application doit être exécutée en arrière-plan, mais nous ne voulons pas afficher de capture d'écran à partir de l'application.

La capture d'écran présente potentiellement un risque pour la sécurité. Réfléchissez bien aux applications bancaires dans lesquelles votre numéro de carte ou votre récapitulatif de compte sera disponible pour tous ceux qui cliquent deux fois sur le bouton d'accueil de l'appareil.

Quelqu'un avec un aperçu de cela? Merci.

95
Tommie

Dans Préparer votre interface utilisateur à fonctionner en arrière-plan , Apple dit:

Préparez votre interface utilisateur pour l'instantané d'application

Une fois que votre application est entrée en arrière-plan et que votre méthode de délégation est revenue, UIKit prend un instantané de l'interface utilisateur actuelle de votre application. Le système affiche l'image résultante dans le sélecteur d'applications. Il affiche également l'image temporairement lorsque vous ramenez votre application au premier plan.

L’interface utilisateur de votre application ne doit contenir aucune information utilisateur sensible, telle que des mots de passe ou des numéros de carte de crédit. Si votre interface contient de telles informations, supprimez-les de votre vue lors de la saisie de l'arrière-plan. Supprimez également les alertes, les interfaces temporaires et les contrôleurs de vue système qui masquent le contenu de votre application. L’instantané représente l’interface de votre application et devrait être reconnaissable par les utilisateurs. Lorsque votre application revient au premier plan, vous pouvez restaurer les données et les vues selon vos besoins.

Voir QA technique QA1838: Empêcher l’apparition d’informations sensibles dans le sélecteur de tâches

En plus de masquer/remplacer les informations sensibles, vous pouvez également demander à iOS 7 de ne pas prendre la capture d'écran via ignoreSnapshotOnNextApplicationLaunch , dont la documentation indique:

Si vous pensez que l'instantané ne peut pas refléter correctement l'interface utilisateur de votre application lorsque celle-ci est relancée, vous pouvez appeler ignoreSnapshotOnNextApplicationLaunch pour empêcher la prise de cette image instantanée.

Cela dit, il semble que la capture d'écran soit toujours prise et j'ai donc déposé un rapport de bogue. Mais vous devriez tester plus avant et voir si l'utilisation de ce paramètre peut aider.

S'il s'agit d'une application d'entreprise, vous pouvez également consulter le paramètre approprié de allowScreenShot décrit dans la section Restrictions Payload du profil de configuration . Référence.


Voici une implémentation qui réalise ce dont j'avais besoin. Vous pouvez présenter votre propre UIImageView ou utiliser un modèle de protocole de délégué pour masquer les informations confidentielles:

//  SecureDelegate.h

#import <Foundation/Foundation.h>

@protocol SecureDelegate <NSObject>

- (void)hide:(id)object;
- (void)show:(id)object;

@end

J'ai ensuite donné à mon délégué aux applications une propriété pour cela:

@property (weak, nonatomic) id<SecureDelegate> secureDelegate;

Mon contrôleur de vue le définit:

- (void)viewDidLoad
{
    [super viewDidLoad];

    AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
    delegate.secureDelegate = self;
}

Le contrôleur de vue implémente évidemment ce protocole:

- (void)hide:(id)object
{
    self.passwordLabel.alpha = 0.0;
}

- (void)show:(id)object
{
    self.passwordLabel.alpha = 1.0;
}

Et, enfin, mon délégué à l'application utilise ce protocole et cette propriété:

- (void)applicationWillResignActive:(UIApplication *)application
{
    [application ignoreSnapshotOnNextApplicationLaunch];  // this doesn't appear to work, whether called here or `didFinishLaunchingWithOptions`, but seems prudent to include it

    [self.secureDelegate hide:@"applicationWillResignActive:"];  // you don't need to pass the "object", but it was useful during my testing...
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    [self.secureDelegate show:@"applicationDidBecomeActive:"];
}

Notez que j'utilise applicationWillResignActive plutôt que le conseillé applicationDidEnterBackground, parce que, comme d'autres l'ont souligné, ce dernier n'est pas appelé lorsque vous appuyez deux fois sur le bouton d'accueil pendant l'exécution de l'application.

Je souhaiterais pouvoir utiliser les notifications pour gérer tout cela, plutôt que le modèle de protocole de délégué, mais dans mes tests limités, les notifications ne sont pas traitées suffisamment tôt, mais le modèle ci-dessus fonctionne bien.

97
Rob

Voici la solution avec laquelle j'ai travaillé pour mon application:

Comme l'a dit Tommy: Vous pouvez utiliser l'applicationWillResignActive. Ce que j'ai fait était de créer un UIImageView avec ma SplashImage et de l'ajouter en tant que sous-vue à ma fenêtre principale.

(void)applicationWillResignActive:(UIApplication *)application
{
    imageView = [[UIImageView alloc]initWithFrame:[self.window frame]];
    [imageView setImage:[UIImage imageNamed:@"Portrait(768x1024).png"]];
    [self.window addSubview:imageView];
}

J'ai utilisé cette méthode à la place de applicationDidEnterBackground, car applicationDidEnterBackground ne sera pas déclenchée si vous doublez le bouton principal et que applicationWillResignActive le sera. J'ai entendu des gens dire que cela pouvait aussi être déclenché dans d'autres cas, donc je teste toujours pour voir si ça pose problème, mais aucun jusqu'à présent! ;)

Ici pour supprimer l'image view:

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    if(imageView != nil) {
        [imageView removeFromSuperview];
        imageView = nil;
    }
}

J'espère que cela t'aides!

Sidenote: J'ai testé cela à la fois sur le simulateur et sur un appareil réel: cela ne s'affichera pas sur le simulateur, mais sur un appareil réel!

32
Laura

Cette méthode rapide et simple générera un instantané noir au-dessus de l'icône de votre application dans le commutateur d'applications iOS7 ou ultérieur.

Tout d'abord, prenez la fenêtre de clé de votre application (généralement configurée dans AppDelegate.m dans l'application: didFinishLaunchingWithOptions) et masquez-la lorsque votre application est sur le point de passer en arrière-plan:

- (void)applicationWillResignActive:(UIApplication *)application
{
    if(isIOS7Or8)
    {
        self.window.hidden = YES;
    }
}

Puis, débloquez la fenêtre de clé de votre application lorsque celle-ci redevient active:

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    if(isIOS7Or8)
    {
        self.window.hidden = NO;
    }
}

À ce stade, vérifiez le sélecteur d'applications et vérifiez que vous voyez un instantané noir au-dessus de l'icône de votre application. J'ai remarqué que si vous lancez le sélecteur d'applications immédiatement après avoir déplacé votre application en arrière-plan, il peut s'écouler environ 5 secondes lorsque vous verrez un instantané de votre application (celle que vous souhaitez masquer!), Après qu’il passe à un instantané entièrement noir. Je ne sais pas ce qui se passe avec le retard; Si quelqu'un a des suggestions, s'il vous plaît, faites-le.

Si vous voulez une couleur autre que le noir dans le sélecteur, vous pouvez le faire en ajoutant une sous-vue avec la couleur de fond souhaitée:

- (void)applicationWillResignActive:(UIApplication *)application
{
    if(isIOS7Or8)
    {
        UIView *colorView = [[[UIView alloc] initWithFrame:self.window.frame] autorelease];
        colorView.tag = 9999;
        colorView.backgroundColor = [UIColor purpleColor];
        [self.window addSubview:colorView];
        [self.window bringSubviewToFront:colorView];
    }
}

Ensuite, supprimez cette sous-vue de couleur lorsque votre application redevient active:

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    if(isIOS7Or8)
    {
        UIView *colorView = [self.window viewWithTag:9999];
        [colorView removeFromSuperview];
    }
}
14
John Jacecko

J'ai utilisé la solution suivante: lorsque l'application est sur le point de démissionner, j'obtiens un instantané appWindow sous forme de vue et lui ajoute un flou. Puis j'ajoute cette vue à la fenêtre de l'application

comment faire ceci:

  1. dans appDelegate juste avant l'implémentation, ajoutez la ligne suivante:

    static const int kNVSBlurViewTag = 198490;//or wherever number you like
    
  2. ajoutez cette méthode:

    - (void)nvs_blurPresentedView
        {
            if ([self.window viewWithTag:kNVSBlurViewTag]){
                return;
            }
            [self.window addSubview:[self p_blurView]];
        }
    
        - (void)nvs_unblurPresentedView
        {
            [[self.window viewWithTag:kNVSBlurViewTag] removeFromSuperview];
        }
    
        #pragma mark - Private
    
        - (UIView *)p_blurView
        {
            UIView *snapshot = [self.window snapshotViewAfterScreenUpdates:NO];
    
            UIView *blurView = nil;
            if ([UIVisualEffectView class]){
                UIVisualEffectView *aView = [[UIVisualEffectView alloc]initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]];
                blurView        = aView;
                blurView.frame  = snapshot.bounds;
                [snapshot addSubview:aView];
            }
            else {
                UIToolbar *toolBar  = [[UIToolbar alloc] initWithFrame:snapshot.bounds];
                toolBar.barStyle    = UIBarStyleBlackTranslucent;
                [snapshot addSubview:toolBar];
            }
            snapshot.tag = kNVSBlurViewTag;
            return snapshot;
        }
    
  3. faites en sorte que votre implémentation appDelegate soit la suivante:

    - (void)applicationWillResignActive:(UIApplication *)application {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
        //...
        //your code
        //...
    
        [self nvs_blurPresentedView];
    }
    
        - (void)applicationWillEnterForeground:(UIApplication *)application {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
        //...
        //your code
        //...
    
        [self nvs_unblurPresentedView];
    }
    

J'ai créé des exemples de projets dans Swift et Objective C . Les deux projets font les actions suivantes dans:

- application: didResignActive - un instantané est créé, estompé et ajouté à la fenêtre de l'application

- application: willBecomeActive La vue floue est supprimée de la fenêtre.

Comment utiliser:

Objecitve C

  1. Ajouter AppDelegate+NVSBlurAppScreen .h et fichiers .m dans votre projet

  2. dans votre méthode -applicationWillResignActive: ajoutez la ligne suivante:

    [self nvs_blurPresentedView];
    
  3. dans votre méthode -applicationDidEnterBackground: ajoutez la ligne suivante:

    [self nvs_unblurPresentedView];
    

Rapide

  1. ajoutez le fichier AppDelegateExtention.Swift à votre projet

  2. dans la fonction applicationWillResignActive, ajoutez la ligne suivante:

    blurPresentedView()
    
  3. dans la fonction applicationDidBecomeActive, ajoutez la ligne suivante:

    unblurPresentedView()
    
3

si seulement utilisez [self.window addSubview:imageView]; dans applicationWillResignActive fonction, cette image ne couvrira pas UIAlertView, UIActionSheet ou MFMailComposeViewController ...

La meilleure solution est

- (void)applicationWillResignActive:(UIApplication *)application
{
    UIWindow *mainWindow = [[[UIApplication sharedApplication] windows] lastObject];
    [mainWindow addSubview:imageView];
}
2
Zorot

Vous pouvez utiliser activator pour configurer le double-clic sur le bouton d'accueil afin de lancer le multitâche et désactiver le double-clic par défaut du bouton d'accueil et le lancement de la fenêtre multitâche. Cette méthode peut être utilisée pour changer les captures d'écran en image par défaut de l'application. Ceci est applicable aux applications avec la fonctionnalité de protection par mot de passe par défaut.

0
Fareed.MK

Fournir ma propre solution en tant que "réponses", bien que cette solution soit très peu fiable. Parfois, je reçois un écran noir comme capture d'écran, parfois le XIB et parfois une capture d'écran de l'application elle-même. En fonction de l'appareil et/ou si je lance ceci dans le simulateur.

Veuillez noter que je ne peux fournir aucun code pour cette solution car il contient de nombreux détails spécifiques à l'application. Mais cela devrait expliquer l’essence de base de ma solution.

Dans AppDelegate.m, sous applicationWillResignActive, je vérifie si nous exécutons iOS7. Si c'est le cas, je charge une nouvelle vue qui est vide avec le logo de l'application au milieu. Une fois que applicationDidBecomeActive est appelé, je relance mes anciennes vues, qui seront réinitialisées - mais cela fonctionne pour le type d'application que je suis en train de développer.

0
Tommie