"앱이 띄워졌어. 윈도우가 나타났고. 근데 dock 아이콘 없고, app switcher 에 아무것도 없고, 절대 앞에 안 왔어. 앱은 멀쩡했어 — 그냥 앱으로 등록이 안 됐을 뿐."
세 가지 증상
개발 중, native 윈도우가 열렸어 — 근데 연결된 세 방식으로 틀리게. dock 에 아이콘 없음. 애플리케이션 switcher 에서 빠짐. 그리고 절대 frontmost 안 됨: 터미널 뒤에 열렸고, 키 입력이 전에 focus 있던 앱으로 계속 라우팅. 세 증상, 한 원인, 그리고 원인이 앱 코드에 전혀 없었어. 앱은 올바랐어; 띄워지는 방식이 문제였어.
bare 바이너리는 앱이 아니야
개발 명령이 bare 실행파일 — 원시 바이너리 파일 — 을 빌드하고 돌려, 제대로 된 application bundle(운영체제가 '앱' 으로 인식하는 구조화된 폴더)이 아니라. OS 가 그 둘을 아주 다르게 다뤄. bundle 은 시스템의 launch services 에 정상적인, foreground-가능 애플리케이션으로 등록돼. bare 바이너리는 그걸 다 건너뛰어: OS 가 그걸 진짜 앱으로 절대 등록 안 해서, dock 존재 없고, switcher 항목 없고, 앞에 올 정상 권리가 없어.
왜 framework 자기 설정이 안 도왔는지
자연스러운 해법은 앱의 activation policy 를 framework 설정으로 'regular'(foreground 앱)로 설정하는 거야. 근데 여기 함정: 그 framework 레벨 설정이 launch 모양이 bare 바이너리일 때 라이브 애플리케이션 객체로 전파 안 됐어. 설정이 제대로 된 bundle 맥락 안에서 도는 걸 가정해; 그 맥락 밖에선, 조용히 효력 발휘에 실패해. 설정은 올바랐고 그래도 안 됐어, 의존하는 전제조건이 거기 없었으니까.
두 진짜 해법
나가는 길이 둘이야. 직접적인 거: framework 아래 시스템 레이어에서, activation policy 를 'regular' 로 강제하고 앱을 명시적으로 앞으로 가져오는 native 호출을 해 — 전파 안 되던 framework 설정을 우회하는. 다른 거: bare 바이너리 띄우기를 멈추고 진짜 application bundle 을 빌드해서, 그걸 돌려, OS 가 처음부터 제대로 등록하게. 첫째는 dev 루프를 제자리에서 고치고; 둘째는 dev artifact 가 진짜 것과 맞게 해.
틀린 knob 에 먼저 손 뻗지 마
이런 혼란 하에, 관련 들리는 모든 설정 flag 를 시도하고 싶어 — 이거 force-focus, 저거 always-on-top. 근데 그건 근본 원인(앱이 등록된 앱이 아님)을 다루지 않고, 그중 적어도 하나는 적극적으로 더 나쁘게 만들어: always-on-top 강제가 기존 문제 위에 키보드 focus 를 깰 수 있어. 규율은 그걸 덮기만 하는 cosmetic 윈도우 flag 건드리기 전에 근본(등록 / activation policy)을 고치는 거야.