방법

Jetpack XR SDK로 Androidify를 XR에 도입

전문 길이: 9분
Dereck Bridie
개발자 관계팀 엔지니어

Android XR로 구동되는 삼성 갤럭시 XR이 출시되었습니다. 이 블로그 게시물은 Android XR Spotlight Week의 일환으로 게시되었습니다. 이 기간 동안 Google은 Android XR용 앱을 학습, 빌드, 준비하는 데 도움이 되는 리소스(블로그 게시물, 동영상, 샘플 코드 등)를 제공합니다.

Android XR로 구동되는 최초의 기기인 삼성 갤럭시 XR이 출시되었습니다. 이제 Play 스토어에서 좋아하는 앱을 3D라는 새로운 차원에서 즐길 수 있습니다.

세 번째 차원은 넓은 공간으로, 앱을 위한 공간도 충분합니다. 앱에 적합한 도구를 사용하여 지금 시작하세요. 예를 들어 Jetpack XR SDK를 사용하여 Kotlin, Compose와 같은 최신 Android 개발 도구로 몰입형 XR 환경을 빌드할 수 있습니다.

이 블로그 게시물에서는 Google이 인기 있는 Androidify 앱의 기발함을 XR로 가져오는 여정을 소개하고, 앱을 XR로 가져오는 데 필요한 기본사항도 다룹니다.

Androidify 둘러보기

Androidify는 Gemini, CameraX, Navigation 3, Jetpack Compose와 같은 최신 기술을 사용하여 Android 봇을 만들 수 있는 오픈소스 앱입니다. Androidify는 처음에는 적응형 레이아웃을 만들어 스마트폰, 폴더블, 태블릿에서 멋지게 보이도록 설계되었습니다.

customize.png

Androidify는 다양한 폼 팩터에서 멋지게 표시됩니다

적응형 레이아웃의 핵심은 재사용 가능한 컴포저블입니다. Jetpack Compose를 사용하면 사용자가 어떤 유형의 기기를 사용하든 직관적인 사용자 환경을 만들 수 있도록 다양한 방식으로 배치할 수 있는 작은 UI 구성요소를 만들 수 있습니다. 실제로 Androidify는 앱을 수정하지 않고도 Android XR과 호환됩니다.

customize_2.png

Androidify는 코드 변경 없이 대형 화면 반응형 레이아웃을 사용하여 XR에 적응합니다

Android XR을 특별히 처리하지 않는 앱은 적절한 크기의 창에서 멀티태스킹할 수 있으며 대형 화면에서와 거의 동일하게 작동합니다. 따라서 Androidify는 추가 작업 없이 Android XR에서 이미 모든 기능을 갖추고 있습니다. 하지만 여기서 멈추고 싶지 않았기에 XR 사용자에게 즐거운 경험을 제공하기 위해 XR 차별화 앱을 만들기로 했습니다.

XR에서 방향 설정하기

앱이 실행될 수 있는 두 가지 모드인 홈 공간과 전체 공간부터 시작하여 Android XR의 주요 기본 개념을 살펴보겠습니다.

homespace.png
홈 공간의 앱
homespace2.png
전체 공간의 앱

홈 공간에서는 여러 앱을 나란히 실행할 수 있으므로 사용자가 여러 창에서 멀티태스킹을 할 수 있습니다. 이러한 점에서 가상 공간에서 대형 화면 Android 기기의 데스크톱 창 모드와 매우 유사합니다.

전체 공간에서 앱에는 공간 경계가 없으며 공간 UI, 가상 환경 제어와 같은 Android XR의 전체 공간 기능을 사용할 수 있습니다.

앱을 전체 스페이스에서만 실행하도록 설정하고 싶을 수도 있지만, 사용자는 앱으로 멀티태스킹을 하고 싶어 할 수 있으므로 두 가지를 모두 지원하면 사용자 환경이 개선됩니다.

Androidify의 새로운 차원을 위한 설계

훌륭한 앱은 훌륭한 디자인에서 시작됩니다. Android DevRel의 수석 디자인 옹호자인 아이비 나이트는 Androidify의 기존 디자인을 활용하여 XR을 위한 새로운 디자인을 만드는 작업을 맡았습니다. 아이비, 시작해 줘!

XR을 위한 디자인에는 고유한 접근 방식이 필요했지만 실제로는 모바일 디자인과 공통점이 많았습니다. 먼저 포함에 대해 생각해 보았습니다. 경계를 명확하게 표시하거나 미묘하게 암시하여 하위 공간에서 UI 요소를 구성하고 그룹화하는 방법입니다. 또한 사용자에 따라 조정되고 이동하는 공간 UI 요소의 다양한 크기를 수용하는 방법을 배웠습니다. Androidify에서와 마찬가지로 적응형 레이아웃으로 빌드하여 공간 UI의 레이아웃을 여러 부분으로 나눌 수 있습니다.

