팀에서 개발한 macOS 메뉴 막대 앱을 사용자가 로그인한 뒤 실행해야 한다. 원격 Mac에서 ‘로그인 시 실행’을 켜면 화면에는 활성화된 것으로 표시된다. 하지만 원격 데스크톱 연결을 끊었다가 다시 연결했을 때 앱이 여전히 열려 있다면, 로그인 항목이 작동했다는 증거는 아니다. 검증할 때는 등록, 사용자 승인, 실제 재로그인 후 실행을 구분해 기록해야 한다. 특히 원격 클라이언트의 연결 해제를 macOS 로그아웃으로 간주해서는 안 된다.
테스트 대상과 범위 정하기
이 글에서 테스트하는 것은 SMAppService.mainApp으로 등록한 주 앱의 로그인 항목이다. 백그라운드 도우미 프로그램이나 시스템 시작 서비스는 대상이 아니다. 앱은 macOS 13 이상을 대상으로 해야 하며, 등록 API는 앱 자체 프로세스에서 호출해야 한다. 명령줄 Swift 스크립트를 별도로 실행하는 것만으로는 앱을 대신해 같은 등록을 완료할 수 없다.
테스트용으로 별도의 표준 사용자 계정을 준비하고, 해당 계정의 그래픽 데스크톱에 다시 로그인할 수 있는지 미리 확인한다. 빌드 작업에 사용 중인 계정으로 바로 실험하지 않는다. 로그아웃하면 대화형 세션이 종료되고, 그 세션에 의존하는 프로세스도 중단될 수 있다. 작업을 저장하고 재접속 방법을 기록한 뒤 테스트를 시작한다.
‘등록됨’, ‘승인됨’, ‘로그인 후 실행됨’은 서로 다른 결론이다. 각각에 해당하는 증거가 필요하며, 앞 단계의 상태만으로 다음 단계를 추정해서는 안 된다.
설치된 앱 확인하기
Xcode에서 실행 버튼을 누른 앱이 아니라 실제 배포할 앱 번들로 테스트한다. 아래 경로를 실제 설치 위치로 바꾼다.
APP="/Applications/ExampleApp.app"
test -d "$APP" || { echo "App bundle not found"; exit 1; }
/usr/libexec/PlistBuddy -c 'Print :CFBundleIdentifier' \
"$APP/Contents/Info.plist"
codesign --verify --deep --strict --verbose=2 "$APP"
출력된 bundle identifier를 기록하고 이번 빌드 대상과 일치하는지 확인한다. codesign 검증이 실패하면 먼저 앱 번들을 수정해야 한다. 정상적으로 실행할 수 없는 문제를 로그인 항목 오류로 오인해서는 안 된다. 서명 검증에 성공했다고 해서 사용자 승인이나 로그인 후 실행까지 확인된 것도 아니다.
앱에서 등록 상태 처리하기
등록 동작은 앱 설정의 명시적인 스위치에 연결하고, 앱이 실행될 때마다 무조건 호출하지 않는다. 다음 코드는 macOS 앱 타깃에 넣는다. 호출하는 쪽에서는 반환된 상태에 맞는 안내를 화면에 표시해야 한다.
import ServiceManagement
@MainActor
func enableLaunchAtLogin() throws -> SMAppService.Status {
let service = SMAppService.mainApp
if service.status == .notRegistered {
try service.register()
}
return service.status
}
반환 상태가 .enabled일 때만 화면에 활성화되었다고 표시한다. .requiresApproval이라면 실패로 표시하거나 몰래 등록을 반복하는 대신, 사용자에게 시스템 설정을 확인하도록 안내한다. 발생한 오류도 화면에서 처리할 수 있도록 전달해야 한다. 스위치를 끌 때는 앱에서 try SMAppService.mainApp.unregister()를 호출한 다음 상태를 다시 읽는다. 스위치 모양만 바꿔서는 안 된다.
사용자 승인 확인하기
동일한 테스트 계정에서 시스템 설정을 열고 로그인 항목 관련 화면을 확인한다. 앱이 목록에 있는지, 사용자가 수동으로 허용해야 하는지 살펴본다. 설정 메뉴의 이름은 macOS 버전에 따라 달라질 수 있으므로 현재 시스템에 표시되는 이름을 따른다. 승인한 뒤 앱으로 돌아와 SMAppService.mainApp.status를 다시 읽는다. 시스템 설정에 앱 이름이 나타났다는 사실만으로 ‘자동 실행 검증 완료’라고 기록해서는 안 된다.
실제로 다시 로그인하기
먼저 앱을 정상적으로 종료하고 실행 중이 아님을 기록한다. 그런 다음 macOS 메뉴에서 테스트 계정을 명시적으로 로그아웃하고, 같은 계정의 그래픽 데스크톱에 다시 로그인한다. 앱 창, 메뉴 막대 아이콘 또는 앱 자체에서 확인할 수 있는 실행 상태를 관찰한다. 테스트 전에 어느 항목을 ‘실행 성공’의 기준으로 삼을지 정해 두어야, 실행 직후 충돌한 경우를 성공으로 잘못 판단하지 않는다.
| 확인 시점 | 보관할 증거 |
|---|---|
| 등록 전 | 앱 버전, bundle identifier, 테스트 계정 |
| 등록 후 | 앱이 읽은 로그인 항목 상태 |
| 승인 후 | 시스템 설정의 상태와 앱이 다시 읽은 상태 |
| 재로그인 후 | 앱 실행 여부와 정상적인 상호작용 가능 여부 |
| 비활성화 후 다시 로그인한 뒤 | 해당 로그인 항목으로 앱이 자동 실행되지 않았는지 여부 |
마지막 항목은 앱에서 로그인 항목을 비활성화한 뒤 다시 테스트해야 한다. 앱이 다른 방식으로도 실행된다면 먼저 그 방식을 확인한다. 프로세스가 존재한다는 사실만으로 비활성화 결과를 부정해서는 안 된다. 테스트가 끝나면 필요에 따라 다시 활성화하고 스위치 상태를 확인한다.
원격 세션으로 인한 착시 배제하기
원격 데스크톱 클라이언트를 닫거나 네트워크가 잠시 끊기거나 화면만 잠그는 것으로는 macOS 사용자 세션이 종료되지 않을 수 있다. 다시 연결했을 때 이전 창이 보인다면 대개 세션이 유지되었다는 것만 확인할 수 있을 뿐, 로그인 항목이 실행되었다는 뜻은 아니다. SSH로 앱을 실행하는 것도 그래픽 로그인 테스트가 아니다. SSH shell과 데스크톱 세션은 환경이 다르다.
등록 상태는 올바른데 로그인 후 앱이 보이지 않는다면 순서대로 확인한다. 등록할 때 사용한 계정과 동일한 계정으로 로그인했는지, 다른 빌드 사본이 아닌 설치된 앱 번들을 테스트했는지, 시스템 설정에서 여전히 승인을 요구하는지, 앱이 실행 직후 종료되는지 살펴본다. 앱에 시작 로그가 있다면 이벤트 시각과 이번 로그인 시각을 기록해 ‘실행되지 않음’과 ‘실행 후 실패’를 구분한다. 로그에는 접근 자격 증명을 남기지 않는다.
다음 빌드를 위한 검증 결과 기록하기
앱 버전, bundle identifier, macOS 버전, 테스트 계정, 등록 전후 상태, 승인 작업, 재로그인 결과, 비활성화 후 재검증 결과를 간단히 기록해 둔다. 앱 번들을 업데이트할 때마다 최소한 설치된 앱의 식별 정보와 재로그인 결과를 다시 확인한다. 로그인 항목 구현이 바뀌었다면 등록과 비활성화 경로를 모두 다시 테스트한다.
이 절차의 목적은 특정 컴퓨터에서 앱이 ‘언제나 자동 실행된다’고 증명하는 것이 아니다. 특정 빌드의 동작을 재현하고 문제를 추적할 수 있게 하는 데 있다. 그래픽 로그인과 원격 연결을 구분하면 로그인 항목 문제의 원인을 대체로 앱 번들, 사용자 승인, 앱 실행 자체로 좁힐 수 있다.
자주 묻는 질문
등록에 성공했는데 다시 로그인해도 앱이 실행되지 않는 이유는 무엇인가요?
사용자 승인이 필요한 상태인지, 설치된 앱을 테스트하는지, 실제 그래픽 세션에서 로그아웃한 뒤 재로그인했는지 확인하세요. 실행 직후 앱이 종료되는지도 점검해야 합니다.
원격 데스크톱 연결을 끊으면 로그아웃 테스트가 되나요?
아니요. 클라이언트 연결이 끊겨도 macOS 사용자 세션은 유지될 수 있습니다. 테스트 계정에서 명시적으로 로그아웃한 뒤 다시 로그인해야 합니다.
클라우드 Mac을 워크플로에 연결하세요
VPSPush는 원격으로 연결할 수 있는 전용 물리 Mac을 제공합니다. 노드와 이용 기간을 선택한 뒤 주문에서 접속 정보와 최종 금액을 확인하세요.