【问题标题】:Controlling the screenshot in the iOS 7 multitasking switcher在 iOS 7 多任务切换器中控制屏幕截图
【发布时间】:2013-09-28 08:36:44
【问题描述】:

我一直在尝试查找有关 iOS 7 中新的多任务切换器的一些信息,尤其是当应用程序进入休眠状态时操作系统截取的屏幕截图。

有什么办法可以完全关闭这个功能或者截图?或者我可以从切换器中完全隐藏应用程序吗?应用需要在后台运行,但我们不想显示应用的任何屏幕截图。

屏幕截图可能存在安全风险,请考虑银行应用程序的思路,在这些应用程序中,双击设备上的主页按钮的任何人都可以使用您的卡号或帐户摘要。

有人对此有任何见解吗?谢谢。

【问题讨论】:

  • 我目前的解决方案是在应用程序进入休眠状态后加载带有应用程序徽标的空白视图,并在应用程序返回时将其删除,但该解决方案很难管理,看起来像是一个 hack 而不是一个优雅的解决方案.此外,此解决方案有时会失败,具体取决于设备等。因此它不是真正可用的解决方案。

标签: ios ios7


【解决方案1】:

Preparing Your UI to Run in the Background,Apple 说:

为应用快照准备 UI

在您的应用程序进入后台并且您的委托方法返回后的某个时间点,UIKit 会拍摄您应用程序当前用户界面的快照。系统在应用切换器中显示生成的图像。当您的应用回到前台时,它还会临时显示图像。

您应用的 UI 不得包含任何敏感的用户信息,例如密码或信用卡号。如果您的界面包含此类信息,请在进入后台时将其从您的视图中删除。此外,消除隐藏应用程序内容的警报、临时界面和系统视图控制器。快照代表您的应用程序的界面,用户应该可以识别。当您的应用返回前台时,您可以根据需要恢复数据和视图。

Technical Q&A QA1838: Preventing Sensitive Information From Appearing In The Task Switcher

除了隐藏/替换敏感信息之外,您可能还想告诉 iOS 7 不要通过ignoreSnapshotOnNextApplicationLaunch 拍摄屏幕快照,其文档中写道:

如果您觉得重新启动应用时快照无法正确反映应用的用户界面,您可以致电ignoreSnapshotOnNextApplicationLaunch 以防止拍摄快照图像。

话虽如此,屏幕快照似乎仍在拍摄,因此我提交了一份错误报告。但您应该进一步测试,看看使用此设置是否有帮助。

如果这是一个企业应用程序,您可能还想查看配置文件参考的Restrictions Payload 部分中列出的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,因为正如其他人指出的那样,在应用程序运行时双击主页按钮时不会调用后者。

我希望我可以使用通知来处理所有这些,而不是委托协议模式,但在我有限的测试中,通知没有及时处理,但上述模式可以正常工作。

【讨论】:

  • 请注意,正如这里提到的stackoverflow.com/questions/18937313/…,模拟器中的行为与设备上的行为并不总是相同!
  • 不管怎样,ignoreSnapshotOnNextApplicationLaunch 方法如果在状态恢复期间没有被调用就会被忽略,如here 所述。
  • 您不需要在 applicationWillResignActive 中执行此操作,因为直到 applicationDidEnterBackground 才截取屏幕截图。当您双击主页按钮时,不会截取屏幕截图;您看到的屏幕是实时的。在屏幕上添加动画以进行验证,例如循环背景颜色。如果您随后选择另一个应用程序,您的 applicationDidEnterBackground 将在实际截屏之前被调用。
  • 顺便说一句,苹果工程师告诉我,ignoreSnapshotOnNextApplicationLaunch 的文档不正确,正如我们所观察到的那样,实际上拍摄了快照,但在下次发布时根本不会使用.
  • ignoreSnapshotOnNextApplicationLaunch 似乎做了它听起来的样子:防止在应用程序启动期间显示屏幕截图。它不会影响多任务 UI 屏幕截图,或者您的应用程序正在恢复而不是启动。
【解决方案2】:

这是我为我的应用程序使用的解决方案:

正如汤米所说:你可以使用applicationWillResignActive。我所做的是用我的 SplashImage 制作一个 UIImageView 并将其作为子视图添加到我的主窗口 -

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

我使用了这个方法而不是 applicationDidEnterBackground,因为如果你双击 home 按钮,applicationDidEnterBackground 不会被触发,而 applicationWillResignActive 会被触发。我听说人们说虽然它也可以在其他情况下触发,所以我仍在测试它是否有问题,但到目前为止还没有! ;)

这里删除imageview:

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

希望这会有所帮助!

旁注:我在模拟器和真机上都测试过:它不会在模拟器上显示,但在真机上会显示!

