Управление скриншотом в многозадачном коммутаторе iOS 7

Я пытался найти некоторую информацию о новом многозадачном коммутаторе в iOS 7 и особенно скриншоте, который требуется ОС, когда приложение переходит в спящий режим.

enter image description here

Есть ли способ полностью отключить эту функцию или снимок экрана? Или я могу скрыть приложение от коммутатора? Приложение должно работать в фоновом режиме, но мы не хотим показывать снимок экрана из приложения.

Снимок экрана потенциально опасен для безопасности, подумайте о линиях для банковских приложений, где номер вашей карты или сводка счетов будут доступны всем, кто дважды щелкнет кнопку "домой" на устройстве.

Кто-нибудь знает это? Спасибо.

Ответ 1

В подготовке вашего пользовательского интерфейса для работы в фоновом режиме Apple говорит:

Подготовьте свой пользовательский интерфейс для снимка приложения

В какой-то момент после того, как ваше приложение входит в фоновый режим и возвращается ваш метод делегата, UIKit делает снимок текущего пользовательского интерфейса ваших приложений. Система отобразит полученное изображение в переключателе приложений. Он также временно отображает изображение при возврате вашего приложения на передний план.

Интерфейс вашего приложения не должен содержать конфиденциальную информацию пользователя, такую как пароли или номера кредитных карт. Если ваш интерфейс содержит такую информацию, удалите ее из ваших представлений при входе в фон. Кроме того, отключите оповещения, временные интерфейсы и контроллеры системного представления, которые скрывают содержимое ваших приложений. Снимок представляет интерфейс вашего приложения и должен быть узнаваемым для пользователей. Когда ваше приложение вернется на передний план, вы сможете восстановить данные и представления соответствующим образом.

См. Технические вопросы и ответы QA1838: Предотвращение появления конфиденциальной информации в переключателе задач.

В дополнение к скрытию/замене конфиденциальной информации вы можете также попросить iOS 7 не делать снимок экрана с помощью ignoreSnapshotOnNextApplicationLaunch, документация которого гласит:

Если вы чувствуете, что моментальный снимок не может правильно отражать пользовательский интерфейс вашего приложения при перезапуске приложения, вы можете вызвать ignoreSnapshotOnNextApplicationLaunch чтобы предотвратить ignoreSnapshotOnNextApplicationLaunch этого снимка.

Сказав это, кажется, что снимок экрана все еще сделан, и поэтому я подал отчет об ошибке. Но вы должны проверить дальше и посмотреть, поможет ли использование этого параметра.

Если бы это было корпоративное приложение, вы также можете обратиться к соответствующему параметру allowScreenShot указанному в разделе " Ограничения полезной нагрузки " справочника профиля конфигурации.


Вот реализация, которая достигает того, что мне нужно. Вы можете представить свой собственный UIImageView или использовать шаблон протокола делегата, чтобы скрыть конфиденциальную информацию:

//  SecureDelegate.h

#import <Foundation/Foundation.h>

@protocol SecureDelegate <NSObject>

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

@end

Затем я дал делегату приложения свойство для этого:

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

Мой контроллер вида устанавливает это:

- (void)viewDidLoad
{
    [super viewDidLoad];

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

Контроллер представления, очевидно, реализует этот протокол:

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

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

И, наконец, мой делегат приложения использует этот протокол и свойство:

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

Обратите внимание, что я использую applicationWillResignActive а не рекомендованный applicationDidEnterBackground, потому что, как отмечали другие, последний не вызывается при двойном нажатии на кнопку "Домой" во время работы приложения.

Я хотел бы использовать уведомления для обработки всего этого, а не шаблон протокола делегата, но в моем ограниченном тестировании уведомления не обрабатываются достаточно своевременно, но приведенный выше шаблон работает нормально.

Ответ 2

Это решение, с которым я работал для моего приложения:

Как сказал Томми: Вы можете использовать applicationWillResignActive. То, что я сделал, это сделать UIImageView с помощью SplashImage и добавить его в качестве подзаголовка в мое главное окно.

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

Я использовал этот метод вместо applicationDidEnterBackground, потому что applicationDidEnterBackground не будет запущен, если вы дважды нажмете кнопку home, а applicationWillResignActive будет. Я слышал, как люди говорили, что это может быть вызвано и в других случаях, поэтому я все еще проверяю, не проблема, но пока нет!;)

