Steuern des Screenshots im iOS 7 Multitasking-Umschalter

98

Ich habe versucht, einige Informationen zum neuen Multitasking-Umschalter in iOS 7 zu finden, insbesondere den Screenshot, den das Betriebssystem macht, wenn die App in den Ruhezustand wechselt.

Geben Sie hier die Bildbeschreibung ein

Gibt es eine Möglichkeit, diese Funktion oder diesen Screenshot vollständig auszuschalten? Oder kann ich die App ganz vor dem Umschalter verstecken? Die App muss im Hintergrund ausgeführt werden, wir möchten jedoch keinen Screenshot der App anzeigen.

Der Screenshot stellt möglicherweise ein Sicherheitsrisiko dar. Denken Sie an Bank-Apps, bei denen Ihre Kartennummer oder Kontozusammenfassung jedem zur Verfügung steht, der auf die Home-Schaltfläche des Geräts doppelklickt.

Hat jemand einen Einblick in das? Vielen Dank.

Tommie
quelle
1
Meine aktuelle Lösung besteht darin, eine leere Ansicht mit dem App-Logo zu laden, sobald die App in den Ruhezustand wechselt, und sie zu entfernen, wenn die App zurückkehrt. Diese Lösung ist jedoch schwer zu verwalten und scheint eher ein Hack als eine elegante Lösung zu sein. Außerdem schlägt diese Lösung von Zeit zu Zeit je nach Gerät usw. fehl. Sie ist also nicht wirklich verwendbar.
Tommie

Antworten:

101

Bei der Vorbereitung Ihrer Benutzeroberfläche für die Ausführung im Hintergrund sagt Apple:

Bereiten Sie Ihre Benutzeroberfläche für den App-Snapshot vor

Irgendwann, nachdem Ihre App in den Hintergrund getreten ist und Ihre Delegatenmethode zurückgekehrt ist, erstellt UIKit einen Schnappschuss der aktuellen Benutzeroberfläche Ihrer App. Das System zeigt das resultierende Bild im App-Umschalter an. Das Bild wird auch vorübergehend angezeigt, wenn Sie Ihre App wieder in den Vordergrund stellen.

Die Benutzeroberfläche Ihrer App darf keine vertraulichen Benutzerinformationen wie Passwörter oder Kreditkartennummern enthalten. Wenn Ihre Benutzeroberfläche solche Informationen enthält, entfernen Sie diese aus Ihren Ansichten, wenn Sie den Hintergrund eingeben. Schließen Sie außerdem Warnungen, temporäre Schnittstellen und Systemansichts-Controller, die den Inhalt Ihrer App verdecken. Der Schnappschuss stellt die Benutzeroberfläche Ihrer App dar und sollte für Benutzer erkennbar sein. Wenn Ihre App wieder in den Vordergrund zurückkehrt, können Sie Daten und Ansichten entsprechend wiederherstellen.

Siehe Technische Fragen und Antworten QA1838: Verhindern, dass vertrauliche Informationen im Task-Umschalter angezeigt werden

Zusätzlich zum Verdecken / Ersetzen vertraulicher Informationen möchten Sie iOS 7 möglicherweise anweisen, den Bildschirmschnappschuss nicht über zu ignoreSnapshotOnNextApplicationLauncherstellen. In der Dokumentation heißt es:

Wenn Sie der Meinung sind, dass der Snapshot die Benutzeroberfläche Ihrer App beim Neustart Ihrer App nicht korrekt wiedergeben kann, können Sie anrufen ignoreSnapshotOnNextApplicationLaunch, um zu verhindern, dass das Snapshot-Bild aufgenommen wird.

Trotzdem scheint der Screenshot noch aufgenommen zu sein und ich habe daher einen Fehlerbericht eingereicht. Sie sollten jedoch weiter testen und prüfen, ob die Verwendung dieser Einstellung hilfreich ist.

Wenn es sich um eine Unternehmensanwendung handelt, sollten Sie auch die entsprechende Einstellung allowScreenShotüberprüfen, die im Abschnitt Einschränkungen der Nutzlast der Konfigurationsprofilreferenz beschrieben ist.