【讨论】:

  • 有一个缺点:在其他情况下,当用户拉下通知停靠栏时,会调用 applicationWillResignActive。因此,当您希望看到应用内容时,您从顶部向下滑动手指并看到该图像。
  • 最好在applicationWillResignActive上模糊敏感信息,在aplicationDidEnterBackground上设置imageView
  • 这可行,但部署到 iOS7 时存在旋转错误,使用 xCode6 构建:stackoverflow.com/questions/26147068/…
  • 如果我编写了您在applicationWillResignActive 中提到的代码,那么当我将我的应用程序带回前台状态时会看到什么?我会看到“Portrait(768x1024).png”图像还是实际屏幕?
  • @Pratik:你会看到图像,除非你在 applicationDidBecomeActive 方法中再次删除它(见上文)。
【解决方案3】:

这种快速简便的方法将在 iOS7 或更高版本的应用切换器中的应用图标上方生成黑色快照。

首先,获取您应用的关键窗口(通常在 AppDelegate.m 中的 application:didFinishLaunchingWithOptions 中设置),并在您的应用即将进入后台时将其隐藏:

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

然后,当您的应用再次激活时,取消隐藏您的应用的关键窗口:

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

此时,查看应用切换器并确认您在应用图标上方看到黑色快照。我注意到,如果您在将应用程序移至后台后立即启动应用程序切换器,则可能会有约 5 秒的延迟,您会看到应用程序的快照(您要隐藏的快照!),之后它转换为全黑快照。我不确定延迟是怎么回事;如果有人有任何建议,请加入。

如果你想在切换器中使用黑色以外的颜色,你可以通过添加一个带有你想要的任何背景颜色的子视图来做这样的事情:

- (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 快照作为视图并为其添加模糊。然后我将此视图添加到应用程序窗口

    如何做到这一点:

    1. 在 appDelegate 实现之前添加一行:

      static const int kNVSBlurViewTag = 198490;//or wherever number you like
      
    2. 添加此方法:

      - (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. 让你的 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];
      }
      

    我在SwiftObjective C 中创建了示例项目。 这两个项目都采取了以下行动:

    -application:didResignActive - 快照被创建、模糊并添加到应用窗口

    -application:willBecomeActive 正在从窗口中删除模糊视图。

    使用方法:

    客观 C

    1. AppDelegate+NVSBlurAppScreen.h 和.m 文件添加到您的项目中

    2. 在您的 -applicationWillResignActive: 方法中添加以下行:

      [self nvs_blurPresentedView];
      
    3. 在您的 -applicationDidEnterBackground: 方法中添加以下行:

      [self nvs_unblurPresentedView];
      

    斯威夫特

    1. 将 AppDelegateExtention.swift 文件添加到您的项目中

    2. 在您的 applicationWillResignActive 函数中添加以下行:

      blurPresentedView()
      
    3. 在您的 applicationDidBecomeActive 函数中添加以下行:

      unblurPresentedView()
      

    【讨论】:

      【解决方案5】:

      如果只在applicationWillResignActive函数中使用[self.window addSubview:imageView];,这个imageView不会覆盖UIAlertView、UIActionSheet或者MFMailComposeViewController...

      最好的解决办法是

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

      【讨论】:

      • 如果您在 web 视图中以全屏模式播放视频,这是非常好的解决方案!
      • 优秀!。即使我们在进入多任务切换器之前打开了一个键盘,它也可以工作!谢谢
      【解决方案6】:

      提供我自己的解决方案作为“答案”,尽管这个解决方案非常不可靠。有时我会得到一个黑屏作为屏幕截图,有时是 XIB,有时是来自应用程序本身的屏幕截图。取决于设备和/或如果我在模拟器中运行它。

      请注意,我无法为此解决方案提供任何代码,因为其中包含许多特定于应用程序的详细信息。但这应该可以解释我的解决方案的基本要点。

      在 appDelegate.m 下的 applicationWillResignActive 我检查我们是否 运行 iOS7,如果我们这样做,我会加载一个空的新视图 app-logo 在中间。一旦 applicationDidBecomeActive 被调用我 重新启动我的旧视图,这些视图将被重置 - 但这适用于 我正在开发的应用程序类型。

      【讨论】:

      • 如果您看到相机应用程序的作用 - 它在进入背景时将图像转换为模糊的图像(您可以看到转换为图标)
      • @Petesh 是的,这是一个很好的实现,但问题是他们是如何做到的。我害怕私有 API。
      • @Tommie 你说“取决于设备和/或我是否在模拟器中运行它”。对我来说,它似乎可以在设备上工作(虽然我没有做过详尽的测试),但不是模拟器。您是否发现它无法在设备上运行?
      【解决方案7】:

      您可以使用激活器来配置双击主页按钮启动多任务,并禁用默认双击主页按钮和启动多任务窗口。此方法可用于将屏幕截图更改为应用程序的默认图像。这适用于具有默认密码保护功能的应用程序。

      【讨论】:

        【解决方案8】:

        Xamarin.iOS

        改编自https://stackoverflow.com/a/20040270/7561

        我想显示我的启动屏幕,而不只是显示颜色。

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

        【讨论】:

          猜你喜欢
          • 2012-10-26
          • 2017-12-02
          • 1970-01-01
          • 2013-12-26
          • 1970-01-01
          • 2023-03-19
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多