홈 스페이스로 디자인 시작하기

다행히 Android XR에서는 홈 공간을 위해 현재 앱을 그대로 사용할 수 있으므로 창 툴바와 전체 공간 전환 버튼만 추가하면 확장된 XR 디자인으로 전환할 수 있습니다.

가능한 하드웨어 기능과 사용자가 이러한 기능과 상호작용하는 방식도 고려했습니다. Androidify의 모바일 레이아웃은 다양한 자세, 클래스 크기, 카메라 수에 맞게 조정되어 더 많은 사진 옵션을 제공합니다. 이 모델에 따라 헤드셋 기기의 카메라 레이아웃도 조정해야 했습니다. 또한 UI와 사용자의 근접성을 고려하여 텍스트가 작동하도록 조정해야 했습니다.

전체 공간으로의 대대적인 전환을 위한 설계

전체 공간이 가장 큰 변화였지만 디자인을 적용할 수 있는 가장 창의적인 공간을 제공했습니다. 

tablet_to_xr.webp
태블릿에서 XR로

Androidify는 시각적 격리 또는 창을 사용하여 '사진 촬영 또는 선택' 창과 같이 배경과 윤곽선이 있는 기능을 그룹화합니다. 또한 상단 앱 바와 같은 구성요소를 사용하여 다른 창을 프레임으로 지정하여 자연스러운 포함을 만들었습니다. 마지막으로 '내 봇 색상 선택' 창 근처에 있는 '변환 시작' 하단 버튼과 같이 특정 요소가 다른 요소와 가까이 있으면 내재적 포함이 제안됩니다.

쉽게 분리할 수 있는 공간 패널 공간 패널에 맞게 모바일 디자인을 조정하는 방법을 결정하려면 가장 뒤에 있는 표면부터 시작하여 앞으로 이동하면서 표면을 삭제해 보세요. 배경을 얼마나 많이 삭제할 수 있는지, 무엇이 남는지 확인하세요. Androidify에 이 연습을 적용한 후에는 큰 녹색 Android 구불구불한 선만 남았습니다. 구불구불한 선은 브랜딩 순간과 배경 역할을 할 뿐만 아니라 3D 공간에서 콘텐츠의 앵커 역할도 했습니다.

이 앵커를 설정하면 요소가 앵커를 중심으로 어떻게 이동할 수 있는지, 근접성을 사용하여 나머지 사용자 환경을 어떻게 분리하고 변환할 수 있는지 쉽게 상상할 수 있었습니다.

앱이 공간을 인식하도록 지원하는 기타 디자인 팁

  • 제한을 두지 않기: 구성요소를 분리하고 실제 (공간) 공간을 제공합니다. 이제 UI 요소에 여유 공간을 줄 시간입니다.
  • 표면 삭제: 배경을 숨기고 디자인에 어떤 영향을 미치는지 확인합니다.
  • 동작으로 동기 부여: 앱에서 전환을 어떻게 사용하고 있나요? 이 캐릭터를 사용하여 앱이 VR로 전환되는 것을 상상해 보세요.
  • 앵커 선택: 스페이스에서 사용자를 잃지 마세요. UI를 수집하거나 그라운딩하는 데 도움이 되는 요소가 있어야 합니다.

XR UI 디자인 패턴에 관한 자세한 내용은 Android 개발자의 Android XR 디자인을 참고하세요.

공간 UI 기본사항

이제 Ivy가 XR용 Androidify를 디자인하면서 사고방식을 적응시킨 경험을 살펴보았으니 공간 UI 개발에 대해 이야기해 보겠습니다. 최신 Android 도구 및 라이브러리를 사용하는 데 익숙하다면 Jetpack XR SDK로 공간 UI를 개발하는 것이 익숙하게 느껴질 것입니다. Compose로 레이아웃을 만드는 등 이미 익숙한 개념을 확인할 수 있습니다. 실제로 공간 레이아웃은 행, 열, 스페이서를 사용하는 2D 레이아웃과 매우 유사합니다.

spatialrows.png

이러한 요소는 SpatialRows 및 SpatialColumns에 정렬됩니다.

여기에 표시된 공간 요소는 SpatialPanel 컴포저블로, 텍스트, 버튼, 동영상과 같은 2D 콘텐츠를 표시할 수 있습니다.

Subspace {
    SpatialPanel(
        SubspaceModifier
            .height(824.dp)
            .width(1400.dp)
    ) {
        Text("I'm a panel!")
    }
}

