RSS
개발 도구

macOS 클립보드 관리자, Swift·Tauri·Electron 중 무엇으로 만들까?

작성자
듀오랩스 대표·11분 읽기

클립보드 관리자를 만들겠다고 하면 첫 질문은 대개 "UI를 뭘로 짤까"입니다. React가 익숙하면 Electron이나 Tauri, 네이티브가 좋으면 SwiftUI를 떠올립니다. 그런데 이 앱의 화면은 검색창 하나와 목록 하나가 거의 전부입니다. 나머지는 운영체제와 주고받는 일입니다.

흔히 데스크톱 프레임워크 선택을 "화면을 어떤 기술로 그릴 것인가"의 문제로 이해합니다. 클립보드 관리자에서는 이 질문이 거의 아무것도 정하지 않습니다. 실제로 갈리는 것은 어느 프레임워크를 고르든 결국 네이티브 코드로 짜야 하는 부분이 얼마나 되는가입니다. 아직 만들기 전 단계이고, 이 글은 고르기 전에 확인한 사실과 그에 대한 제 판단입니다.

복사했다고 알려 주는 이벤트가 없는 구조

macOS의 NSPasteboard에는 내용이 바뀌었다는 알림이 없습니다. 대신 changeCount라는 정수가 있고, Apple 문서는 이 값이 pasteboard 소유권이 바뀔 때마다 증가한다고만 적습니다. 알림이 없으니 클립보드 관리자는 이 숫자를 주기적으로 읽어 달라졌는지 봅니다. 폴링 간격이 곧 "복사했는데 목록에 늦게 뜬다"는 체감 지연이 됩니다.

macOS 15.4부터는 고려할 것이 하나 더 붙습니다. NSPasteboard.AccessBehavior의 기본값은 앱이 일반 pasteboard를 프로그램으로 읽을 때 사용자에게 묻는 것입니다. 사용자는 시스템 설정에서 항상 허용, 묻기, 항상 거부 중 하나를 고릅니다. 클립보드를 읽는 것이 본업인 앱이라면 첫 실행 안내에서 반드시 다뤄야 할 주제입니다. changeCount만 읽어도 이 확인이 뜨는지는 아직 확인하지 못했습니다. 만들기 시작하면 가장 먼저 확인할 부분입니다.

Electron과 Tauri도 사정은 같습니다. 두 쪽 모두 클립보드 변경 이벤트가 없어서 폴링해야 합니다.

비밀번호를 기록하지 않겠다는 약속, nspasteboard.org 표식

클립보드 관리자가 가장 조심해야 하는 것은 비밀번호 관리자에서 복사한 값입니다. 이를 위한 관례가 nspasteboard.org에 정리돼 있습니다. 복사하는 앱이 내용 옆에 표식 타입을 함께 올려 두면, 기록하는 앱이 그것을 보고 건너뛰는 방식입니다.

표식 뜻
org.nspasteboard.ConcealedType 기밀로 다뤄야 하는 내용
org.nspasteboard.TransientType 잠깐만 올라가 있을 내용
org.nspasteboard.AutoGeneratedType 사용자가 복사할 의도 없이 앱이 만든 내용
org.nspasteboard.source 내용을 올린 앱의 번들 ID

같은 페이지에는 1Password의 com.agilebits.onepassword, Handoff의 com.apple.is-remote-clipboard 같은 예전 고유 타입도 나옵니다. 이 표식을 확인하려면 pasteboard에 올라온 임의의 타입 이름을 조회할 수 있어야 합니다. 프레임워크를 비교할 때 이 조건이 생각보다 큰 차이를 만듭니다.

포커스를 뺏지 않는 창과 ⌘V 전송

목록에서 항목을 고르면 원래 쓰던 앱에 바로 붙여 넣어져야 합니다. 여기에는 두 가지가 필요합니다.

먼저 목록 창이 떠도 원래 앱이 활성 상태로 남아 있어야 합니다. AppKit에서는 NSPanel에 .nonactivatingPanel 스타일을 주면 소유한 앱을 활성화하지 않는 패널이 됩니다. 이게 안 되면 창을 띄우는 순간 붙여 넣을 대상이 바뀌어 버립니다.

다음으로 대상 앱에 ⌘V 키 이벤트를 보내야 합니다. CGEvent로 키 이벤트를 만들어 보내고, 권한은 macOS 10.15부터 있는 CGRequestPostEventAccess로 요청합니다. 시스템 설정에서는 "손쉬운 사용" 항목에 나타나지만, Apple DTS의 설명에 따르면 이벤트를 보내는 데만 한정된 별도 권한입니다.

App Store 배포가 갈리는 조건

자동 붙여넣기 때문에 클립보드 관리자는 Mac App Store에 낼 수 없다는 말이 종종 보입니다. 반만 맞는 말입니다.

DTS는 이벤트를 보내는 권한이 App Sandbox와 함께 쓸 수 있는 권한이라고 답했습니다. 반면 포커스된 입력란을 읽는 식의 일반 Accessibility API는 샌드박스 앱에서 쓸 수 없습니다. 그리고 이 권한을 쓰는 샌드박스 앱이 심사를 통과할지는 DTS가 아니라 App Review가 정한다고 선을 그었습니다.