Hier ist eine Implementierung, die das erreicht, was ich brauchte. Sie können Ihr eigenes präsentieren UIImageViewoder ein Delegate-Protokoll-Muster verwenden, um die vertraulichen Informationen zu verschleiern:

//  SecureDelegate.h

#import <Foundation/Foundation.h>

@protocol SecureDelegate <NSObject>

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

@end

Ich habe dann meinem App-Delegierten eine Eigenschaft dafür gegeben:

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

Mein View Controller legt es fest:

- (void)viewDidLoad
{
    [super viewDidLoad];

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

Der View Controller implementiert offensichtlich dieses Protokoll:

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

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

Und schließlich nutzt mein App-Delegierter dieses Protokoll und diese Eigenschaft:

- (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:"];
}

Beachten Sie, dass ich applicationWillResignActiveeher die empfohlene als die empfohlene verwende applicationDidEnterBackground, da letztere, wie andere bereits betont haben, nicht aufgerufen wird, wenn Sie zweimal auf die Home-Schaltfläche tippen, während die App ausgeführt wird.

Ich wünschte, ich könnte Benachrichtigungen verwenden, um all dies zu verarbeiten, anstatt das Muster des Delegiertenprotokolls, aber in meinen begrenzten Tests werden die Benachrichtigungen nicht rechtzeitig genug verarbeitet, aber das obige Muster funktioniert einwandfrei.

rauben
quelle
6
Beachten Sie, dass, wie hier erwähnt, stackoverflow.com/questions/18937313/… das Verhalten im Simulator nicht immer das gleiche ist wie auf dem Gerät!
Michael Forrest
5
Für das, was es wert ist, wird die ignoreSnapshotOnNextApplicationLaunchMethode ignoriert, wenn sie nicht wie hier beschrieben während der Zustandswiederherstellung aufgerufen wird .
Charles A.
3
Sie müssen dies nicht in applicationWillResignActive tun, da der Screenshot erst nach applicationDidEnterBackground aufgenommen wird. Wenn Sie zweimal auf die Home-Schaltfläche tippen, wird kein Screenshot erstellt. Der Bildschirm, den Sie sehen, ist live. Fügen Sie Ihrem Bildschirm eine Animation hinzu, um dies zu überprüfen, z. B. Hintergrundfarben zyklisch. Wenn Sie dann eine andere App auswählen, wird Ihre applicationDidEnterBackground aufgerufen, bevor der eigentliche Screenshot aufgenommen wird.
Honus
3
Übrigens wurde ich von einem Apple-Techniker darüber informiert, dass die Dokumentation nicht ignoreSnapshotOnNextApplicationLaunchkorrekt ist, dass, wie wir alle festgestellt haben, tatsächlich ein Schnappschuss erstellt wird, der jedoch beim nächsten Start einfach nicht verwendet wird.
Rob
2
ignoreSnapshotOnNextApplicationLaunch scheint das zu tun, wonach es sich anhört: zu verhindern, dass beim Start der Anwendung ein Screenshot angezeigt wird . Dies hat keinen Einfluss auf den Screenshot der Multitasking-Benutzeroberfläche oder darauf, ob Ihre Anwendung fortgesetzt und nicht gestartet wird.
Glenn Maynard
32

Dies ist die Lösung, mit der ich für meine Anwendung gearbeitet habe:

Wie Tommy sagte: Sie können die applicationWillResignActive verwenden. Ich habe mit meinem SplashImage eine UIImageView erstellt und sie als Unteransicht zu meinem Hauptfenster hinzugefügt.

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

Ich habe diese Methode anstelle von applicationDidEnterBackground verwendet, da applicationDidEnterBackground nicht ausgelöst wird, wenn Sie zweimal auf die Home-Schaltfläche tippen, und applicationWillResignActive. Ich habe Leute sagen hören, dass es auch in anderen Fällen ausgelöst werden kann, also teste ich immer noch, um zu sehen, ob es ein Problem gibt, aber bisher keines! ;)

Hier, um die Bildansicht zu entfernen:

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

Hoffe das hilft!

Nebenbemerkung: Ich habe dies sowohl auf dem Simulator als auch auf einem realen Gerät getestet: Es wird nicht auf dem Simulator angezeigt, aber auf einem realen Gerät!