SpatialPanel은 서브스페이스 컴포저블입니다. 하위 스페이스 컴포저블은 하위 스페이스 내에 포함되어야 하며 SubspaceModifier 객체에 의해 수정됩니다. 하위 공간은 앱의 UI 계층 구조 내 어디에나 배치할 수 있으며 하위 공간 컴포저블만 포함할 수 있습니다. SubspaceModifier 객체도 Modifier 객체와 매우 유사합니다. 크기 조정 및 위치 지정과 같은 매개변수를 제어합니다.

Orbiter 은 SpatialPanel에 연결할 수 있으며 연결된 콘텐츠와 함께 이동할 수 있습니다. 이러한 컨트롤은 연결된 콘텐츠에 관한 컨텍스트 컨트롤을 제공하여 콘텐츠에 기본 초점을 맞추는 데 자주 사용됩니다. 구성 가능한 거리에서 콘텐츠의 네 면 중 하나에 배치할 수 있습니다.

orbiter.png
Orbiter가 SpatialPanel 하단에 연결되어 있습니다.

더 많은 공간 UI 요소가 있지만 Androidify의 공간 레이아웃을 만드는 데 사용한 주요 요소는 다음과 같습니다.

XR 개발 시작하기

프로젝트 설정부터 시작해 보겠습니다. Jetpack XR 종속 항목 페이지에서 확인할 수 있는 Jetpack XR Compose 종속 항목이 추가되었습니다.

사용자를 전체 공간으로 전환하는 버튼의 코드를 추가했습니다. 먼저 전체 공간으로 전환할 수 있는 기능을 감지합니다.

@Composable
fun couldRequestFullSpace(): Boolean =
   LocalSpatialConfiguration.current.hasXrSpatialFeature && 
   !LocalSpatialCapabilities.current.isSpatialUiEnabled
}

그런 다음 기존 레이아웃에 콘텐츠 펼치기 아이콘을 사용하는 새 버튼 구성요소를 만들고 onClick 동작을 부여했습니다.

@Composable

fun RequestFullSpaceIconButton() {
   if (!couldRequestFullSpace()) return
   val session = LocalSession.current ?: return

   IconButton(
       onClick = {
           session.scene.requestFullSpaceMode()
       },
   ) {
       Icon(
           imageVector =  
               vectorResource(R.drawable.expand_content_24px),
           contentDescription = 
               stringResource("To Full Space"),
       )
   }
}

이제 이 버튼을 클릭하면 전체 공간에 중간 레이아웃만 표시됩니다. 공간 기능을 확인하고 공간 UI를 표시할 수 있는지 확인할 수 있습니다. 이 경우 새로운 공간 레이아웃이 표시됩니다.

@Composable

fun HomeScreenContents(layoutType: HomeScreenLayoutType) {
   val layoutType = when {
      LocalSpatialCapabilities.current.isSpatialUiEnabled -> 
          HomeScreenLayoutType.Spatial
      isAtLeastMedium() -> HomeScreenLayoutType.Medium
      else -> HomeScreenLayoutType.Compact
   }

   when (layoutType) {
      HomeScreenLayoutType.Compact ->
          HomeScreenCompactPager(...)

      HomeScreenLayoutType.Medium ->
          HomeScreenMediumContents(...)

      HomeScreenLayoutType.Spatial ->
          HomeScreenContentsSpatial(...)
   }
}

홈 화면 디자인 구현

전체 스페이스의 홈 화면을 위한 공간 디자인으로 돌아가 구현 방법을 알아보겠습니다.

customize_3.png

여기에서 두 개의 SpatialPanel 요소가 확인됩니다. 하나는 오른쪽의 동영상 카드가 있는 패널이고 다른 하나는 기본 UI가 포함된 패널입니다. 마지막으로 상단에 Orbiter가 부착되어 있습니다. 동영상 플레이어 패널부터 살펴보겠습니다.

@Composable
fun HomeScreenContentsSpatial(...) {
   Subspace {
      SpatialPanel(SubspaceModifier
                   .fillMaxWidth(0.2f)
                   .fillMaxHeight(0.8f)
                   .aspectRatio(0.77f)
                   .rotate(0f, 0f, 5f),
      ) {
          VideoPlayer(videoLink)
      }
   }
}

추가 변경 없이 일반 레이아웃의 2D VideoPlayer 구성요소를 SpatialPanel에 재사용했습니다. 독립형은 다음과 같습니다.

bluetiel.png

기본 콘텐츠 패널도 마찬가지였습니다. SpatialPanel에서 중간 패널 콘텐츠를 재사용했습니다.

