Yuichi Murata's Engineering Blog

グローバル・エンジニアリング・チームをつくる

WebCam を表示するだけの OS X アプリを作った

はじめて OS X アプリ開発 & Swift をやってみました。

https://raw.githubusercontent.com/yuichi1004/cam/master/screenshot.png github.com

きっかけは Google Meet の機能不足。スクリーンシェアをしているときこちらのカメラだけ表示が消えてしまうのである。なんとも不公平感があるし、こちらの表情を始めとするメッセージが伝えられなくなるのが不満であった。このアプリを使うと単にフローティングした WebCam が表示される。以上。

OS X (Cocoa) を使った開発はいままでやったことは無かったし、Swift も初めてであった。けれども特段の学習もなく、サンプルコードを参考にここまで実装するのにおよそ半日ほどでできた。 ひとえに Swift に感謝である。Objective-C だったらここまで到達する前に挫折していたと思う。

Swift は今どきの言語を触っていればなんとなく勘で触れるように思った。文法も全く勉強せずに取り掛かったが、クラスの定義、オーバーライド、Getter/Setter などは理解できた。

Movable Panel

フルスクリーンアプリ上でも動作するウィジェット風のウインドウは以下の処理で作成している。

  • canJoinAllSpaces, .fullScreen を指定することでフルスクリーン上でもウインドウが動作する
  • isFloatingPanel を使って常に全面にウインドウが来るようにする
  • isMovableByWIndowBackground を使ってドラッグアンドドロップでウインドウが動かせるようにする
class MoveablePanel: NSPanel {
    override init(contentRect: NSRect, styleMask style: NSWindow.StyleMask, backing backingStoreType: NSWindow.BackingStoreType, defer flag: Bool) {
        super.init(contentRect: contentRect, styleMask: [.nonactivatingPanel, .resizable], backing: .buffered, defer: true)
        
        self.aspectRatio = NSMakeSize(240.0,135.0)
        self.level = NSWindow.Level.mainMenu
        self.isMovableByWindowBackground = true
        self.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary]
        self.isFloatingPanel = true
        self.orderFrontRegardless()
    }
}

ウェブカメラの表示

ウェブカメラの表示に関してはよくまとまったサンプルがあったので大いに参考にさせてもらった。Thanks fbukevin for cool example for web cam view. 以下のサンプルと同じく AVCaptureVideoPreviewLayer を用いてウインドウ上にカメラ映像を重ねている。

github.com

カメラ映像が左右逆転してしまうのだけ、どう直していいのか分からなかった。識者がいたら教えてほしい。

ステータスバーアイコンの表示

OS X メニューバー右のアイコンの登録も NSStatusBar を使って簡単にできた。 以下ソースコード。予めイメージバンドル StatusBarButtonImage を登録しておく。 あとはメニューを追加してあげれば、クリックしたときに任意のメニューが表示できる。

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
    let statusItem = NSStatusBar.system.statusItem(withLength:NSStatusItem.squareLength)
    
    func applicationDidFinishLaunching(_ aNotification: Notification) {
        if let button = statusItem.button {
            button.image = NSImage(named: NSImage.Name("StatusBarButtonImage"))
        }
        let menu = NSMenu()
        menu.addItem(NSMenuItem(title: "Quit Cam", action: #selector(NSApplication.terminate(_:)), keyEquivalent:"Q"))
        statusItem.menu = menu
    }
}

まとめ

いままで Objective-C の食わず嫌いで距離をおいていたけど、Swift なら趣味の範囲で OS X/iOS 開発に取り掛かってみるのもありかなと思った。