I have an app which plays video, and I don't want people to use the new iOS-11 feature to record these videos and make them public. That feature is described here.
I could not find any documentation regarding an option for my app to prevent users from recording it.
Can anybody please guide me to anything related to this?
Thank you!
I am publishing here the official response from Apple Developer Technical Support (DTS):
While there is no way to prevent screen recording, as part of iOS 11, there are new APIs on UIScreen that applications can use to know when the screen is being captured:
UIScreen.isCaptured Instance Property
UIScreenCapturedDidChange Notification Type Property
The contents of a screen can be recorded, mirrored, sent over AirPlay, or otherwise cloned to another destination. UIKit sends the UIScreenCapturedDidChange notification when the capture status of the screen changes.
The object of the notification is the UIScreen object whose isCaptured property changed. There is no userInfo dictionary. Your application can then handle this change and prevent your application content from being captured in whatever way is appropriate for your use.
HTH!
The feature is available on and above iOS11. Better keep it inside didFinishLaunchingWithOptions
Objective-C syntax
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if (#available(iOS 11.0, *)) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(screenCaptureChanged) name:UIScreenCapturedDidChangeNotification object:nil];
}
return YES;
}
-(void)screenCaptureChanged{
if (#available(iOS 11.0, *)) {
BOOL isCaptured = [[UIScreen mainScreen] isCaptured];// will keep on checking for screen recorder if it is runnuning or not.
if(isCaptured){
UIView *colourView = [[UIView alloc]initWithFrame:self.window.frame];
colourView.backgroundColor = [UIColor blackColor];
colourView.tag = 1234;
colourView.alpha = 0;
[self.window makeKeyAndVisible];
[self.window addSubview:colourView];
// fade in the view
[UIView animateWithDuration:0.5 animations:^{
colourView.alpha = 1;
}];
}else{
// grab a reference to our coloured view
UIView *colourView = [self.window viewWithTag:1234];
// fade away colour view from main view
[UIView animateWithDuration:0.5 animations:^{
colourView.alpha = 0;
} completion:^(BOOL finished) {
// remove when finished fading
[colourView removeFromSuperview];
}];
}
} else {
// Fallback on earlier versions
// grab a reference to our coloured view
UIView *colourView = [self.window viewWithTag:1234];
if(colourView!=nil){
// fade away colour view from main view
[UIView animateWithDuration:0.5 animations:^{
colourView.alpha = 0;
} completion:^(BOOL finished) {
// remove when finished fading
[colourView removeFromSuperview];
}];
}
}
}
Related
I'd like to display a custom View Controller immediately each time the user returns to the app. Currently I can do this easily with didFinishLaunchingWithOptions by simply choosing what the initial rootViewController will be before anything appears on the screen.
However if I put the intercept VC in applicationDidBecomeActive, then the previous VC is on screen for half a second, before I can load the intercept.
How can I make it so when the app is put back into foreground the VC immediately on screen is my custom intercept? That VC will then restore the foreground view on its own.
FYI: I am using this intercept to verify the user is within supported location, then allowing the app to return to state or display an unsupported screen.
There are two solutions to this problem.
Solution:1 You could write your interceptVC - functionality on the application's delegate method
func applicationWillEnterForeground(application: UIApplication)
instead of writing in
func applicationDidBecomeActive(application: UIApplication)
Solution:2
As you did the interceptVC - functionary on applicationDidBecomeActive can also be applied to while application went background,
func applicationDidEnterBackground(application: UIApplication)
so that, when the applicationDidBecomActive delay can be covered.
Note: Here the application once entered background will always has the interceptVC in the background.
Solution by OP.
A solution I used was to set a custom background image when the app resigns active. This is also the screen shown in the multitask selector. When the app resumes active it is the initial screen shown until my interceptVC loads. The image I used is the same background as my interceptVC so it appears instant. This was also easier than attempting to preload the intercept VC on resign of active. Some fade animations are also used on the imageview to make it smoother and non-jarring.
- (void)applicationWillResignActive:(UIApplication *)application {
// fill screen with our own imageView
UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.window.frame];
if(IS_IPHONE_6P){
imageView.image = [UIImage imageNamed:#"splash_1242x2208.png"];
} else if(IS_IPHONE_6){
imageView.image = [UIImage imageNamed:#"splash_750x1334.png"];
} else if(IS_IPHONE_5){
imageView.image = [UIImage imageNamed:#"splash_640x1136.png"];
} else if(IS_IPHONE_4_OR_LESS){
imageView.image = [UIImage imageNamed:#"splash_640x960.png"];
} else {
// should not happen
imageView.image = [UIImage imageNamed:#"splash_750x1334.png"];
}
imageView.tag = 1234;
imageView.alpha = 0;
[self.window addSubview:imageView];
[self.window bringSubviewToFront:imageView];
// fade in the view
[UIView animateWithDuration:0.5 animations:^{
imageView.alpha = 1;
}];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// grab a reference to our imageView
UIView *imageView = [self.window viewWithTag:1234];
// fade away imageView view from main view
[UIView animateWithDuration:0.5 animations:^{
imageView.alpha = 0;
} completion:^(BOOL finished) {
// remove when finished fading
[imageView removeFromSuperview];
}];
}
I'm trying to pause my game when the app gets interrupted! (like Phonecalls, SMS, etc.)
I created a pause menu in my Game Viewcontroller (rush_gamemode).
When I press the pause Button in the game everything works just fine.
If I call the method via "applicationWillResignActive" in AppDelegate it does work kind of.
Here's my Code:
in rush_gamemode.h
-(void)goIntoPause;
in rush_gamemode.m
-(void)goIntoPause
{
NSLog(#"RUSH goIntoPause was called!");
self.Button_Pause.hidden = YES;
//--------pause timer-------//
if (self.timerStart) {
timerWasStarted = YES;
self.oldTimeNumber = self.timeNumber;
[self.timerStart invalidate];
self.timerStart = nil;
}
//--------set up pause menu--------//
self.transparent_subview_background.alpha = 0;
self.Pause_Subview.hidden = NO;
self.Pause_Subview.backgroundColor = [UIColor clearColor];
[UIView beginAnimations:NULL context:NULL];
[UIView setAnimationDuration:.75];
[UIView setAnimationCurve: UIViewAnimationCurveEaseInOut];
[self.transparent_subview_background setAlpha:0.75];
[UIView commitAnimations];
}
in AppDelegate.h
#class rush_gamemode;
#interface AppDelegate : UIResponder <UIApplicationDelegate>
{
rush_gamemode* rush;
}
in AppDelegate.m I imported "rush_gamemode.h"
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
rush = [[rush_gamemode alloc] init];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
[rush goIntoPause];
}
So when I start the App, and press the HomeButton (e.g) or get a Phone call, the console shows the NSLog ("RUSH goIntoPause was called!") but doesn't do anything else..
What am I doing wrong here?
cheers, Niklas
I have an app that uses a xib defined AdBannerView. If the app runs on an iPhone (4 or 5) everything works as expected, ads get shown, banners get hidden / shown etc.
However if the app is run on an iPad it crashes after repeatedly failing to receive the ad. Examining the call stack shows repeated calls to bannerView:didFailToReceiveAdWithError:
Watching allocations while its running on an iPad shows continuous memory growth until the crash.
Messing with the network connectivity doesn't seem to alter the fact that it works on an iPhone but not on an iPad.
I read this SO question which instead of using a AdBannerView in the xib it creates it on the fly and then releases it appropriately when the ad fails to load.
EDIT:
I changed the devices setting in the project file from iPhone to Universal. The app now does not crash but of course all the views are now 'messed up'. So one option for a fix would be to implement the iPad idiom throughout the app.
My questions are -
What is going on? No, really! I'm confused as to why there is differing behaviour between devices.
Should I look to creating the AdBannerView programmatically? That kind of feels defeatist.
How can I fix this behaviour?
Here is the code
#pragma mark ADBannerViewDelegate
- (void)bannerViewDidLoadAd:(ADBannerView *)banner
{
[self showBanner];
}
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
[self hideBanner];
}
- (void)bannerViewActionDidFinish:(ADBannerView *)banner
{
[self hideBanner];
}
#pragma mark ADBanner helpers
- (void)hideBanner
{
CGRect hiddenFrame = self.bannerDisplayFrame;
hiddenFrame.origin.y = self.view.frame.size.height;
[UIView animateWithDuration:0.3f
animations:^{
[self.adBannerView setFrame:hiddenFrame];
}
completion:^(BOOL finished)
{
if (finished)
{
[self.adBannerView setAlpha:0.0f];
}
}];
}
- (void)showBanner
{
[self.adBannerView setAlpha:1.0f];
[UIView animateWithDuration:0.3f
animations:^{
[self.adBannerView setFrame:self.bannerDisplayFrame];
}
completion:^(BOOL finished)
{
if (finished)
{
[NSTimer scheduledTimerWithTimeInterval:60.0f target:self selector:#selector(hideBanner) userInfo:nil repeats:NO];
}
}];
}
It looks like you are creating new iAD banner views every time, the suggested way is to use a shared one throughout the whole app. This might be the reason of continuous memory growth in your app and you will definitely end up with a warning from apple servers if you request ads too many times. Have a look at here in Apple's documentation for more details iAD Best Practices
This is how I implemented shared adbannerview, it might be of help.
AppDelegate.h
#property (nonatomic, strong) ADBannerView *adBanner;
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...
adBanner = [[ADBannerView alloc] initWithFrame:CGRectZero];
adBanner.delegate = self;
adBanner.backgroundColor = [UIColor clearColor];
adBanner.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleTopMargin;
...
}
prefix.pch or better in a header file included in prefix.pch
#define SharedAdBannerView ((AppDelegate *)[[UIApplication sharedApplication] delegate]).adBanner
And I have a implemented a uiviewcontroller category to handle iADs
#implementation UIViewController (SupportIAD)
-(void)bannerViewDidLoadAd:(ADBannerView *)banner
{
SharedAdBannerView.hidden = FALSE;
}
-(void) bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
SharedAdBannerView.hidden = TRUE;
}
//This method adds shared adbannerview to the current view and sets its location to bottom of screen
//Should work on all devices
-(void) addADBannerViewToBottom
{
SharedAdBannerView.delegate = self;
//Position banner just below the screen
SharedAdBannerView.frame = CGRectMake(0, self.view.bounds.size.height, 0, 0);
//Height will be automatically set, raise the view by its own height
SharedAdBannerView.frame = CGRectOffset(SharedAdBannerView.frame, 0, -SharedAdBannerView.frame.size.height);
[self.view addSubview:SharedAdBannerView];
}
-(void) removeADBannerView
{
SharedAdBannerView.delegate = nil;
[SharedAdBannerView removeFromSuperview];
}
#end
And now in every viewcontroller that is going to display iADs, import the category and in viewDidLoad:
- (void)viewDidLoad
{
...
[self removeADBannerView];
[self addADBannerViewToBottom];
...
}
To prevent the views getting messed up, try turning "Auto Layout" off.
Xcode 4.5 corrupting XIBs?
I have solved this problem.
The root of the problem is that iPad's view property of iPad's UIViewController looping recursively.
All you need is to break infinite call.
In my case I just add these lines:
if (_banner.alpha == 0)
{
return;
}
in banner hiding method.
I guess you have crash here:
hiddenFrame.origin.y = self.view.frame.size.height;
Anyway, its not a good approach do not check property before changing.
I have some text displayed in an editable webView. As soon as I scroll it down and touch somewhere to edit the rendered text, it scrolls to the top itself and the keyboard appears and hence I have to scroll it down again for editing. Is there a way to prevent webView from doing that?
Got the same problem and still looking for normal solution of this weird behavior.
We still cannot prevent UIWebView from doing this, and if you look at Evernote application on iPad, you'll see the same issue there, unfortunately :(
The only thing we could do on this is to save contentOffset of UIWebView when keyboard is shown and restore if after keyboard is opened.
This will look like:
//register your controller for keyboard notifications
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWasShown:) UIKeyboardDidShowNotification object:nil];
Then you will need to handle keyboard notification like:
- (void)keyboardWillShow:(NSNotification *)aNotification {
// scroll view will scroll to beginning, but we save current offset
[_yourViewWithWebView saveOffset];
...
}
After that you will need to handle event when keyboard was shown:
- (void)keyboardWasShown:(NSNotification*)aNotification{
...
// scroll view scrolled to beginning, but we restore previous offset
[_yourViewWithWebView restoreOffset];
}
Accordingly in your view which contains UIWebView you'll need to implement:
static CGPoint editableWebViewOffsetPoint;
- (void) saveOffset{
editableWebViewOffsetPoint = yourWebView.scrollView.contentOffset;
}
- (void) restoreOffset{
//just use animation block to have scroll animated after jumping to top and back to old position
[UIView animateWithDuration:.2
delay:0
options:UIViewAnimationOptionCurveEaseIn
animations:^{
yourWebView.scrollView.contentOffset = editableWebViewOffsetPoint;
}
completion:nil];
}
Hope in general this will help you to solve your problem at least partially.
If someone will help us to prevent UIWebView scrolling to top each time keyboard is displayed, I'd appreciate this deeply.
UIWebView.scrollView.scrollsToTop = NO; does not help.
Disabling scrolling before showing keyboard and enabling it after keyboard is displayed also didn't work.
Also in future you will face problem with editing text when cursor is not in visible area of UIWebView - and it does not scroll itself automatically to make cursor visible. We have solved that problem, but I am in progress of creating detailed and readable tutorial of how we've done this. If you already solved this problem, I'd appreciate to look at your solution :)
PS: http://www.cocoanetics.com/2011/01/uiwebview-must-die/
Thank you,
Sergey N.
A method that works rather well is temporarily disabling setContentOffset: on UIScrollView, while the keyboard is being shown. This is a little hackish though, so it may cause other issues instead, in some situations.
As in #Sergey N.'s response, register for the keyboard notifications, but instead of storing/restoring contentOffset, use these:
- (void)keyboardWillShow:(NSNotification *)aNotification {
[self disableMethod:#selector(setContentOffset:) onClass:[UIScrollView class]];
}
- (void)keyboardWasShown:(NSNotification *)aNotification {
[self enableMethod:#selector(setContentOffset:) onClass:[UIScrollView class]];
}
Somewhere else in the class (or in another class, as long as you replace self in above calls), place these:
-(void)swizzleMethod:(SEL)origSel from:(Class)origClass toMethod:(SEL)toSel from:(Class)toClass{
Method origMethod = class_getInstanceMethod(origClass, origSel);
Method newMethod = class_getInstanceMethod(toClass, toSel);
method_exchangeImplementations(origMethod, newMethod);
}
-(void)disableMethod:(SEL)sel onClass:(Class)cl{
[self swizzleMethod:sel from:cl toMethod:#selector(doNothing) from:[self class]];
}
-(void)enableMethod:(SEL)method onClass:(Class)cl{
[self swizzleMethod:#selector(doNothing) from:[self class] toMethod:method from:cl];
}
-(void)doNothing{
}
This prevents the webview from scrolling to top in the first place, so it won't show that bad animation, however, in some situations it may cause some problems (e.g have more input controls in the view holding the webview). Tested this successfully in iOS 5.0+.
In iOS 6.0 the scrolling to top seems to be fixed, so no workaround is necessary.
Functions for "editing text when cursor is not in visible area" problem.
- (void)keyboardWasShown:(NSNotification *)aNotification {
//if(self.navigationController.viewControllers objectAtIndex:([self.navigationController.viewControllers count]-1)==self.)
NSLog(#"keyboardshown");
if (keyboardshown)
return;
keyboardshown=YES;
NSDictionary* userInfo = [aNotification userInfo];
CGRect keyboardEndFrame;
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
CGRect newFrame = self.textView.frame;
CGRect keyboardFrame = [self.textView convertRect:keyboardEndFrame toView:nil];
newFrame.size.height -= keyboardFrame.size.height;
[UIView beginAnimations:#"ResizeForKeyboard" context:nil];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.3];
[self.textView setFrame:newFrame];
[UIView commitAnimations];
}
- (void)keyboardWasHidden:(NSNotification *)aNotification {
if (!keyboardshown)
return;
keyboardshown=NO;
NSDictionary* userInfo = [aNotification userInfo];
CGRect keyboardEndFrame;
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
CGRect newFrame = self.textView.frame;
CGRect keyboardFrame = [self.textView convertRect:keyboardEndFrame toView:nil];
newFrame.size.height += keyboardFrame.size.height;
[UIView beginAnimations:#"ResizeForKeyboard" context:nil];
[UIView setAnimationDuration:0.3];
self.textView.frame = newFrame;
[UIView commitAnimations];
}
Actually keyboardWasShown will not always be invoked especially when user has BT keyboard connected and virtual one can be hidden/shown by Eject key. We have implemented our own class like:
#implementation KeyboardUtils
+ (CGRect) convertRect:(CGRect)rect toView:(UIView *)view {
UIWindow *window = [view isKindOfClass:[UIWindow class]] ? (UIWindow *) view : [view window];
return [view convertRect:[window convertRect:rect fromWindow:nil] fromView:nil];
}
/**
* This is working but deprecated solution
* Based on UIKeyboardCenterBeginUserInfoKey and UIKeyboardCenterEndUserInfoKey which are deprecated since iOS 3.2
*/
+ (BOOL)checkKeyboardOnDisplayCenterBegin:(CGRect)centerBegin centerEnd:(CGRect)centerEnd{
CGRect mainScreen = [UIApplication currentBounds];
BOOL isKeyboardOnDisplay = CGRectContainsPoint(mainScreen, centerEnd.origin);
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithBool:isKeyboardOnDisplay] forKey:#"isKeyboardOnDisplay"];
[[NSUserDefaults standardUserDefaults] synchronize];
return isKeyboardOnDisplay;
}
/**
* This method allows to verify if software keyboard is currently present on screen for the application
* Allows to handle undocked, split states of keyboard, as well as connected Bluetooth keyboard.
* Needed to adjust UI - scrolling and insets for editable parts of the app, as well as avoid application be beneath open keyboard
*/
+ (BOOL)checkKeyboardOnDisplayBeginFrame:(CGRect)frameBegin endFrame:(CGRect)frameEnd{
CGRect mainScreen = [UIApplication currentBounds];
UIView *firstView = [[(AppDelegate *)[[UIApplication sharedApplication] delegate] window].subviews objectAtIndex:0];
CGRect convertedEndFrame = [KeyboardUtils convertRect:frameEnd toView:firstView];
BOOL isKeyboardOnDisplay = CGRectContainsRect(mainScreen, convertedEndFrame);
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithBool:isKeyboardOnDisplay] forKey:#"isKeyboardOnDisplay"];
[[NSUserDefaults standardUserDefaults] synchronize];
return isKeyboardOnDisplay;
}
+ (BOOL)checkKeyboardOnDisplayFromNotification:(NSNotification *)aNotification{
BOOL isKeyboardOnDisplay = [KeyboardUtils checkKeyboardOnDisplayBeginFrame:[[aNotification.userInfo valueForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue]
endFrame:[[aNotification.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]];
return isKeyboardOnDisplay;
}
Then you can use it like:
- (void)keyboardWillChangeFrame:(NSNotification*)aNotification{
[KeyboardUtils checkKeyboardOnDisplayFromNotification:aNotification];
}
Where keyboardWillChangeFrame is selector-observer for:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
In such a way you are saving state of your keyboard (if it is shown as docked one and really present on display, and BT keyboard is not used) into NSUserDefaultSettings. In your handlers which listen to keyboard notifications or orientation changes you should check this key value from the defaults.
One more additional method is [UIApplication currentBounds];
It is present in the app by extending it with category like: (.h file)
#import <UIKit/UIKit.h>
#interface UIApplication (AppDimensions)
+(CGSize) currentSize;
+(CGRect) currentBounds;
+(CGSize) sizeInOrientation:(UIInterfaceOrientation)orientation;
#end
.m file:
#import "UIApplication+AppDimensions.h"
#implementation UIApplication (AppDimensions)
+(CGSize) currentSize
{
return [UIApplication sizeInOrientation:[UIApplication sharedApplication].statusBarOrientation];
}
+(CGRect) currentBounds{
CGRect bounds = [UIScreen mainScreen].bounds;
bounds.size = [UIApplication currentSize];
return bounds;
}
+(CGSize) sizeInOrientation:(UIInterfaceOrientation)orientation
{
CGSize size = [UIScreen mainScreen].bounds.size;
UIApplication *application = [UIApplication sharedApplication];
if (UIInterfaceOrientationIsLandscape(orientation))
{
size = CGSizeMake(size.height, size.width);
}
if (application.statusBarHidden == NO)
{
size.height -= MIN(application.statusBarFrame.size.width, application.statusBarFrame.size.height);
}
return size;
}
#end
Hope this will help anyone who is concerned about handling presence of keyboard on the screen.
I'm wanting to spoof the feel of the main splash screen fading out whenever applicationDidBecomeActive is called, but it's not working. What am I doing wrong?
- (void)applicationDidBecomeActive:(UIApplication *)application
{
if(IS_IPHONE_5)
splash = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Default-568h.png"]];
else
splash = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Default.png"]];
[self.window.rootViewController.view addSubview:splash];
[UIView animateWithDuration:0.5
animations:^{
splash.alpha = 0;
}
completion:^(BOOL finished) {
[splash removeFromSuperview];
}];
}
Then you need to define the following somewhere. I use the project .pch but you can use your header if you want.
#define IS_IPHONE_5 ( fabs( ( double )[ [ UIScreen mainScreen ] bounds ].size.height - ( double )568 ) < DBL_EPSILON )
I find, from ios6 you get a nice transition doing this
-(BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[UIView animateWithDuration:0.2
delay:0
options: UIViewAnimationCurveEaseIn
animations:^{
self.window.viewForBaselineLayout.alpha = 0; // and at this alpha
}
completion:^(BOOL finished){
}];
return YES;
}
then immediately at the start of
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[UIView animateWithDuration:0.5
delay:0
options: UIViewAnimationCurveEaseOut
animations:^{
self.window.viewForBaselineLayout.alpha = 1; // and at this alpha
}
completion:^(BOOL finished){
}];
It gives a cross fadeish effect from the loading screen to the now loaded app screen.
If that is really your code, you probably have a typo in the image name. (If not, let us know what "not working" means.)
Also, the splash screen doesn't normally come up every applicationDidBecomeActive:. didFinishLaunchingWithOptions: is the time you know that you have been launched and the splash screen had been shown on your behalf.
Try adding it directly to your window instead of the rootViewController.view.
[self.window addSubview:splash];
You may also need to rotate the image using view.transform to align with the startup image.
Your code looks about right; I do this in several apps.
However, you want to do this as part of applicationDidFinishLaunching:options: and not in applicationDidBecomeActive:. It only makes sense to fade the splash screen when it is shown, which is only when the app is launched and not already running. When your app becomes active, it may have been in the background -- i.e. already launched -- so fading the splash screen in this case doesn't make sense.
Or, did you want your splash screen to appear ALWAYS when it becomes active, even if it is resumed from the background from a suspended state?