SpatialPanel(SubspaceModifier.fillMaxSize(),
             resizePolicy = ResizePolicy(
                 shouldMaintainAspectRatio = true
             ),
             dragPolicy = MovePolicy()
) {
    Box {
        FillBackground(R.drawable.squiggle_full)
        HomeScreenSpatialMainContent(...)
    }
}

이 패널에 ResizePolicy를 적용하여 사용자가 패널 크기를 조절할 수 있는 핸들을 가장자리 근처에 제공했습니다. 또한 사용자가 이를 드래그할 수 있는 MovePolicy도 있습니다.

customize_4.png

동일한 하위 공간에 배치하면 서로 독립적이므로 VideoPlayer 패널을 기본 콘텐츠 패널의 하위 요소로 만들었습니다. 이렇게 하면 상위-하위 관계를 통해 기본 콘텐츠 패널을 드래그할 때 VideoPlayer 패널이 이동합니다.

@Composable
fun HomeScreenContentsSpatial(...) {
   Subspace {
       SpatialPanel(SubspaceModifier..., resizePolicy, dragPolicy) {
           Box {
               FillBackground(R.drawable.squiggle_full)
               HomeScreenSpatialMainContent(...)
           }
           Subspace {
              SpatialPanel(SubspaceModifier...) {
                  VideoPlayer(videoLink)
              }
           }
       }
   }
}

이런 방식으로 첫 번째 화면을 만들었습니다.

다른 화면으로 이동

다른 화면도 간단히 살펴보고 각 화면에 적용된 특정 고려사항을 강조하겠습니다.

fullspace.png
전체 공간의 생성 화면

여기서는 SpatialRow 및 SpatialColumn 컴포저블을 사용하여 권장 시청 공간에 맞는 레이아웃을 만들었으며, Medium 레이아웃의 구성요소를 다시 사용했습니다.

fullspace_2.png

전체 공간의 결과 화면: 프롬프트로 생성된 봇: 빨간색 야구 모자, 파일럿 선글라스, 하늘색 티셔츠, 빨간색과 흰색 체크무늬 반바지, 녹색 플립플롭을 착용하고 테니스 라켓을 들고 있습니다.


결과 화면에는 페더링 효과를 사용하여 무료 인용구가 표시되므로 화면 가장자리에서 흐려질 수 있습니다. 또한 사용된 입력을 볼 때 실제 3D 전환을 사용하여 공간에서 사진을 뒤집습니다.

Google Play 스토어에 게시

이제 공간 레이아웃을 사용하여 앱을 XR에 맞게 준비했으므로 Play 스토어에 출시했습니다. 앱의 AndroidManifest.xml 파일에 적용된 마지막으로 중요한 변경사항이 있습니다.

<!-- Androidify can use XR features if they're available; they're not required. -->
<uses-feature android:name="android.software.xr.api.spatial" 
              android:required="false" />

이렇게 하면 Play 스토어에서 이 앱에 XR 차별화 기능이 있음을 알 수 있으며, 사용자가 앱이 XR을 염두에 두고 제작되었음을 알 수 있는 배지가 표시됩니다.

androidify2.png
Android XR의 Google Play 스토어에 표시된 Androidify


출시를 업로드할 때 XR용으로 출시하기 위한 특별한 단계는 필요하지 않습니다. 모바일 트랙의 사용자에게와 마찬가지로 XR 기기의 사용자에게도 동일한 앱이 정상적으로 배포됩니다. 하지만 앱의 XR 관련 스크린샷을 추가하거나 공간 동영상 애셋을 사용하여 앱의 몰입형 미리보기를 업로드할 수 있습니다. Android XR 기기에서 Play 스토어는 이를 몰입형 3D 미리보기로 자동 표시하므로 사용자는 앱을 설치하기 전에 콘텐츠의 깊이와 규모를 경험할 수 있습니다.

지금 바로 나만의 환경을 구축하세요

Androidify는 기존 2D Jetpack Compose 앱을 공간화하는 방법을 보여주는 좋은 예입니다. 오늘 Google은 디자인부터 코드, 게시까지 Androidify의 공간 UI를 개발하는 전체 프로세스를 보여드렸습니다. 공간 패러다임과 호환되도록 기존 디자인을 수정하고, SpatialPanel 및 Orbiter 컴포저블을 사용하여 사용자가 전체 공간에 진입할 때 표시되는 공간 레이아웃을 만들고, 마지막으로 새로운 버전의 앱을 Play 스토어에 출시했습니다.

이 블로그 게시물이 Android XR에 자체 앱을 가져오는 방법을 이해하는 데 도움이 되었기를 바랍니다. 다음은 학습에 도움이 될 수 있는 몇 가지 링크입니다.

작성자:

계속 읽기