본문 바로가기
C.W.K.
Stream
Lesson 05 of 06 · published

네이티브 탈출구: objc2 & Frontmost

~15 min · tauri, macos, objc2, native

Level 0웹 관광객
0 XP0/56 lessons0/13 achievements
0/100 XP to next level100 XP to go0% complete
"Tauri API는 흔한 95%를 덮어. 남은 5%에선 문을 잠그는 대신 OS 자체의 열쇠를 쥐여줘."

크로스 플랫폼 API로 안 될 때

Tauri 창 API는 일부러 크로스 플랫폼으로 만들어져서, OS마다 있는 별난 구석을 다 열어주진 못해. 가끔은 네이티브 윈도잉 층을 직접 불러야 해. macOS는 AppKit/Cocoa(objc2 크레이트로), Windows는 Win32 API(windows-rs로), Linux는 GTK. Tauri는 자기 추상 안에 널 가두지 않아. 바닥의 핸들에 손을 뻗어 OS랑 직접 말할 수 있게 해줘. 그 뒷문이 있어서 Tauri로 진지한 네이티브 앱을 만들 수 있는 거야.

Cinder 사례: Frontmost 활성화

scaffold 트랙의 macOS 포커스 버그 기억나? 클릭은 먹는데 키 입력은 안 먹던 그 dev 바이너리. 그리고 같은 뿌리에서 나온 다른 증상으로, always-on-top으로 떠 있는 창이 key window가 안 되는 문제도 있었어. macOS는 key window한테만 키보드 이벤트를 보내는데, 제대로 활성화된 앞쪽 앱이 아닌 프로세스는 영영 그 자격을 못 얻을 수 있거든. Tauri의 set_focus()만으론 안 고쳐졌어. 진짜 해결책은 Cocoa까지 내려가는 거였어. set_activation_policy(Regular)로 프로세스를 올리고, objc2NSApplication.activate()를 직접 부르는 거지.

가두고, 못 박고, 이유를 적어둬

네이티브 코드는 플랫폼을 타니까 #[cfg(target_os = "macos")] 뒤에 있어야 해 — 다른 플랫폼은 그게 없는 셈 치고 깔끔히 컴파일되게. objc2 크레이트는 버전을 못 박아 두고(Cinder는 objc2-app-kit이랑 objc2-foundation을 고정해뒀어), 이런 코드는 다음에 읽는 사람한테 하나도 안 뻔하니까 있는지 주석을 달아. 네이티브 뒷문은 힘이 세고 그만큼 잘못 쓰기도 쉬워. 이 코드가 무게를 지고 있다고 생각하고, 어떤 버그를 막고 있는지 적어둬.

Code

objc2로 Cocoa까지 내려가기 (cfg로 가둬서)·rust
// macOS 전용: 앱을 앞으로 가져와 창이 key가 되고 실제로 키보드 이벤트를
// 받게. 프로세스가 활성화된 포그라운드 앱이 아닐 때 Tauri의 set_focus()만
// 으론 부족해. (Cinder의 실제 고침.)
#[cfg(target_os = "macos")]
builder = builder.setup(|app| {
    use tauri::{ActivationPolicy, Manager};
    app.set_activation_policy(ActivationPolicy::Regular);

    use objc2_app_kit::{NSApplication, NSApplicationActivationPolicy};
    use objc2_foundation::MainThreadMarker;
    if let Some(mtm) = MainThreadMarker::new() {
        let ns_app = NSApplication::sharedApplication(mtm);
        ns_app.setActivationPolicy(NSApplicationActivationPolicy::Regular);
        ns_app.unhide(None);
        ns_app.activate();
    }
    if let Some(win) = app.get_webview_window("main") {
        let _ = win.show();
        let _ = win.set_focus();
    }
    Ok(())
});
플랫폼별로 가둔 네이티브 의존성·toml
# 네이티브 의존성은 Cargo.toml에서 플랫폼 스코프 + 버전 핀.
[target.'cfg(target_os = "macos")'.dependencies]
objc2 = "0.5"
objc2-app-kit = "0.3"
objc2-foundation = "0.3"

External links

Exercise

오늘 objc2를 직접 쓸 필요는 없어. 대신 따져봐. macOS에서 Tauri의 set_focus()가 왜 키보드 입력을 못 넘겨줄 수 있는지, Cocoa 레벨 activate()가 거기에 뭘 더해주는지 네 말로 설명해봐. 그다음 네 앱이 네이티브 크레이트를 꺼내 들 만한 OS별 동작을 하나 짚어. 뒷문을 열어도 되는 때를 아는 게 진짜 기술이야.
Hint
핵심은 이거야. macOS는 키보드 이벤트를 'key window'한테만 보내고, 그 자격은 제대로 활성화된 앞쪽 앱만 안정적으로 가져. set_focus는 Tauri한테 정중히 부탁하는 거고, NSApplication.activate()는 OS한테 앱 전체를 frontmost로 만들라고 하는 거야. 뒷문은 Tauri의 이식성 API로는 표현이 안 되는 OS 사실을 다룰 때 쓰는 거야.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.