4

I am trying to implement an iOS Clipboard Listener using Objective C which runs in the background listening for copies anywhere outside the app.

The logic I am using is implemented in https://github.com/vitoziv/VIClipboardListener, the main points are:

  1. Add an observer for the UIPasteboardChangedNotification event

    [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(pasteboardChanged:)
                                             name:UIPasteboardChangedNotification
                                           object:nil];
    
  2. Start a background task which will watch for changes to the UIPasteboard

    UIApplication* app = [UIApplication sharedApplication];
    _bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
        [app endBackgroundTask:_bgTask];
        _bgTask = UIBackgroundTaskInvalid;
    }];
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [self checkPasteBoardCount];
    
        [app endBackgroundTask:_bgTask];
        _bgTask = UIBackgroundTaskInvalid;
    });
    
  3. Inside the checkPasteBoardCount method, watch for changes to the UIPasteboard by checking the pasteboard.changeCount every second and comparing to the last value

    UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
    NSInteger changeCount = pasteboard.changeCount;
    NSInteger bgTaskTime = BACKGROUND_TIME;
    while (bgTaskTime >= 0) {
        //NSLog(@"app in background, left %i second.",bgTaskTime);
        if (changeCount != pasteboard.changeCount) {
            [[NSNotificationCenter defaultCenter] postNotificationName:UIPasteboardChangedNotification object:nil];
            changeCount = pasteboard.changeCount;
        }
        [NSThread sleepForTimeInterval:SLEEP_TIME];
        bgTaskTime -= SLEEP_TIME;
    }
    

This should cause our observer's pasteboardChanged method to be called every time there is a change in the UIPasteboard contents. That change should be accessible using the UIPasteboard.string etc. methods.

Running this on an emulator gives perfect results, the pasteboardChanged method gets called on every copy from any app while the app runs in the background, and the contents of the [UIPasteboard generalPasteboard] always contain the copied content.

However, when running this on a real device, despite the fact that the observer is indeed called on every copy, the content of the [UIPasteboard generalPasteboard].string property is almost always nil. On some rare occasions (maybe when quickly reopening the app after copying from outside) the actual value was there, but it seems random.

Are there any context-related rules to accessing the Pasteboard data on a real device, such as only being able to read content created from within the same app? Or could there be differences in thread management between the emulator and a real device?

Any help would be appreciated. Thanks!

P.S. I was only able to test on the one device so far, will try another one to confirm the behavior.

Paul Hristea
  • 1,191
  • 1
  • 7
  • 4
  • Not directly related but you should not be posting the UIPasteboardChangedNotification yourself. – rmaddy Jun 22 '18 at 00:22
  • That seemed incorrect to me as well. Does the system dispatch this event so that I could just subscribe to it? Do you happen to have an example or link that I can check out on this point? Thank you! – Paul Hristea Jun 22 '18 at 00:25
  • Yes, the system posts that notification. Read the documentation for `UIPasteboard changeCount`. – rmaddy Jun 22 '18 at 00:32
  • I tried removing the line where I post the notification, but now the selector never gets fired. I'll try on a real device, maybe it's because of the emulator? Anyway, it seems like I'm not the only one with this problem: https://stackoverflow.com/questions/26868751/nsnotificationcenter-pasteboardchangednotification-not-firing – Paul Hristea Jun 22 '18 at 11:21

0 Answers0