ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 안드로이드 미래 먹거리 XR
    Android 2025. 7. 11. 15:58

     

     

    안녕하세요. Mash-Up Android 15기 유호현입니다.

     

    지난 5월 개최된 2025 Google I/O에서 Android XR 글래스가 공개 되었는데요, Google I/O의 XR 글래스 데모에서는 제미나이가 탑재된 XR 글래스와 소통하며 친구에게 메시지를 보내고, 일정 안내를 요청하는 등, 마치 아이언맨 영화 속 자비스가 현실이 되는 순간을 보여주었습니다.

    2025 Google I/O 발표 외에도 XR에 대한 기술적 흐름의 신호가 몇 가지 존재했는데, 지난 해 12월 삼성과 퀄컴이 연합하여 만든 Android XR 기기 ‘프로젝트 무한'을 발표하였고, 안드로이드 스튜디오 Narwhal 버전에서는 기본적으로 XR 에뮬레이터가 탑재되어, 안드로이드 XR 개발을 지원하기 시작했습니다.

    이러한 변화의 흐름 속에서, 안드로이드 개발자인 우리는 먹고 살기 위해 Android XR 개발을 살펴보지 않을 수 없을텐데요. 그래서 직접 공식 문서와 코드랩을 살펴보고, 현재 개발중인 사이드 프로젝트의 XR화를 시도해보는 경험을 통해 Android XR 개발에 대한 기본적인 수준의 내용을 공유해보고자 합니다.

     

    Jetpack XR SDK

    Android XR 개발을 위한 도구들이 여럿 있지만, 그 중 이미 우리에게 익숙한 Kotlin과 Compose를 활용하기 위해서는 Jetpack XR SDK를 사용해야 합니다. 또한 Kotlin과 Compose로 개발된 기존 앱을  XR 환경에 맞게 개선하고자 한다면 당연하게도 Jetpack XR SDK를 사용해야 합니다.

     

    Jetpack XR SDK는 다음과 같은 라이브러리들로 구성됩니다.

    • XR용 Jetpack Compose: Android XR의 공간 기능을 활용하는 공간 UI 레이아웃을 선언적으로 빌드한다.
    • XR용 Material Design: XR에 맞게 조정되는 Material 구성요소와 레이아웃으로 빌드한다.
    • Jetpack SceneCore: 3D 콘텐츠로 Android XR 장면 그래프를 빌드하고 조작한다.
    • Jetpack XR용 ARCore: 인식 기능으로 디지털 콘텐츠를 실제 세계로 가져온다.

    추가적으로 Jetpack XR SDK를 활용하기 위한 환경 구축을 해야 하는데요, 세팅에 대한 내용은 공식문서에 잘 나와있습니다. 단 아직 정식 버전에서는 XR 프로젝트를 생성할 수도, XR 에뮬레이터를 사용할 수도 없기 때문에, 반드시 안드로이드 스튜디오 Canary 버전을 설치해야 XR 개발이 가능합니다. (25.7.10일자 기준)

    Android Studio Canary 버전

     

    Home Space 모드와 Full Space 모드

    Home Space(좌) Full Space(우)

     

    안드로이드 XR 환경에서는 Home Space, Full Space 두 가지 모드에서 앱을 경험할 수 있습니다.

     

     

    https://developer.android.com/design/ui/xr/guides/foundations#modes

     

    Home Space

    Home Space 모드는 XR 환경에서의 기본적인 공간으로, 여러 가지 앱을 띄워놓고 멀티 태스킹 하며 사용할 수 있으며, 호환이 가능하다면 안드로이드 XR 환경에서 Home Space 모드로 기존의 앱을 사용할 수 있습니다.

    Full Space

    Full Space 모드는 오직 하나의 앱만 실행되며, 다른 앱은 모두 숨겨집니다. 단, 오직 하나의 앱만 실행된다는 것은 XR이 오직 하나의 앱을 위해서만 환경을 구성한다는 뜻과 같은데, Full Space 모드에서는 공간에 3D 오브젝트를 띄우거나, 여러 개의 앱 패널을 띄울 수 있고, 주변 공간을 변화시킬 수도 있습니다.

     

    현재 매쉬업 프로젝트로 플리핀 이라는 앱을 개발하고 있는데요, 이 앱을 그대로 Android XR로 빌드해보면 Home Space 모드에서 다음과 같이 앱이 실행됩니다.

    Home Space 모드에서의 플리핀 앱

     

    다만, 보이시는 것과 같이 안드로이드 XR 환경에서는 화면을 자유롭게 옮길수도, 화면 크기를 조절할 수도 있기 때문에 XR 대응을 위해서라면 앱의 대화면 대응이 절실히 필요하다는 것이 느껴집니다.

     

    Full Space 전환

    매니페스트에 앱 실행시 Full Space 모드에서 실행할 수 있도록 설정하지 않았다면, 기본적으로 Home Space 모드에서 앱이 실행됩니다. 그래서 Jetpack XR SDK 에서는 런타임중 Full Space 모드로 전환하기 위한 방법을 제공하며, 다음 Composition Local들이 주요하게 사용됩니다.

    • LocalSpatialConfiguration : 앱의 현재 공간 구성에 대한 액세스를 제공하는 컴포지션 로컬이다. 모드 변경을 요청하는 메서드 외에도 앱이 포함된 볼륨 크기 등의 기타 정보가 포함되어 있다.
    • LocalSpatialCapabilities : 앱에서 현재 사용할 수 있는 공간 기능을 확인하는 데 사용할 수 있는 컴포지션 로컬이다. 모드(HomeSpace 또는 Full Space) 외에도 공간 음향, 3D 콘텐츠 지원 등의 기능이 포함되어 있다.
    • LocalHasXrSpatialFeature : 공간 UI 기능을 지원하는 기기에서 앱이 실행되는지 확인하는 데 사용할 수 있는 컴포지션 로컬이다. 내부적으로 기기에 android.software.xr.immersive 시스템 기능이 있는지 확인한다.

    이제 앞서 소개한 세 가지 Composition Local 들을 활용하여 Full Space 모드로 전환할 수 있는 버튼을 만들어 보겠습니다. 해당 코드는 XR codeLab을 참고하였습니다.

    @Composable
    fun ToggleSpaceModeButton(modifier: Modifier = Modifier) {
        val spatialConfiguration = LocalSpatialConfiguration.current
    
        if (LocalSpatialCapabilities.current.isSpatialUiEnabled) { // 현재 Home Space 인지 Full Space 인지 검사한다.
            ToggleSpaceModeButton(
                modifier = modifier,
                contentDescription = "Request Home Space mode",
                iconResource = R.drawable.ic_home_space_mode,
                onClick = { spatialConfiguration.requestHomeSpaceMode() } // 클릭시 Home Space 모드로 전환한다
            )
        } else {
            ToggleSpaceModeButton(
                modifier = modifier,
                contentDescription = "Request Full Space mode",
                iconResource = R.drawable.ic_full_space_mode,
                onClick = { spatialConfiguration.requestFullSpaceMode() } // 클릭시 Full Space 로 전환한다
            )
        }
    }
    
    @Composable
    fun ToggleSpaceModeButton(
        contentDescription: String,
        @DrawableRes iconResource: Int,
        onClick: () -> Unit,
        modifier: Modifier = Modifier
    ) {
        FilledTonalIconButton(
            modifier = modifier,
            onClick = onClick
        ) {
            Icon(
                painterResource(iconResource),
                contentDescription
            )
        }
    }

     

    추가적으로 LocalHasXRSpatialFeature 값을 검사하여 XR 환경에서만 ToggleSpaceModeButton이 노출될 수 있도록 해야 합니다.

    if (LocalHasXrSpatialFeature.current) {
        ToggleSpaceModeButton()
    }

     

    이를 실제로 적용해본 결과는 다음과 같습니다.

    Home Space <-> Full Space 전환

     

    잘 살펴보면 Home Space 모드에서 앱 왼쪽에 다른 앱이 떠있는데, Full Space 모드로 전환하면 다른 앱이 사라지는 것을 볼 수 있습니 다. (버튼 아이콘도 깨알같이 바뀜) 하지만 아직까지는 실행되는 화면에서 큰 차이를 느낄 수 없는데요, 다음 이어질 내용들에서 Full Space 모드에서 화면을 바꿔가보겠습니다.

     

    Spatial Panel

    https://developer.android.com/design/ui/xr/guides/spatial-ui#spatial-panels

     

    SpatialPanel은 안드로이드 XR 앱의 컨테이너 역할을 하는 기본 구성 요소입니다. Home Space 모드에서 앱은 단일 패널을 통해 표시되지만, Full Space 모드에서는 앱을 하나 이상의 패널로 나누어 좀 더 몰입감 높은 환경을 제공할 수 있습니다.

     

    Full Space 모드에서 앱을 여러 패널에 나누어 보여주기 위해 알아야할 주요 Composable은 다음과 같습니다.

    Subspace

    • Subspace는 Android XR 환경에서 3D 콘텐츠를 배치하고 렌더링하기 위한 Compose 영역이다.
    • 오직 Full Space 모드인 XR 환경에서만 노출되며, 일반 모바일, 태블릿 등의 다른 환경에서는 콘텐츠가 표시되지 않는다.

    SpatialPanel

    • 3D 공간에 배치할 수 있으며 앱 콘텐츠를 표시할 수 있는 2D 평면.
    • Subspace 혹은 setSubspaceContent 내에서만 호출해야 한다.
    • SubspaceModifier 에서 movable 또는 resizable를 추가하여 패널의 크기를 조절하거나 이동을 허용할 수 있다.

    SubspaceLayout

    • SpatialPanel들을 Subspace 내에서 배치할 수 있는 컴포저블.
    • SubspaceLayout의 종류로는 SpatialRow, SpatialColumn, SpatialBox, SpatialLayoutSpacer … 등이 있다.

    이제 이 Composable들을 앱에 적용해보겠습니다.

    모바일에서 보는 플리핀 홈화면

     

    플리핀 앱의 홈 화면에서는 바텀 네비게이션으로 이동 가능한 3개의 화면이 있습니다. 바텀 네비게이션으로 이동 가능한 3 가지 화면을 Full Space 모드에서 가로로 배치하여 보여주는 코드를 다음과 같이 작성하였습니다.

    Subspace { // Supspace를 사용해야만 FullMode에서 패널을 배치 가능
        SpatialRow( // SpatialRow로 3D 상에 패널을 Row로 배열
            alignment = SpatialAlignment.Center,
        ) {
            // SpatialPanel을 3개 추가하고, 바텀 네비게이션에서 이동 가능한 화면을 배치
            SpatialPanel(
                modifier = SubspaceModifier
                    .width(457.dp)
                    .height(952.dp)
            ) {
                MissionStatusRoute()
            }
            SpatialPanel(
                modifier = SubspaceModifier
                    .width(457.dp)
                    .height(952.dp)
            ) {
                HomeRoute()
            }
            SpatialPanel(
                modifier = SubspaceModifier
                    .width(457.dp)
                    .height(952.dp)
            ) {
                MyPageRoute()
            }
        }
    }

     

    최상단에 Subspace 컴포저블을 통해 렌더링 가능한 영역을 만들어주었고, 2D 평면 패널인 SpatialPanel 3개를 배치하였습니다. 그리고 SpatialPanel안에는 각각 홈에서의 세 가지 화면 Composable을 추가하였습니다. 그 결과는 아래와 같습니다.

    Full Space 에서의 홈 화면

     

    Orbiter

    패널 하단에 존재하는 것이 Orbiter 이다.

    Orbiter는 부가적인 Spatial UI 컴포넌트입니다. 공간 패널, 레이아웃 또는 기타 항목에 연결되도록 설계되었으며, 일반적으로 연결된 항목과 관련된 항목을 포함해야 합니다.

     

    Orbiter를 생성하려면 Orbiter 컴포저블을 사용하면 되는데, position, alignment로 파라미터로 위치를 지정해줄 수 있습니다.

     

    플리핀 앱의 홈 화면에서 플로팅 되어 있는 두 버튼을 Orbiter로 만들어 화면 외부에 배치하기 위해 코드를 다음과 같이 작성하였습니다.

    val spatialConfiguration = LocalSpatialConfiguration.current
    
    SpatialPanel(
        ...
    ) {
        // 기존 홈 화면
        HomeRoute(
            ...
        )
        // 상단 우측에 배치되는 Orbiter
        Orbiter(
            position = OrbiterEdge.Top,
            offset = 40.dp,
            alignment = Alignment.End,
        ) {
            ToggleSpaceModeButton(
                ...
                onClick = { spatialConfiguration.requestHomeSpaceMode() }
            )
        }
        // 하단 중앙에 배치되는 Orbiter
        Orbiter(
            position = OrbiterEdge.Bottom,
            offset = 50.dp,
            alignment = Alignment.CenterHorizontally,
        ) {
            DhcFloatingButton(
                ...
            )
        }
    }

     

    와 같이 배치하고 싶은 패널 내부에 Orbiter을 호출하고 위치를 지정해주면, 패널과 연결되어 패널 외부를 자유롭게 활용할 수 있게 됩니다. 실행 결과는 아래와 같습니다.

     

    XR 적용 후기

    앞서 기존 앱을 XR 기기에서 실행할 수 있는 기본적인 방법들을 소개했습니다. 하지만 공식 문서를 조금만 더 들여다보면, 단순히 앱을 띄우는 수준을 넘어 주변 환경을 변경하거나 3D 오브젝트를 배치하는 등 XR 공간을 십분 활용하는 문서도 존재했는데요.

    그중 가장 놀라며 기대되었던 것은 Android XR 에서는 AR Core를 활용하여 다양한 방식의 상호작용이 가능해진 것입니다. 이는 단순환 디스플레이의 전환을 넘어 UI/UX의 새로운 패러다임이 등장한 것이고, 핸즈 프리한 상호작용과 몰입된 경험을 바탕으로 모바일을 완전히 대체할 수 있지 않을까 라는 생각도 듭니다.

    이번 포스팅에서는 안드로이드 XR 개발의 기본적인 내용만을 다루었지만, XR 환경에서 사용할 수 있는 흥미로운 기능들을 활용하여 오직 XR을 위한 안드로이드 앱을 개발해보아도 재밌을 것 같습니다. 가까운 미래에 안드로이드 XR이 안드로이드 개발자들의 새로운 미래 먹거리가 될 것을 기대하며 마무리 해보겠습니다.

    감사합니다.
Designed by Tistory.