일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- Skeleton UI
- 스켈레톤 UI
- React Native
- launchscreen
- 360도 뷰어
- 파노라마 뷰
- 리액트
- Android
- React-Native
- react-native-fast-image
- 앱 성능 개선
- 스플래시스크린
- 3b52.1
- native
- 360도 이미지 뷰어
- 라이브러리 없이
- 네이티브
- 리엑트 네이티브
- Native Module
- boilerplate 제거
- 360도 이미지
- 스켈레톤 통합
- launch screen
- react
- 리액트 네이티브
- panorama view
- Privacy manifest
- ios
- requirenativecomponent
- privacyinfo.plist
- Today
- Total
Neoself의 기술 블로그
React Native 네이티브 모듈 연결하기 - 파노라마 뷰(Android 2/3) 본문
Android에서의 Native UIComponent 모듈 연결과정은 다음 순서로 진행된다.
- Android 환경 설정
1.1 build.gradle 설정
1.2 레이아웃 XML 파일 생성
1.3 AndroidManifest.xml 설정 - Native Module or View Manager 파일 생성
- Package 파일 추가
- MainApplication.kt 파일 수정
base레벨의 Native View가 ReactNative에서 호출될 수 있도록 연결 - React Native 단에서 네이티브 모듈 연결
1. Android 환경 설정
1.1 build.gradle 설정
먼저 app/build.gradle 파일에 필요한 패키지를 추가한다
implementation "androidx.core:core-ktx:1.12.0"
implementation files('../libs/sdk-base-1.200.0.aar')
- core-ktx는 PackageManager 파일에서 사용할 Annotation을 위한 패키지이며,
- sdk-base-1.200.0.aar는 파노라마 뷰 구현을 위한 gvr-android-sdk 패키지이다.
1.2 레이아웃 XML 파일 생성
android/app/src/main/res/layout 디렉토리에 네이티브 모듈이 표시되는 레이아웃 XML 파일을 추가한다.
<com.{프로젝트명}.video360.MonoscopicView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_root"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible"
/>
1.3 AndroidManifest.xml 설정
파노라마뷰를 구현하기 위해 필요로하는 하드웨어 특징과 권한을 AndroidManifest.xml 파일에 선언한다.
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
// 3차원 컴퓨터 그래픽스 API인 OpenGL의 서브셋
<uses-feature android:glEsVersion="0x00030002" android:required="true" />
// 기기의 가속도 센서
<uses-feature android:name="android.hardware.sensor.accelerometer" android:required="true"/>
// 기기의 자이로스코프 센서
<uses-feature android:name="android.hardware.sensor.gyroscope" android:required="true"/>
// 고성능 VR 기능
<uses-feature android:name="android.hardware.vr.high_performance" android:required="true"/>
// VR 모드 소프트웨어 기능
<uses-feature android:name="android.software.vr.mode" android:required="true"/>
// 외부 저장소를 읽을 수 있는 권한을 요청
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
...
</manifest>
2. View Manager 파일 생성
이 파일은 android/app/src/main/java/com/{앱이름}/ 즉, MainApplication.kt 파일이 존재하는 디렉토리에 생성해야하며, 통상적으로 구현하고자하는 임의 모듈명(ex.PanoramaView) 뒤에 Module 혹은 Manager를 붙여 명명한다. 이 파일은 네이티브 모듈의 동작을 제어한다.
구현 도중 시행착오
구현에 앞서 Android Activity의 LifeCycle을 React Native가 인식할 수 있는 View Manager 파일로 변경하는 접근방식을 파악해야 했다. gvr-android-sdk는 이미지 로드, 3D 공간 렌더 방식 설정, 터치동작 트래커 등록을 위한 initialize함수, 그리고 터치동작, 기기의 회전값에 따라 렌더이미지가 변화하는 onResume() 함수가 모두 연결되어야 동작이 되었는데, 안드로이드 액티비티 생명주기에 아무런 지식도 없었던 만큼, Manager 파일로의 변환을 위해 생명주기에 대한 리서치가 선행되어야 했다.
생명주기에 대한 러프한 조사를 완료한 이후, 택한 첫번째 접근방식은 Activity처럼 생명주기를 조작할 수 있는 Fragment를 생성하여 Manager에서 호출하는 것이였다. React native 공식문서에서 해당 Fragment 생성을 통해 네이티브 이벤트를 RN에서 자유롭게 호출하는 방식을 소개하였는데, 렌더되는 시점을 커스텀하기 보다는 뷰가 상시 렌더링되는 것이 목표였던만큼 지향하는 방향성이 다르다는 생각이 들었고, 무엇보다 Dispatch와 관련하여 에러가 발생해 Fragment호출이 원활하지 않았다.
Android Native UI Components · React Native
그 후, 택한 방향은 react에서 공식 제공하는 LifecycleEventListener 패키지를 활용해 ViewManager 파일 내부에서 생명주기를 접근 할수 있게 기능을 추가하는 것이였다. LifecycleEventListener에서 제공하는 onHostResume() 함수를 사용하여 onResume 생명주기에 접근할 수 있었다. 해당 방식을 택한 결과, Activity에서 호출한 것과 같이 정상 동작하는 것을 확인할 수 있었다.
public class PanoramaViewManager extends SimpleViewManager<MonoscopicView> implements LifecycleEventListener {
private static final String REACT_CLASS = "PanoramaView"; // RN에서 커스텀 뷰 매니저를 식별할때 사용함
@NonNull
@Override
public String getName(){ return REACT_CLASS; } // RN에서 해당 뷰 매니저의 이름을 가져오는 메서드를 오버라이드함
public MonoscopicView videoView;
// Manager 파일의 루트 선언구문, 제일 먼저 실행되는 구간이기에 initialize함수를 호출하였다.
public PanoramaViewManager(ReactApplicationContext context) {
//ReactApplication 컨텍스트에 LifecycleEventListner 추가하는 구문
context.addLifecycleEventListener(this);
// Activity 파일과 달리 Manager 파일에서 xml파일을 접근하기 위해선, LayoutInflater 클래스를 선언한 후, 해당 객체를 통해 xml파일을 참조해야한다.
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// 앞서 생성한 video_activity.xml에 맞춰 뷰를 생성한 후, 해당 뷰에서 파노라마뷰 초기화
videoView = (MonoscopicView) inflater.inflate(R.layout.video_activity, null);
videoView.initialize();
//이미지 데이터의 경우 Intent를 통해 MonoscopicView 클래스 내부 loadMedia 메서드의 인자로 전달
Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
intent.setClassName("com.google.vr.sdk.samples.video360", "com.google.vr.sdk.samples.video360.VrVideoActivity");
intent.setData(Uri.parse("file:///sdcard/IMAGE.JPG"));
intent.putExtra("stereoFormat", 2);
videoView.loadMedia(intent);
}
@NonNull
@Override
protected MonoscopicView createViewInstance(@NonNull ThemedReactContext reactContext) {
return videoView;
}
// 생명주기 메서드 구현
@Override
public void onHostResume() {
videoView.onResume();
}
@Override
public void onHostPause() {
videoView.onPause();
}
@Override
public void onHostDestroy() {
videoView.destroy();
}
}
3. Package 파일 추가
iOS의 네이티브 모듈 구현 과정과 가장 큰 차이점이라고 볼 수 있는데, Android 단에는 외부 패키지 사용 시, 별도로 Package파일을 추가하여 네이티브 모듈을 직접 호출해줘야 한다. Package 파일 내부에 사용하고자 하는 Manager, Module들을 등록해주어야 React Native의 initialize 과정에서 사용을 위한 준비과정을 거칠 수 있다.
// PanoramaViewPackage.kt
public class PanoramaViewPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
// Manager 파일만 등록할 것이기에, 모듈의 경우 빈 배열 반환
return Collections.emptyList();
}
@NonNull
@Override
public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
return Arrays.<ViewManager>asList(
// Manager 클래스 등록
new PanoramaViewManager(reactContext)
}
}
4. MainApplication.kt 파일 수정
// MainApplication.kt
class MainApplication : Application(), ReactApplication {
...
override val reactNativeHost: ReactNativeHost =
object : DefaultReactNativeHost(this) {
override fun getPackages(): List<ReactPackage> =
PackageList(this).packages.apply {
add(PanoramaViewPackage()) // Package파일 적용
}
...
}
...
그 후, 앞서 생성했던 Package 파일을 React Native CLI 초기 생성시 자동 생성되는 MainApplication.kt 파일에 직접 추가하는 과정을 거쳐 React Native initialize 작업에서 네이티브 모듈이 인식될 수 있도록 한다.
5. React Native 단에서 네이티브 모듈 연결
마지막으로 React Native 단으로 넘어와 선언된 네이티브 모듈을 연결한다.
// .../panoramaView/index.tsx
import { requireNativeComponent } from 'react-native';
// requireNativeComponent 인자값이 네이티브 단에서 선언한 이름과 일치해야함.
export const PanoramaView = requireNativeComponent<PanoramaViewProps>('PanoramaView');
이때 requireNativeComponent 로 모듈을 불러오는 구문과 모듈과 연결된 View 컴포넌트를 렌더하는 구문이 한 파일에 같이 존재할 경우, 하기 에러가 반환된다.
Invariant Violation: Tried to register two views with the same name PanoramaView
따라서, 위처럼 requireNativeComponent로 모듈을 불러오는 구문과 실제 View 컴포넌트를 렌더링하는 구문을 분리해야한다.
위 과정을 모두 완료할 경우, 최종적으로 다음과 같이 React Native 단에서 전체화면 혹은 특정 영역 내에서의 파노라마 뷰를 확인 및 상호작용할 수 있다.
다음 글에서는 이 기본 구현을 바탕으로 파노라마 뷰를 더욱 고도화하는 과정을 다루고자 한다.
Reference
Android Native Modules · React Native
'개발지식 정리 > React Native' 카테고리의 다른 글
React Native에서 PrivacyInfo.xcprivacy 대응하기 (0) | 2024.06.28 |
---|---|
React Native 스켈레톤 UI 모듈 구현 및 최적화 (0) | 2024.06.26 |
React Native 네이티브 모듈 연결하기 - 파노라마 뷰(iOS) (0) | 2024.06.20 |
React Native 네이티브 모듈 연결하기 - 파노라마 뷰(Android 3/3) (1) | 2024.06.10 |
React Native 네이티브 모듈 연결하기 - 파노라마 뷰(Android 1/3) (1) | 2024.06.06 |