Laura
quelle
2
Es gibt einen Nachteil: applicationWillResignActive wird unter anderem aufgerufen, wenn der Benutzer das Benachrichtigungsdock herunterzieht. Sie schieben also Ihren Finger von oben nach unten und sehen das Bild, während Sie erwartet haben, dass der Inhalt der App angezeigt wird.
Kirill Gamazkov
4
Es ist besser, vertrauliche Informationen in applicationWillResignActive zu verwischen und imageView auf aplicationDidEnterBackground
Kirill Gamazkov am
Dies funktioniert, aber es gibt einen Rotationsfehler bei der Bereitstellung auf iOS7, der mit xCode6 erstellt wurde: stackoverflow.com/questions/26147068/…
Alex Stone
Wenn ich Code schreibe, den Sie in applicationWillResignActive erwähnt haben , was wird dann angezeigt, wenn ich meine App wieder in den Vordergrund versetze? Wird das Bild "Portrait (768x1024) .png" oder der tatsächliche Bildschirm angezeigt?
NSPratik
2
@Pratik: Sie sehen das Bild, es sei denn, Sie entfernen es erneut in der applicationDidBecomeActive-Methode (siehe oben).
Laura
14

Diese schnelle und einfache Methode liefert einen schwarzen Schnappschuss über dem Symbol Ihrer App im App-Umschalter für iOS7 oder höher.

Nehmen Sie zunächst das Schlüsselfenster Ihrer App (normalerweise in AppDelegate.m in der Anwendung eingerichtet: didFinishLaunchingWithOptions) und blenden Sie es aus, wenn Ihre App in den Hintergrund tritt:

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

Blenden Sie dann das Schlüsselfenster Ihrer App ein, wenn Ihre App wieder aktiv wird:

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

Überprüfen Sie zu diesem Zeitpunkt den App-Umschalter und stellen Sie sicher, dass über dem Symbol Ihrer App ein schwarzer Schnappschuss angezeigt wird. Ich habe festgestellt, dass es nach dem Starten des App-Umschalters unmittelbar nach dem Verschieben der App in den Hintergrund zu einer Verzögerung von ~ 5 Sekunden kommen kann, nach der Sie einen Schnappschuss Ihrer App sehen (den, den Sie ausblenden möchten!) was es zu einem komplett schwarzen Schnappschuss übergeht. Ich bin mir nicht sicher, was mit der Verzögerung los ist. Wenn jemand Vorschläge hat, melden Sie sich bitte.

Wenn Sie im Umschalter eine andere Farbe als Schwarz wünschen, können Sie Folgendes tun, indem Sie eine Unteransicht mit einer beliebigen Hintergrundfarbe hinzufügen:

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

Entfernen Sie dann diese Farbunteransicht, wenn Ihre App wieder aktiv wird:

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

Ich habe die folgende Lösung verwendet: Wenn die Anwendung zurücktritt, erhalte ich den appWindow-Snapshot als Ansicht und füge Unschärfe hinzu. Dann füge ich diese Ansicht dem App-Fenster hinzu

