Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Capturing active application notifications in MacOS/React native

I’m building a MacOS application using react native. I want to find out when the user switches applications and grab screenshots when they occur. I have the following toy implementation:

import Foundation
import AppKit

@objc(ScreenShotModule)
public class ScreenShotModule: NSObject, RCTBridgeModule {
  
  public static func moduleName() -> String! {
    return "ScreenShotModule"
  }
  
  var count:Int = 0
  
  override init() {
    super.init()
    print("called init")
    NotificationCenter.default.addObserver(
      self,
      selector: #selector(appDidBecomeActive),
      name: NSWorkspace.didActivateApplicationNotification,
      object: nil)
  }
  
  @objc func appDidBecomeActive(notification: NSNotification) {
    print("got notified")
    let displayId = CGMainDisplayID()
    guard let image = CGDisplayCreateImage(displayId) else { return }
        
    let bitmapRep = NSBitmapImageRep(cgImage: image)
    guard let imageData = bitmapRep.representation(using: .png, properties: [:]) else { return }
        
    let fileManager = FileManager.default
    let directoryURLs = fileManager.urls(for: .picturesDirectory, in: .userDomainMask)
        
    if let documentDirectory = directoryURLs.first {
      let filePath = documentDirectory.appendingPathComponent("screenshot_\(count).png")
      do {
        try imageData.write(to: filePath)
        count += 1
        print("Screenshot saved to: \(filePath)")
      } catch {
        print("Error saving screenshot: \(error)")
      }
    }
  }
  
  @objc func triggerAppDidBecomeActive() {
      let dummyNotification = NSNotification(name: NSNotification.Name(""), object: nil)
      self.appDidBecomeActive(notification: dummyNotification)
  }
  
  @objc func postNotification() {
    print("posted!")
    NotificationCenter.default.post(name: NSWorkspace.didActivateApplicationNotification, object: "foo",
                                    userInfo: ["key": "Value"])
  }
  
  @objc public static func requiresMainQueueSetup() -> Bool {
    return true
  }
}

This works in that I can manually take screenshots via triggerAppDidBecomeActive, and I can take screenshots upon posting fake events via postNotification. However, while I’m running the app and switching between applications, no screenshots are taken. So somehow, my switching applications does not send events to, or otherwise does not trigger:

NotificationCenter.default.addObserver(
      self,
      selector: #selector(appDidBecomeActive),
      name: NSWorkspace.didActivateApplicationNotification,
      object: nil)

I’ve turned on and off Application sandboxing without change. I’ve also tried using DistributedNotificationCenter and that doesn’t work either. How can I figure out when a user switches active applications?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

You’re using NotificationCenter.default.addObserver, but you should be using NSWorkspace.shared.addObserver

I believe this is universally true for the NSWorkspace.* notifications.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading