在 iOS 7 多任务切换器中控制屏幕截图
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18959411/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Controlling the screenshot in the iOS 7 multitasking switcher
提问by Tommie
I've been trying to find some information regarding the new multitasking switcher in iOS 7 and especially the screenshot that the OS takes when the app is going into hibernation.
我一直在尝试查找有关 iOS 7 中新的多任务切换器的一些信息,尤其是当应用程序进入休眠状态时操作系统截取的屏幕截图。
Is there any way to completely turn off this feature or screenshot? Or can I hide the app altogether from the switcher? The app needs to run in the background, but we do not want to show any screenshot from the app.
有什么办法可以完全关闭这个功能或截图吗?或者我可以从切换器中完全隐藏该应用程序吗?该应用程序需要在后台运行,但我们不想显示该应用程序的任何屏幕截图。
The screenshot is potentially a security-risk, think along the lines for banking-apps where your card number or account summary will be available to anyone that double-click on the home button on the device.
屏幕截图可能存在安全风险,请考虑银行应用程序,其中双击设备上的主页按钮的任何人都可以使用您的卡号或帐户摘要。
Anyone with any insight into this? Thanks.
有人对此有任何见解吗?谢谢。
回答by Rob
In Preparing Your UI to Run in the Background, Apple says:
在准备您的 UI 以在后台运行时,Apple 说:
Prepare Your UI for the App Snapshot
At some point after your app enters the background and your delegate method returns, UIKit takes a snapshot of your app's current user interface. The system displays the resulting image in the app switcher. It also displays the image temporarily when bringing your app back to the foreground.
Your app's UI must not contain any sensitive user information, such as passwords or credit card numbers. If your interface contains such information, remove it from your views when entering the background. Also, dismiss alerts, temporary interfaces, and system view controllers that obscure your app's content. The snapshot represents your app's interface and should be recognizable to users. When your app returns to the foreground, you can restore data and views as appropriate.
为应用程序快照准备 UI
在您的应用程序进入后台并且您的委托方法返回后的某个时刻,UIKit 会拍摄您应用程序当前用户界面的快照。系统在应用切换器中显示生成的图像。将您的应用程序带回前台时,它还临时显示图像。
您应用的 UI 不得包含任何敏感的用户信息,例如密码或信用卡号。如果您的界面包含此类信息,请在进入后台时将其从您的视图中删除。此外,关闭使您的应用程序内容变得模糊的警报、临时界面和系统视图控制器。快照代表您的应用程序界面,用户应该可以识别。当您的应用返回前台时,您可以根据需要恢复数据和视图。
See Technical Q&A QA1838: Preventing Sensitive Information From Appearing In The Task Switcher
请参阅技术问答 QA1838:防止敏感信息出现在任务切换器中
In addition to obscuring/replacing sensitive information, you might also want to tell iOS 7 to not take the screen snapshot via ignoreSnapshotOnNextApplicationLaunch
, whose documentation says:
除了隐藏/替换敏感信息之外,您可能还想告诉 iOS 7 不要通过 获取屏幕快照ignoreSnapshotOnNextApplicationLaunch
,其文档说:
If you feel that the snapshot cannot correctly reflect your app's user interface when your app is relaunched, you can call
ignoreSnapshotOnNextApplicationLaunch
to prevent that snapshot image from being taken.
如果您觉得重新启动应用程序时快照无法正确反映应用程序的用户界面,您可以调用
ignoreSnapshotOnNextApplicationLaunch
以防止拍摄该快照图像。
Having said that, it appears that the screen snapshot is still taken and I have therefore filed a bug report. But you should test further and see if using this setting helps.
话虽如此,屏幕快照似乎仍在拍摄,因此我提交了错误报告。但是您应该进一步测试,看看使用此设置是否有帮助。
If this was an enterprise app, you might also want to look into the appropriate setting of allowScreenShot
outlined in the Restrictions Payloadsection of the Configuration Profile Reference.
如果这是一个企业应用程序,您可能还需要查看配置配置文件参考allowScreenShot
的限制负载部分中概述的适当设置。
Here is an implementation that achieves what I needed. You can present your own UIImageView
, or your can use a delegate-protocol pattern to obscure the confidential information:
这是一个实现我所需要的实现。您可以展示自己的UIImageView
,也可以使用委托协议模式来隐藏机密信息:
// SecureDelegate.h
#import <Foundation/Foundation.h>
@protocol SecureDelegate <NSObject>
- (void)hide:(id)object;
- (void)show:(id)object;
@end
I then gave my app delegate a property for that:
然后我给了我的应用程序委托一个属性:
@property (weak, nonatomic) id<SecureDelegate> secureDelegate;
My view controller sets it:
我的视图控制器设置它:
- (void)viewDidLoad
{
[super viewDidLoad];
AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
delegate.secureDelegate = self;
}
The view controller obviously implements that protocol:
视图控制器显然实现了该协议:
- (void)hide:(id)object
{
self.passwordLabel.alpha = 0.0;
}
- (void)show:(id)object
{
self.passwordLabel.alpha = 1.0;
}
And, finally, my app delegate avails itself of this protocol and property:
最后,我的应用程序委托利用了这个协议和属性:
- (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:"];
}
Note, I'm using applicationWillResignActive
rather than the advised applicationDidEnterBackground
, because, as others have pointed out, the latter is not called when double tapping on the home button while the app is running.
请注意,我使用的是applicationWillResignActive
而不是 建议applicationDidEnterBackground
,因为正如其他人所指出的那样,在应用程序运行时双击主页按钮时不会调用后者。
I wish I could use notifications to handle all of this, rather than the delegate-protocol pattern, but in my limited testing, the notifications aren't handled in a timely-enough manner, but the above pattern works fine.
我希望我可以使用通知来处理所有这些,而不是委托协议模式,但在我有限的测试中,通知没有及时处理,但上述模式工作正常。
回答by Laura
This is the solution I worked with for my application:
这是我为我的应用程序使用的解决方案:
As Tommy said: You can use the applicationWillResignActive. What I did was making a UIImageView with my SplashImage and add it as subview to my main window-
正如汤米所说:您可以使用 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];
}
I used this method instead of applicationDidEnterBackground because applicationDidEnterBackground won't be triggered if you doubletap the home button, and applicationWillResignActive will be. I heard people say though it can be triggered in other cases aswell, so I'm still testing around to see if it gives problem, but none so far! ;)
我使用这个方法而不是 applicationDidEnterBackground 因为如果你双击主页按钮不会触发 applicationDidEnterBackground,而 applicationWillResignActive 将被触发。我听到人们说虽然它也可以在其他情况下触发,所以我仍在测试它是否有问题,但到目前为止还没有!;)
Here to remove the imageview:
在这里删除图像视图:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
if(imageView != nil) {
[imageView removeFromSuperview];
imageView = nil;
}
}
Hope this helps!
希望这可以帮助!
Sidenote: I tested this on both the simulator and a real device: It Won't Show on the simulator, but it does on a real device!
旁注:我在模拟器和真实设备上都测试了这个:它不会在模拟器上显示,但它会在真实设备上显示!
回答by John Jacecko
This quick and easy method will yield a black snapshot above your app's icon in the iOS7 or later app switcher.
这种快速简便的方法将在 iOS7 或更高版本的应用程序切换器中您的应用程序图标上方生成一个黑色快照。
First, take your app's key window (typically setup in AppDelegate.m in application:didFinishLaunchingWithOptions), and hide it when your app is about to move into the background:
首先,获取应用程序的关键窗口(通常在应用程序:didFinishLaunchingWithOptions 中的 AppDelegate.m 中设置),并在应用程序即将进入后台时隐藏它:
- (void)applicationWillResignActive:(UIApplication *)application
{
if(isIOS7Or8)
{
self.window.hidden = YES;
}
}
Then, un-hide your app's key window when your app becomes active again:
然后,当您的应用再次处于活动状态时,取消隐藏您的应用的关键窗口:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
if(isIOS7Or8)
{
self.window.hidden = NO;
}
}
At this point, check out the app switcher and verify that you see a black snapshot above your app's icon. I've noticed that if you launch the app switcher immediately after moving your app into the background, there can be a delay of ~5 seconds where you'll see a snapshot of your app (the one you want to hide!), after which it transitions to an all-black snapshot. I'm not sure what's up with the delay; if anyone has any suggestions, please chime in.
此时,检查应用程序切换器并确认您在应用程序图标上方看到黑色快照。我注意到,如果您在将应用程序移入后台后立即启动应用程序切换器,则可能会有大约 5 秒的延迟,您将看到应用程序的快照(您想隐藏的快照!),之后它过渡到全黑快照。我不确定延迟是怎么回事;如果有人有任何建议,请加入。
If you want a color other than black in the switcher, you could do something like this by adding a subview with any background color you'd like:
如果您想要切换器中的黑色以外的颜色,您可以通过添加具有您想要的任何背景颜色的子视图来执行以下操作:
- (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];
}
}
Then, remove this color subview when your app becomes active again:
然后,当您的应用再次激活时删除此颜色子视图:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
if(isIOS7Or8)
{
UIView *colorView = [self.window viewWithTag:9999];
[colorView removeFromSuperview];
}
}
回答by Nikolay Shubenkov
I used the following solution: when application is going to resign I get appWindow snapshot as a View and add blur to it. Then I add this view to app window
我使用了以下解决方案:当应用程序要辞职时,我将 appWindow 快照作为视图并为其添加模糊。然后我将此视图添加到应用程序窗口
how to do this:
这该怎么做:
in appDelegate just before implementation add line:
static const int kNVSBlurViewTag = 198490;//or wherever number you like
add this methods:
- (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; }
make your appDelegate implementation be the as follows:
- (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]; }
在 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]; }
I created Example projects in Swiftand Objective C. Both projects makes the following actions in:
我在Swift和Objective C 中创建了示例项目。这两个项目都在以下方面采取了以下行动:
-application:didResignActive- snapshot is created, blurred and added to app window
-application:didResignActive- 创建、模糊并添加到应用程序窗口的快照
-application:willBecomeActiveblur view is being removed from window.
-application:willBecomeActive模糊视图正在从窗口中删除。
How to use:
如何使用:
Objecitve C
目标C
Add
AppDelegate+NVSBlurAppScreen
.h and .m files to your projectin your -applicationWillResignActive: method add the following line:
[self nvs_blurPresentedView];
in your -applicationDidEnterBackground: method add the following line:
[self nvs_unblurPresentedView];
将
AppDelegate+NVSBlurAppScreen
.h 和 .m 文件添加到您的项目中在您的 -applicationWillResignActive: 方法中添加以下行:
[self nvs_blurPresentedView];
在您的 -applicationDidEnterBackground: 方法中添加以下行:
[self nvs_unblurPresentedView];
Swift
迅速
add AppDelegateExtention.swift file to your project
in your applicationWillResignActive function add the following line:
blurPresentedView()
in your applicationDidBecomeActive function add the following line:
unblurPresentedView()
将 AppDelegateExtention.swift 文件添加到您的项目中
在您的 applicationWillResignActive 函数中添加以下行:
blurPresentedView()
在 applicationDidBecomeActive 函数中添加以下行:
unblurPresentedView()
回答by Zorot
if only use [self.window addSubview:imageView];
in applicationWillResignActive
function, This imageView won't cover UIAlertView, UIActionSheet or MFMailComposeViewController...
如果只[self.window addSubview:imageView];
在applicationWillResignActive
函数中使用,这个 imageView 不会覆盖 UIAlertView、UIActionSheet 或 MFMailComposeViewController...
Best solution is
最好的解决办法是
- (void)applicationWillResignActive:(UIApplication *)application
{
UIWindow *mainWindow = [[[UIApplication sharedApplication] windows] lastObject];
[mainWindow addSubview:imageView];
}
回答by Tommie
Providing my own solution as an "answers", though this solution is very unreliable. Sometimes i get a black screen as the screenshot, sometimes the XIB and sometimes a screenshot from the app itself. Depending on device and/or if i run this in the simulator.
提供我自己的解决方案作为“答案”,尽管这个解决方案非常不可靠。有时我会得到一个黑屏作为屏幕截图,有时是 XIB,有时是应用程序本身的屏幕截图。取决于设备和/或我是否在模拟器中运行它。
Please note i cannot provide any code for this solution since it's a lot of app-specific details in there. But this should explain the basic gist of my solution.
请注意,我无法为此解决方案提供任何代码,因为其中包含许多特定于应用程序的详细信息。但这应该可以解释我的解决方案的基本要点。
In AppDelegate.m under applicationWillResignActive i check if we're running iOS7, if we do i load a new view which is empty with the app-logo in the middle. Once applicationDidBecomeActive is called i re-launch my old views, which will be reset - but that works for the type of application i'm developing.
在 AppDelegate.m 下 applicationWillResignActive 我检查我们是否正在运行 iOS7,如果我们运行,我会加载一个新视图,该视图是空的,中间带有应用程序徽标。一旦 applicationDidBecomeActive 被调用,我将重新启动我的旧视图,该视图将被重置 - 但这适用于我正在开发的应用程序类型。
回答by Fareed.MK
You can use activator to configure double clicking of home button to launch multitasking and disable default double clicking of home button and launching of multitasking window. This method can be used to change the screenshots to the application's default image. This is applicable to apps with default passcode protection feature.
您可以使用激活器配置双击主页按钮启动多任务并禁用默认双击主页按钮和启动多任务窗口。此方法可用于将屏幕截图更改为应用程序的默认图像。这适用于具有默认密码保护功能的应用程序。
回答by ben
Xamarin.iOS
Xamarin.iOS
Adapted from https://stackoverflow.com/a/20040270/7561
改编自https://stackoverflow.com/a/20040270/7561
Instead of just showing a color I wanted to show my launch screen.
我想显示我的启动屏幕,而不是仅仅显示一种颜色。
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();
}