Wie macht man das:

  1. in appDelegate kurz vor der Implementierung Zeile hinzufügen:

    static const int kNVSBlurViewTag = 198490;//or wherever number you like
  2. Fügen Sie diese Methoden hinzu:

    - (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. Stellen Sie Ihre appDelegate-Implementierung wie folgt ein:

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

Ich habe Beispielprojekte in Swift und Objective C erstellt . Beide Projekte führen die folgenden Aktionen aus:

-Anwendung: didResignActive - Der Schnappschuss wird erstellt, verwischt und dem App-Fenster hinzugefügt

-Anwendung: Die Ansicht " willBecomeActive" wird aus dem Fenster entfernt.

Wie benutzt man:

Ziel C.

  1. Fügen AppDelegate+NVSBlurAppScreenSie Ihrem Projekt .h- und .m-Dateien hinzu

  2. Fügen Sie in Ihrer Methode -applicationWillResignActive: die folgende Zeile hinzu:

    [self nvs_blurPresentedView];
  3. Fügen Sie in Ihrer Methode -applicationDidEnterBackground: die folgende Zeile hinzu:

    [self nvs_unblurPresentedView];

Schnell

  1. Fügen Sie Ihrem Projekt die Datei AppDelegateExtention.swift hinzu

  2. Fügen Sie in Ihrer applicationWillResignActive-Funktion die folgende Zeile hinzu:

    blurPresentedView()
  3. Fügen Sie in Ihrer applicationDidBecomeActive-Funktion die folgende Zeile hinzu:

    unblurPresentedView()
Nikolay Shubenkov
quelle
2

Wenn diese Bildansicht nur [self.window addSubview:imageView];in der applicationWillResignActiveFunktion verwendet wird, werden UIAlertView, UIActionSheet oder MFMailComposeViewController nicht behandelt ...

Beste Lösung ist

- (void)applicationWillResignActive:(UIApplication *)application
{
    UIWindow *mainWindow = [[[UIApplication sharedApplication] windows] lastObject];
    [mainWindow addSubview:imageView];
}
Zorot
quelle
Sehr gute Lösung, wenn Sie ein Video im Vollbildmodus in einer Webansicht abspielen lassen!
Tommie
Ausgezeichnet!. Es funktioniert auch, wenn wir eine Tastatur geöffnet haben, bevor wir in den Multitasking-Umschalter einsteigen! Danke
Prabhu.Somasundaram
0

Bereitstellung meiner eigenen Lösung als "Antwort", obwohl diese Lösung sehr unzuverlässig ist. Manchmal bekomme ich einen schwarzen Bildschirm als Screenshot, manchmal das XIB und manchmal einen Screenshot von der App selbst. Je nach Gerät und / oder ob ich dies im Simulator laufen lasse.

Bitte beachten Sie, dass ich keinen Code für diese Lösung bereitstellen kann, da dort viele app-spezifische Details enthalten sind. Dies sollte jedoch den Grundgedanken meiner Lösung erklären.

In AppDelegate.m unter applicationWillResignActive überprüfe ich, ob iOS7 ausgeführt wird. Wenn wir dies tun, lade ich eine neue Ansicht, die leer ist und in der Mitte das App-Logo enthält. Sobald applicationDidBecomeActive aufgerufen wird, starte ich meine alten Ansichten neu, die zurückgesetzt werden - aber das funktioniert für die Art der Anwendung, die ich entwickle.

Tommie
quelle
1
Wenn Sie sehen, was die Kamera-App tut - sie wandelt das Bild in ein unscharfes um, wenn Sie in den Hintergrund gehen (Sie können den Übergang sehen, wenn er sich auf das Symbol reduziert)
Petesh
@Petesh Ja, das ist eine nette Implementierung, aber die Frage ist, wie sie es machen. Ich fürchte eine private API.
Rob
@Tommie Du sagst "Je nach Gerät und / oder ob ich das im Simulator laufen lasse". Für mich scheint es auf dem Gerät zu funktionieren (obwohl ich keine umfassenden Tests durchgeführt habe), aber nicht auf dem Simulator. Finden Sie, dass es auf dem Gerät nicht funktioniert?
Rob
0

Sie können Activator verwenden, um das Doppelklicken der Home-Schaltfläche zum Starten von Multitasking zu konfigurieren und das standardmäßige Doppelklicken der Home-Schaltfläche und das Starten des Multitasking-Fensters zu deaktivieren. Mit dieser Methode können Sie die Screenshots in das Standardbild der Anwendung ändern. Dies gilt für Apps mit standardmäßiger Passcode-Schutzfunktion.

Fareed.MK
quelle
-2

Xamarin.iOS

Angepasst von https://stackoverflow.com/a/20040270/7561

Anstatt nur eine Farbe anzuzeigen, wollte ich meinen Startbildschirm anzeigen.

 public override void DidEnterBackground(UIApplication application)
 {
    //to add the background image in place of 'active' image
    var backgroundImage = new UIImageView();
    backgroundImage.Tag = 1234;
    backgroundImage.Image = UIImage.FromBundle("Background");
    backgroundImage.Frame = this.window.Frame;
    this.window.AddSubview(backgroundImage);
    this.window.BringSubviewToFront(backgroundImage);
}

public override void WillEnterForeground(UIApplication application)
{
    //remove 'background' image
    var backgroundView = this.window.ViewWithTag(1234);
    if(null != backgroundView)
        backgroundView.RemoveFromSuperview();
}
ben
quelle