디바이스 내 디버깅 및 JUnit 5
Source: Dev.to
이번 글은 금요일 릴리즈 포스트에 대한 첫 번째 후속 글이며, 이번 릴리즈에서 앱 자체가 아니라 Codename One 앱을 반복 개발하는 방식에 영향을 주는 두 가지 변경 사항을 다룹니다. 실제 iPhone이나 Android 디바이스에서 Java를 Java 그대로 다루는 온‑디바이스 디버깅과 JavaSE 시뮬레이터에서 표준 JUnit 5를 실행하는 기능입니다. 첫 번째 항목이 오래전부터 원하던 기능이며 설명이 가장 길어 대부분의 내용이 여기서 다루어집니다.
Codename One이란? Codename One은 하나의 Java 또는 Kotlin 코드베이스로 iOS, Android, 데스크톱, 웹 네이티브 앱을 만들 수 있는 오픈소스 프레임워크입니다. 자세한 내용은 codenameone.com을 참고하세요.
온‑디바이스 디버깅: Java를 Java 그대로 다루기
Codename One은 기술적인 의미에서 언제나 온‑디바이스 디버깅을 지원해 왔습니다. .ipa에 Xcode를 붙일 수 있었고, 실행 중인 APK에 Android Studio를 붙일 수 있었으며, 네이티브 콜 스택을 읽고, ParparVM이 생성한 Objective‑C 혹은 C 코드를 단계별로 탐색할 수 있었습니다. 하지만 MyForm.java에 브레이크포인트를 잡고 실제 iPhone에서 해당 지점에 도달했을 때, Java 객체의 필드를 Java 객체로서 검사할 수는 없었습니다. 또한 iOS 앱을 디버깅하려면 반드시 Mac이 필요했는데, 이는 바이너리를 이해할 수 있는 디버거가 Xcode뿐이었기 때문입니다. Java → C(ParparVM) 변환 단계에서 디바이스 쪽으로 돌아갈 방법이 없었습니다.
iOS PR #4999와 Android PR #5012가 그 격차를 메웠습니다. 이번 주부터는 JDWP를 지원하는 모든 디버거(IntelliJ IDEA, jdb, VS Code Java Debugger, Eclipse, NetBeans 등)가 Codename One 앱에 연결돼 실행 중인 프로세스를 JVM처럼 다룰 수 있습니다.
지원 대상:
iOS
-
iOS 시뮬레이터 (Mac에서만 실행 가능)
-
동일 네트워크에 있는 개발 머신에서 Wi‑Fi 로 연결된 실제 iPhone
실제 iPhone을 디버깅할 때 로컬 Mac이 필요하지 않습니다. Codename One 빌드 클라우드가 iOS 빌드를 수행해 서명된 .ipa를 생성합니다. 이를 일반적인 방법(TestFlight, ad‑hoc, 혹은 빌드 클라우드 설치 링크)으로 iPhone에 설치한 뒤, JDWP가 Wi‑Fi 로 연결되면 Linux나 Windows IDE에서도 Mac과 동일하게 디버깅할 수 있습니다. Mac은 로컬 Xcode 빌드와 iOS 시뮬레이터 실행에만 필요합니다.
Android
-
Android 에뮬레이터
-
USB 로 연결된 실제 Android 폰
-
무선
adb로 연결된 실제 Android 폰
Android 디버깅은 표준 adb 를 사용하므로 개발 머신에 Android SDK 플랫폼 도구가 설치돼 있어야 합니다. macOS, Linux, Windows 모두 지원하므로 세 환경 중 어느 것이든 Android 디버깅이 가능합니다.
실제 화면
IntelliJ IDEA와 iOS 시뮬레이터에서 브레이크포인트에 도달한 iOS 앱 화면:
다른 Java 프로젝트와 동일한 Debug 툴 창을 사용합니다. 왼쪽 Frames 패널에는 전체 Java 콜 스택이 표시되고, Variables 패널에는 this와 로컬 변수들이 Java 값으로 나타납니다. 일반 JVM에서 보는 것과 같은 드릴‑다운이 가능합니다. 오른쪽 시뮬레이터는 실제 iOS 앱이며, 브레이크포인트에서 일시 정지된 상태로 다음 스텝을 기다리고 있습니다.
구성 요소들의 동작 방식
iOS에서는 IDE가 디바이스와 직접 통신하지 않습니다. CN1 Debug Proxy는 개발 머신에서 실행되는 작은 Java 프로세스로, 두 개의 TCP 포트를 바인딩합니다. 하나는 CN1 와이어 프로토콜을 사용해 iOS 앱이 연결하는 포트이고, 다른 하나는 IDE가 표준 JDWP 로 연결하는 포트입니다. IDE는 일반적인 원격 JVM을 보게 되고, iOS 앱은 디버그 프록시를 보게 됩니다. 프록시는 양쪽 사이를 변환하면서 ParparVM 구조 레이아웃을 탐색해 Java 필드, 메서드 호출, 값이 양방향으로 깨끗하게 라운드‑트립하도록 합니다.
flowchart LR
IDE["IntelliJ IDEA
any OS"] -- "JDWP
(localhost:8000)" --> Proxy["CN1 Debug Proxy
your dev machine"]
Proxy -- "CN1 wire protocol
(Wi‑Fi or loopback)" --> App["Codename One iOS app
real iPhone or iOS Simulator"]
Android에서는 프록시가 필요 없습니다. Dalvik/ART 자체가 JDWP 를 구현하고 있기 때문에 IntelliJ 가 adb 내장 JDWP 포워더를 통해 디바이스에 직접 연결합니다. Maven 플러그인의 새로운 cn1:android-on-device-debugging 목표가 adb 오케스트레이션과 포트 포워딩을 대신 수행합니다.
flowchart LR
IDE["IntelliJ IDEA
macOS / Linux / Windows"] -- "JDWP
(localhost:5005)" --> ADB["adb forward
your dev machine"]
ADB -- "JDWP over USB or Wi‑Fi" --> Device["Android device
or emulator
Dalvik / ART"]
두 플랫폼 사이의 중요한 차이점: Android에서는 네이티브 인터페이스의 Impl 클래스가 일반 Java이므로 JDWP 가 그 클래스를 다른 Java 클래스와 동일하게 단계별로 탐색합니다. 반면 iOS에서는 Impl 가 Objective‑C 로 구현돼 JDWP 가 이를 이해하지 못하므로 IDE에서 해당 코드를 직접 스텝‑인할 수 없습니다. 대신 Codename One 프레임워크 코드와 여러분이 작성한 Java 코드를 네이티브 인터페이스 호출 전후까지는 정상적으로 스텝하고, 호출이 반환하는 값을 검사할 수 있습니다. Objective‑C 메서드 본문은 JDWP 입장에서 불투명하게 남으므로, 필요하다면 Xcode 를 병행해서 연결해 Objective‑C 코드를 디버깅하세요.
튜토리얼: IntelliJ + iOS
Codename One 아키타입은 이제 IntelliJ 실행 구성 드롭다운에 On‑Device Debug 폴더 아래 두 개의 실행 구성을 자동 생성합니다: CN1 Debug Proxy와 CN1 Attach iOS. 아래 튜토리얼은 최근에 Initializr 로 생성한 프로젝트를 기준으로 합니다. 오래된 프로젝트라면 Initializr 로 새 프로젝트를 만든 뒤 .idea 디렉터리와 Maven pom.xml 파일을 복사해 주세요.
1. 빌드 힌트 활성화
common/codenameone_settings.properties 파일을 열고 아키타입이 만든 네 줄을 주석 해제합니다:
ios.onDeviceDebug=true
ios.onDeviceDebug.proxyHost=127.0.0.1
ios.onDeviceDebug.proxyPort=55333
ios.onDeviceDebug.waitForAttach=true
ios.onDeviceDebug=true 은 iOS 빌드를 계측된 변형으로 전환합니다. 나머지 세 줄은 프록시 연결을 설정합니다.
네 번째 힌트인 ios.onDeviceDebug.waitForAttach=true 는 로드 차단(block‑on‑load) 옵션이며, 기본값으로 유지하는 것을 권장합니다. 이 옵션을 켜면 iOS 앱이 시작 시 “Waiting for debugger” 오버

