"앱은 떴어. 창도 나타났고. 그런데 dock 아이콘이 없고, app switcher 에도 없고, 앞으로 오지도 않았어. 앱은 멀쩡했어. 앱으로 등록이 안 됐을 뿐이지."
증상 셋
개발 중에 native 창이 열리긴 했어. 그런데 서로 이어진 세 가지가 틀어져 있었지. dock 에 아이콘이 없어. 애플리케이션 switcher 에서도 빠져 있고. 그리고 절대 맨 앞으로 안 와. 터미널 뒤에 열리고, 키 입력은 계속 아까 focus 가 있던 앱으로 가. 증상은 셋인데 원인은 하나였고, 그 원인이 앱 코드에는 아예 없었어. 앱은 맞게 짜여 있었고, 문제는 그게 떠지는 방식이었어.
맨 바이너리는 앱이 아니야
개발용 명령이 맨 실행 파일, 그러니까 날것의 바이너리를 만들어서 돌려. 운영체제가 '앱' 으로 알아보는 구조를 갖춘 폴더인 제대로 된 application bundle 이 아니라. OS 는 이 둘을 아주 다르게 다뤄. bundle 은 시스템의 launch services 에 정상적인, 앞으로 나올 수 있는 애플리케이션으로 등록돼. 맨 바이너리는 그 과정을 통째로 건너뛰고. OS 가 얘를 진짜 앱으로 등록한 적이 없으니까 dock 에도 없고, switcher 항목도 없고, 앞으로 나올 정당한 권리도 없는 거야.
framework 설정이 안 먹힌 이유
자연스러운 해법은 앱의 activation policy 를 framework 설정으로 'regular', 그러니까 앞으로 나올 수 있는 앱으로 세우는 거야. 그런데 여기 함정이 있어. 그 framework 층 설정이 띄워진 모양이 맨 바이너리일 때는 살아 있는 애플리케이션 객체까지 전달이 안 됐어. 그 설정은 제대로 된 bundle 맥락 안에서 도는 걸 전제하거든. 그 맥락 밖에서는 조용히 안 먹혀. 설정은 맞았는데도 안 됐던 거야. 그게 기대는 전제가 거기 없었으니까.
진짜 해법 둘
나가는 길이 둘이야. 직접적인 쪽은 framework 아래 시스템 층에서 activation policy 를 'regular' 로 밀어 넣고 앱을 명시적으로 앞으로 끌어오는 native 호출을 하는 거야. 전달이 안 되던 framework 설정을 우회하는 거지. 다른 쪽은 맨 바이너리 띄우기를 그만두고 진짜 application bundle 을 빌드해서 그걸 돌리는 거고. 그러면 OS 가 처음부터 제대로 등록해. 앞쪽은 개발 흐름을 그 자리에서 고치고, 뒤쪽은 개발용 결과물을 진짜 결과물이랑 맞춰 놓는 거야.
엉뚱한 손잡이부터 잡지 마
이런 혼란 속에서는 관련 있어 보이는 설정 플래그를 죄다 시도해 보고 싶어져. 이거 강제 focus, 저거 항상 맨 위. 그런데 그건 진짜 원인인 '이 앱이 등록된 앱이 아님' 을 안 건드려. 게다가 그중 적어도 하나는 상황을 더 나쁘게 만들어. 항상 맨 위를 강제하면 원래 문제 위에 키보드 focus 까지 깨질 수 있거든. 규율은 겉만 가리는 창 플래그를 만지기 전에 뿌리인 등록과 activation policy 부터 고치는 거야.