이번 글에서는 **RayNeo X2 AR 글래스**에서 작동하는 애플리케이션을 개발하기 위해 **가장 먼저 준비해야 할 환경 설정**과 RayNeo X2만의 **독특한 아키텍처**를 자세히 이해하는 시간을 가지겠습니다. RayNeo X2 개발이 처음이시더라도 걱정 마세요. 하나씩 차근차근 따라오실 수 있도록 친절하게 안내해 드릴게요. <br> <br> # 1. 개발 환경, 어떻게 구축해야 할까요? RayNeo X2는 독립적인 Android OS 위에서 작동해요. <span style="color:rgb(209, 209, 209)">(Android 12L 기반, API Level 32)</span> 이 덕분에 일반적인 안드로이드 기기처럼 **ADB(Android Debug Bridge)**를 사용해서 우리가 만든 커스텀 APK 파일을 설치하고 테스트할 수 있답니다. <br> > [!info] 잠깐! ADB(Android Debug Bridge)란? > ADB는 개발자가 PC에서 안드로이드 기기를 제어하고, 만든 앱을 설치하거나, 기기 상태를 확인하거나, 앱 실행 중 발생하는 로그(기록)를 볼 수 있게 해주는 **만능 명령어 도구**예요. <br><br> ## 1.1 ADB를 통해 외부 APK 설치하기 (Sideloading) 개발한 애플리케이션을 RayNeo X2에 설치하려면 ADB 도구가 필수입니다. RayNeo X2에 외부 앱을 설치할 때는 반드시 **외부 APK 설치 권한**을 명시적으로 부여해야 하는데요. 개발 환경을 설정하고 외부 APK 파일을 장치에 설치하는 기본 순서는 다음과 같습니다. <br> 1. **ADB 툴 설치** ```bash brew install android-platform-tools ``` 2. **외부 APK 설치 권한 부여** ```bash adb devices # 연결된 기기 목록 확인 adb shell settings put global mercury_install_allowed 1 ``` 3. **APK 설치 (Sideloading)** ```bash adb install [apk 경로] ``` <br><br> ## 1-2 링 컨트롤러 없이도 앱을 실행하려면? <br> ![[RayNeo screenshot2.jpg|center|w70]] <br> RayNeo X2는 기본적으로 **링 컨트롤러(Ring Controller)**가 없으면 외부 앱이 실행되지 못하도록 제한하는 정책을 가지고 있어요. 하지만 만약 우리가 앱을 테스트할 때마다 링 컨트롤러를 꼭 써야 한다면 개발이 정말 번거로워지겠죠? **다행히도** 시스템은 앱의 매니페스트(`AndroidManifest.xml`) 파일을 확인하여 이 앱이 **"RayNeo 전용 애플리케이션"**인지 아닌지를 구분한답니다. 우리가 할 일은 앱이 RayNeo 전용 앱이라고 시스템에 알려주는 거예요. <br><br> **✅ 필수 메타데이터 선언** ```xml <application ... > <meta-data android:name="com.rayneo.mercury.app" android:value="true" /> </application> ``` 이 메타데이터를 `true`로 설정하면, 시스템은 이 앱을 RayNeo 전용 애플리케이션으로 인식해요. 이렇게 되면 **링 컨트롤러 없이도** 앱이 정상적으로 실행될 수 있게 되죠. 만약 이 설정이 빠지면 앱이 실행될 때 시스템 프롬프트가 표시되면서 실행이 불가능해지니 **이 과정을 절대 잊지 마세요!** <br><br> <br> # 2. RayNeo X2 아키텍처 이해하기 RayNeo X2 애플리케이션은 일반적인 Android 애플리케이션과 비교했을 때 입력 방식, UI 상호작용, 디스플레이 레이아웃 등 여러 면에서 큰 차이를 보여요. 이 차이점을 이해하는 것이 개발의 첫걸음이에요. | 특징 | 일반적인 Android 앱 (스마트폰) | **RayNeo X2 앱** (AR 글래스) | | ----------- | ---------------------------- | ----------------------------------- | | **입력 방식** | 손가락 제스처 (2D 터치) | **안경 다리 터치 또는 링** (1차원 입력에 한정) | | **UI 상호작용** | 탭 기반 (바로 누름) | **포커스 → 탭 흐름** (초점 맞추고 선택) | | **디스플레이** | 단일 화면 | **듀얼 디스플레이** (좌우 동기화 필수) | | **확장성** | Google Play Services 자유롭게 사용 | **Google Play Services 미지원**, 기능 제한 | <br><br> ## 2.1 사용자를 위한 3D UI 동기화 (Binocular Synchronization) ![[rayneox2-binocular-synchronization.png|center|w70]] 가장 큰 특징 중 하나는 디스플레이 구조예요. RayNeo X2는 왼쪽 눈과 오른쪽 눈 각각에 콘텐츠를 렌더링하는 **양안(Binocular) 디스플레이 아키텍처**를 사용해요. **만약 여기서 좌우 화면의 UI 위치나 크기가 조금이라도 어긋나면 어떻게 될까요?** 사용자, 특히 장시간 착용하는 분들은 **시각적 불편함이나 심지어 방향 감각 상실(Disorientation)**을 경험할 수 있어요. 이는 개발자가 프론트엔드에서 레이아웃을 잡을 때 **좌우 화면이 완벽하게 동기화**되도록 극도로 신경 써야 함을 의미합니다. <br> **✅ 입체감을 시뮬레이션하는 방법** 이 문제를 해결하고 사용자에게 안정적인 3D 경험을 제공하기 위해, 우리는 ARDK(Augmented Reality Development Kit)에서 제공하는 `make3DEffectForSide()` 메서드를 **반드시** 사용해야 해요. 이 메서드는 3D 인터페이스 요소를 양쪽 디스플레이에 정확히 동기화할 뿐만 아니라, 좌우 시야 간의 **수평 차이(Horizontal Disparity)**를 주어 우리가 실제로 깊이를 느끼는 것처럼 **입체감**을 보여줍니다. <br> <br><br> ## 2.2 포커스 기반 상호작용 이해하기 일반 스마트폰처럼 화면의 특정 버튼을 바로 탭(Tap)하는 방식은 RayNeo X2에서 통하지 않아요. 왜냐하면 입력이 안경 다리의 **1차원 터치**로 제한되어 있기 때문이죠. 마치 키보드 방향키로만 화면을 조작해야 하는 상황을 상상해 보세요. <br> 이러한 제약을 극복하기 위해 RayNeo X2는 **2단계 상호작용 프로세스**를 따릅니다. 1. **포커스(Focus):** 사용자가 원하는 UI 요소에 **먼저 초점을 맞춥니다.** ![[RayNeo screenshot1.jpg|center|w70]] <div style="text-align:center"><span style="color:gray;">'Lens' 앱에 초점을 맞춘 상황</span></div> 2. **선택(Tap):** 그 후에 안경 다리를 터치하여 **선택을 확정**합니다. <br> 이러한 상호작용 모델을 구현하기 위해 우리는 ARDK의 `FocusHolder`, `FocusInfo`, `FixPosFocusTracker`와 같은 핵심 컴포넌트들을 활용하여 **동적으로 조정 가능한 포커스 커서**를 설계해야 한답니다. <br><br><br> # 3. RayNeo ARDK의 핵심 클래스 RayNeo ARDK는 RayNeo X2의 고유한 하드웨어(듀얼 디스플레이)와 상호작용 제약 조건(1차원 입력)을 해결하기 위해 특별히 개발된 **소프트웨어 개발 키트**예요. ARDK는 듀얼 디스플레이 제어, 포커스 관리, 그리고 제한적인 터치 입력을 처리하는 데 필수적인 요소들로 구성되어 있습니다. 다음은 ARDK의 주요 클래스와 그 핵심 역할을 기능별로 요약한 내용입니다. | 카테고리 | 핵심 역할 | 주요 클래스 | | ------------- | --------------------------------------------------------------------- | ---------------------------------------- | | **UI 동기화** | 좌우 디스플레이에 **동일한 UI**를 동시에 표시하여 시각적 불편함을 방지함 | `BindingPair`, `BaseMirrorActivity` | | **3D 시각 효과** | 좌우 시야에 차이를 주어 **입체감(깊이)**을 시뮬레이션함 | `make3DEffect` / `make3DEffectForSide` | | **입력 이벤트 해석** | 안경 다리의 원시적인 **1차원 터치**를 의미 있는 제스처로 변환함 | `TouchDispatcher`, `CommonTouchCallback` | | **제스처 흐름 처리** | 변환된 제스처를 Click, DoubleClick과 같은 **구조화된 이벤트(TempleAction)**로 캡슐화하고 처리함 | `TempleAction`, `BaseTouchActivity` | | **포커스 기반 UI** | 사용자가 상호작용할 UI 요소의 **초점(Focus)** 상태를 추적하고 관리함 | `FocusHolder`, `FixPosFocusTracker` | <br><br> ## 3.1 SDK 라이브러리 통합 및 초기화 과정 개발을 시작하기 전에 프로젝트에 ARDK 라이브러리를 추가하고 올바르게 초기화하는 것이 중요합니다. <br> **🛠️ SDK 통합 단계** 1. **라이브러리 추가** - RayNeo Maven 서버를 사용한다면, `settings.gradle`에 서버 주소를 추가해 주세요. - 만약 `.aar` 파일을 사용한다면, 파일을 `libs` 디렉토리에 넣고 관련 Kotlin 및 AndroidX 의존성(Dependencies)을 `build.gradle`에 선언해야 합니다. 2. **SDK 초기화** - ARDK의 모든 핵심 기능(특히 터치 이벤트 감지)이 앱의 전체 생명주기 동안 올바르게 작동하려면, 애플리케이션 클래스(`Application class`)에서 `MercurySDK.init(this)`를 호출해야 합니다. 3. **`AndroidManifest.xml`에 등록** - 위에서 정의한 Application 클래스를 `AndroidManifest.xml` 파일에 **반드시** 등록해 주어야 합니다 <br><br> <br> # 4. 핵심 기능 구현: 카메라 프리뷰 RayNeo X2의 핵심 보조 기능은 카메라를 통해 **실시간 시각 정보**를 사용자에게 제공하는 것이죠. 이 기능을 구현하기 위해 저는 Google의 최신 카메라 개발 라이브러리인 **CameraX**를 사용했습니다. <br> ## 4.1 CameraX와 BinderPair 구조의 결합 CameraX는 카메라 통합 작업을 간소화하고 호환성을 확보하는 Jetpack 라이브러리입니다. 하지만 RayNeo X2는 일반 스마트폰이 아니기 때문에, 이 라이브러리를 그대로 사용하기만 해서는 안 돼요. 듀얼 디스플레이를 지원하기 위해서는 **RayNeo ARDK의** **ViewBinding/BinderPair** **구조**를 활용해야 합니다. 생각해 보세요. RayNeo X2는 물리적인 카메라는 하나지만, 그 출력을 보여줄 화면은 왼쪽/오른쪽 두 개가 있습니다. <br> 우리는 `startCamera()` 함수 내에서 CameraX를 사용해 **두 개의 별도** **Preview** **객체를 생성**하고, 각각을 ARDK의 `mBindingPair.left.viewFinder`와 `mBindingPair.right.viewFinder`에 연결해야 합니다. ```Kotlin // 두 개의 Preview 객체 생성 (좌우) val leftPreview = Preview.Builder().build().also { it.setSurfaceProvider(mBindingPair.left.viewFinder.surfaceProvider) } val rightPreview = Preview.Builder().build().also { it.setSurfaceProvider(mBindingPair.right.viewFinder.surfaceProvider) } // ImageCapture 객체는 하나만 생성 imageCapture = ImageCapture.Builder().build() // 라이프사이클에 바인딩 cameraProvider.bindToLifecycle( this, cameraSelector, leftPreview, rightPreview, imageCapture ) ``` <br> 이러한 **BinderPair 구조**를 통해 우리는 사용자에게 일관성 있고 몰입감 있는 **양안 카메라 프리뷰(Binocular camera preview)**를 제공할 수 있게 된답니다. 또한 `bindToLifecycle()` 호출은 카메라 리소스를 액티비티의 생명주기에 자동으로 연결하여, 앱이 백그라운드로 이동할 때 자동으로 카메라를 해제함으로써 배터리 소모와 충돌을 방지하는 똑똑한 역할을 합니다. <br><br> <br> 이번 글에서는 RayNeo X2 AR 개발을 위한 필수 환경 설정과 일반 안드로이드 개발과는 확연히 다른 RayNeo X2의 핵심 아키텍처(듀얼 디스플레이, 포커스 기반 입력)를 자세히 이해해 보았습니다. 다음 **2부**에서는 이 카메라 프리뷰를 기반으로 **안경 다리 터치(Temple Action)**를 감지하여 실제로 사진을 찍고 갤러리에 저장하는 방법을 다뤄볼 거예요. 또한, 개발 과정에서 제 마주했던 **RayNeo X2 플랫폼의 실질적인 한계점** (예: 내장 TTS 부재)과 이를 **극복하기 위한 전략**에 대해서도 더 자세히 이야기해 드릴게요. 다음에 뵙겠습니다! <br><br><br><br>