Paste와 Maccy는 둘 다 App Store에서 팝니다. Paste의 도움말은 바로 붙여넣기에 손쉬운 사용 권한이 필요하다고 적지만, App Store판과 직접 배포판을 나눠 설명하지는 않습니다. Maccy의 App Store 설명에는 자동 붙여넣기 언급이 없습니다. 그러니 "App Store판에서도 된다"는 것은 문서로 확인된 사실이 아니라 추정입니다.

App Store 밖으로 내면 Developer ID 인증서로 서명하고 공증을 받아야 Gatekeeper를 통과합니다. 어느 쪽이든 배포 쪽 일이라 프레임워크와는 무관합니다. 저라면 직접 배포로 먼저 내고 App Store는 나중에 따로 따지겠습니다.

프레임워크마다 네이티브로 남는 코드

위의 조건을 프레임워크별로 놓으면 이렇습니다.

필요한 것 Swift (AppKit + SwiftUI) Tauri 2 Electron
변경 감지 changeCount 폴링 Rust에서 폴링 폴링
임의 타입 읽기 (표식 포함) NSPasteboard 그대로 공식 플러그인으로는 불가, Rust로 직접 44부터 application/osclipboard 형식으로 가능
포커스 안 뺏는 패널 NSPanel Rust/Objective-C로 직접 type: 'panel' (스타일 마스크를 런타임에 덧붙임)
⌘V 전송 CGEvent Rust로 직접 네이티브 모듈 필요
웹뷰 없음 시스템 WKWebView Chromium 내장

Tauri 쪽에서 눈여겨볼 것은 공식 clipboard-manager 플러그인의 범위입니다. 함수가 readText, writeText, readImage, writeImage, writeHtml, clear 여섯 개뿐이고, HTML은 쓰기만 됩니다. 문서 주석에도 HTML은 문자열로만 읽을 수 있어서 readHtml이 없다고 적혀 있습니다. 임의의 타입을 읽는 길이 없으니 ConcealedType 표식도 이 플러그인으로는 볼 수 없습니다. 결국 클립보드 앱의 핵심은 Rust에서 macOS API를 직접 부르는 코드가 됩니다. 전역 단축키는 공식 플러그인이, 메뉴바 아이콘은 코어의 트레이 기능이 맡아서 이 부분은 편합니다.

Electron은 최근에 달라졌습니다. Electron 44에서 clipboard 모듈이 W3C Clipboard API 모양으로 다시 짜이면서 readBuffer와 availableFormats가 빠졌습니다. 운영체제 원본 형식은 이제 electron application/osclipboard;format="<이름>"이라는 사용자 정의 형식으로 읽습니다. 렌더러 프로세스에서는 더 이상 쓸 수 없고 메인 프로세스 전용입니다. 예전 글의 예제 코드는 44 이상에서 그대로 돌지 않습니다.

크기에 대한 공식 숫자는 Tauri 쪽에만 있습니다. Tauri는 최소 앱이 600KB 미만일 수 있다고 적고, Electron 문서는 Chromium과 Node.js를 바이너리에 넣는다고만 적습니다. 항상 떠 있는 앱이라 유휴 메모리가 중요한데, 이건 각자 빌드해서 재야 할 숫자입니다.

화면 기술이 정하지 못하는 것

표에서 "직접"이라는 말이 없는 열은 Swift뿐입니다. Tauri를 고르면 React로 목록을 그리는 대신, 같은 macOS API를 Rust에서 부르는 코드를 씁니다. 네이티브 코드를 피하려고 고른 프레임워크에서 가장 어려운 부분이 네이티브로 남는 셈입니다.

그래서 제 기준은 하나입니다. Windows판을 낼 계획이 있는가. macOS만이라면 Swift가 맞다고 봅니다. 운영체제 쪽 일이 전부 1급 API이고, React를 쓸 수 있다는 이점은 검색창과 목록 정도의 화면에서는 크지 않습니다. Windows까지 낸다면 Tauri를 고르겠습니다. 화면과 히스토리 저장·검색은 한 벌로 두고, 감지·패널·붙여넣기만 운영체제별로 짜는 구조가 됩니다. Electron은 44의 clipboard 개편으로 임의 형식을 다시 읽을 수 있게 됐지만, 항상 떠 있는 작은 앱에 Chromium을 싣는 비용을 정당화할 이유를 저는 아직 찾지 못했습니다.

확실하지 않은 것은 두 가지입니다. macOS 15.4의 pasteboard 접근 확인이 changeCount 폴링에도 걸리는지, 그리고 App Store판의 자동 붙여넣기가 심사를 통과하는지입니다. 둘 다 프레임워크와는 무관하게 첫 주에 확인해야 할 일입니다.

마지막 수정:

공유하실 때는 출처(Duolabs)와 원문 주소를 표시해 주세요.