Search code examples
iosobjective-cxcodeappdelegatensnotificationcenter

NSNotificationCenter not firing when application is terminated and launched again in iOS


I have a logistics app which has a requirement to disable the screen recording, and I don't want people to use the new iOS-11 feature to record the screen with sensitive datas and make them public. Since disabling screen recording is not possible in iOS so i tried a work around by detecting the iOS11 screen recording feature On or Off. I used isCaptured and UIScreenCapturedDidChange Notification. The code is given below:

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

So the logic is when the screen recording starts the notification is fired and the logic of placing the black color on video while recording is happening and when the recording stops the black color is removed. This works fine when the application is moved to background , active , inactive and foreground scenarios. But when the application is killed(terminated) while screen recording is still going on and when we launch the application again while screen recording is still going on the black color doesn't covers the screen. So how to call the notification selector again with the selector method working


Solution

  • Check the value of the screen's isCaptured property in application:didFinishLaunchingWithOptions: and show or hide the overlay view accordingly.

    UIWindow+ScreenCapture.h:

    #import <UIKit/UIKit.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface UIWindow (ScreenCapture)
    
    - (void)showOrHideContentDependingOnCapturedState;
    - (void)hideContent;
    - (void)showContent;
    
    @end
    
    NS_ASSUME_NONNULL_END
    

    UIWindow+ScreenCapture.m:

    #import "UIWindow+ScreenCapture.h"
    
    @implementation UIWindow (ScreenCapture)
    
    - (void)showOrHideContentDependingOnCapturedState {
        if (self.screen.isCaptured) {
            [self hideContent];
        } else {
            [self showContent];
        }
    }
    
    - (void)hideContent {
        UIView *blackView = [self viewWithTag:1234];
        if (!blackView) {
            blackView = [[UIView alloc] initWithFrame:self.bounds];
        }
    
        blackView.tag = 1234;
        blackView.backgroundColor = UIColor.blackColor;
        blackView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    
        // This is important! If this is not set, then any new view added to
        // the window (like the root view controller's view) will be overtop of
        // `blackView`, which we don't want.
        blackView.layer.zPosition = 10000;
    
        [self addSubview:blackView];
    }
    
    - (void)showContent {
        [[self viewWithTag:1234] removeFromSuperview];
    }
    
    @end
    

    AppDelegate.h:

    #import <UIKit/UIKit.h>
    
    @interface AppDelegate : UIResponder <UIApplicationDelegate>
    
    @property (nullable, strong, nonatomic) UIWindow *window;
    
    @end
    

    AppDelegate.m:

    #import "AppDelegate.h"
    #import "UIWindow+ScreenCapture.h"
    
    @implementation AppDelegate
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(checkIsBeingRecorded)
                                                     name:UIScreenCapturedDidChangeNotification
                                                   object:nil];
        [self.window showOrHideContentDependingOnCapturedState];
    
        return YES;
    }
    
    - (void)checkIsBeingRecorded {
        for (UIWindow *window in UIApplication.sharedApplication.windows) {
            [window showOrHideContentDependingOnCapturedState];
        }
    }
    
    @end