Здесь, чтобы удалить изображение:

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

Надеюсь, это поможет!

Sidenote: Я тестировал это как на симуляторе, так и на реальном устройстве: он не будет отображаться на симуляторе, но он работает на реальном устройстве!

Ответ 3

Этот быстрый и простой способ даст черный снимок выше вашего значка приложения в коммутаторе приложений iOS7 или более поздней версии.

Во-первых, откройте окно своего приложения (как правило, установите приложение AppDelegate.m в приложении: didFinishLaunchingWithOptions) и скройте его, когда ваше приложение вот-вот переместится в фоновый режим:

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

Затем откройте окно приложения, когда ваше приложение снова активируется:

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

На этом этапе проверьте переключатель приложений и убедитесь, что вы видите черный снимок над значком вашего приложения. Я заметил, что если вы запустите приложение-переключатель сразу после перемещения приложения в фоновом режиме, может произойти отсрочка ~ 5 секунд, где вы увидите моментальный снимок вашего приложения (тот, который вы хотите скрыть!), После который перейдет на черно-черный снимок. Я не уверен, что с задержкой; если у кого есть какие-либо предложения, пожалуйста, звоните.

Если вам нужен цвет, отличный от черного в коммутаторе, вы можете сделать что-то вроде этого, добавив subview с любым цветом фона, который вам нужен:

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

Затем удалите это подзону цвета, когда ваше приложение снова активируется:

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

Ответ 4

Я использовал следующее решение: когда приложение собирается уйти в отставку, я получаю снимок appWindow как вид и добавляю к нему размытие. Затем я добавляю этот вид в окно приложения

как это сделать:

  • в appDelegate перед внедрением добавить строку:

    static const int kNVSBlurViewTag = 198490;//or wherever number you like
    
  • добавьте следующие методы:

    - (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;
        }
    
  • сделать реализацию appDelegate следующим:

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

Я создал примеры проектов в Swift и Цель C. Оба проекта выполняют следующие действия:

-приложение: didResignActive - моментальный снимок создается, размывается и добавляется в окно приложения

-application: willBecomeActive размытие будет удалено из окна.

Как использовать:

Objecitve C

  • Добавить AppDelegate+NVSBlurAppScreen.h и .m файлы в ваш проект

  • в вашем приложении -applicationWillResignActive: добавьте следующую строку:

    [self nvs_blurPresentedView];
    
  • в вашем -applicationDidEnterBackground: метод добавьте следующую строку:

    [self nvs_unblurPresentedView];
    

Swift

  • добавить файл AppDelegateExtention.swift в ваш проект

  • в вашей функции applicationWillResignActive добавьте следующую строку:

    blurPresentedView()
    
  • в вашей функции applicationDidBecomeActive добавьте следующую строку:

    unblurPresentedView()
    

Ответ 5

если использовать функцию [self.window addSubview:imageView]; в applicationWillResignActive, этот образ не будет охватывать UIAlertView, UIActionSheet или MFMailComposeViewController...

Лучшее решение

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

Ответ 6

Предоставление моего собственного решения в качестве "ответов", хотя это решение очень ненадежно. Иногда я получаю черный экран как скриншот, иногда XIB, а иногда и скриншот из самого приложения. В зависимости от устройства и/или если я запускаю его в симуляторе.

Обратите внимание: я не могу предоставить какой-либо код для этого решения, так как он содержит множество подробных сведений о приложении. Но это должно объяснить основную суть моего решения.

В AppDelegate.m в приложенииWillResignActive я проверяю, если мы запуск iOS7, если мы загружаем новое представление, пустое с app-logo посередине. Когда applicationDidBecomeActive называется я перезапустите мои старые представления, которые будут reset - но это работает для тип приложения, которое я разрабатываю.

Ответ 7

Вы можете использовать активатор, чтобы настроить двойной щелчок на домашней кнопке, чтобы запустить многозадачность и отключить двойной щелчок кнопкой мыши на домашней кнопке и запуск окна многозадачности. Этот метод можно использовать для изменения скриншотов на образ приложения по умолчанию. Это применимо к приложениям с функцией защиты паролем по умолчанию.

Ответ 8

Xamarin.iOS

Адаптировано из fooobar.com/info/64890/...

Вместо того, чтобы просто показывать цвет, я хотел показать экран запуска.

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