React Native
React Native - 스크린샷 활용 (3) 갤러리 저장(@react-native-camera-roll/camera-roll)
크런키스틱
2025. 2. 17. 22:29
728x90
이전 글에 이어서 스크린샷을 갤러리에 저장하는 방법을 살펴본다.
이는 나중에 살펴볼 fs나 file-access 등과 같이 파일 시스템에 접근하여 파일과 디렉토리에 저장하는 것이 아닌 카메라 앨범에 저장하는 방법이다.
https://www.npmjs.com/package/@react-native-camera-roll/camera-roll
@react-native-camera-roll/camera-roll
React Native Camera Roll for iOS & Android. Latest version: 7.9.0, last published: 3 months ago. Start using @react-native-camera-roll/camera-roll in your project by running `npm i @react-native-camera-roll/camera-roll`. There are 35 other projects in the
www.npmjs.com
1. 설치
npm install @react-native-camera-roll/camera-roll
#or
yarn add @react-native-camera-roll/camera-roll
2. Android 권한 설정
android/app/src/main/AndroidManifest.xml 파일에 권한을 추가한다.
// AndroidManifest.xml
<manifest>
...
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
...
<application>
이 후, 권한을 묻는 코드를 작성한다.
// getCheckPermission.ts
import {PermissionsAndroid, Platform} from 'react-native';
export const hasAndroidPermission = async () => {
const getCheckPermissionPromise = () => {
if ((Platform.Version as number) >= 33) {
return Promise.all([
PermissionsAndroid.check(
PermissionsAndroid.PERMISSIONS.READ_MEDIA_IMAGES,
),
PermissionsAndroid.check(
PermissionsAndroid.PERMISSIONS.READ_MEDIA_VIDEO,
),
]).then(
([hasReadMediaImagesPermission, hasReadMediaVideoPermission]) =>
hasReadMediaImagesPermission && hasReadMediaVideoPermission,
);
} else {
return PermissionsAndroid.check(
PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE,
);
}
};
const hasPermission = await getCheckPermissionPromise();
if (hasPermission) {
return true;
}
const getRequestPermissionPromise = () => {
if ((Platform.Version as number) >= 33) {
return PermissionsAndroid.requestMultiple([
PermissionsAndroid.PERMISSIONS.READ_MEDIA_IMAGES,
PermissionsAndroid.PERMISSIONS.READ_MEDIA_VIDEO,
]).then(
statuses =>
statuses[PermissionsAndroid.PERMISSIONS.READ_MEDIA_IMAGES] ===
PermissionsAndroid.RESULTS.GRANTED &&
statuses[PermissionsAndroid.PERMISSIONS.READ_MEDIA_VIDEO] ===
PermissionsAndroid.RESULTS.GRANTED,
);
} else {
return PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE,
).then(status => status === PermissionsAndroid.RESULTS.GRANTED);
}
};
return await getRequestPermissionPromise();
};
3. 코드
// test.tsx
import CustomText from '@/components/text';
import {TestProps} from '@/types/stack';
import {useRef, useState} from 'react';
import {Button, Platform, StyleSheet, View} from 'react-native';
import {SafeAreaView} from 'react-native-safe-area-context';
import ViewShot from 'react-native-view-shot';
import {hasAndroidPermission} from '@/utils/getCheckPermission';
import {showBottomToast} from '@/utils/toastMessage';
import {CameraRoll} from '@react-native-camera-roll/camera-roll';
const TestScreen = ({navigation}: TestProps) => {
const [uri, setUri] = useState<string>('');
const viewShotRef = useRef<ViewShot>(null);
const onCapture = async () => {
const viewShotUri = await viewShotRef.current?.capture?.();
if (viewShotUri) setUri(viewShotUri);
};
// Save image to gallery
const onSaveGallery = async (uri: string) => {
if (Platform.OS === 'android' && !(await hasAndroidPermission())) {
return showBottomToast('error', '갤러리 접근 권한을 허용해주세요.');
}
await CameraRoll.saveToCameraRoll(uri, 'photo');
showBottomToast('success', '갤러리에 저장되었습니다.');
};
return (
<SafeAreaView className="flex-1">
<ViewShot
ref={viewShotRef}
style={style.viewShot}
options={{
fileName: `ScreenShot_${new Date().toDateString()}`,
format: 'jpg',
quality: 1,
}}>
<View className="w-2/3 h-2/3 flex justify-center items-center bg-white">
<CustomText className="text-success text-xl" children="테스트 화면" />
<Button title="캡처" onPress={onCapture} />
<Button title="저장" onPress={() => onSaveGallery(uri)} />
</View>
</ViewShot>
</SafeAreaView>
);
};
export default TestScreen;
const style = StyleSheet.create({
viewShot: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'green',
},
});
간단한 예시 코드로,
- 권한 허용 여부를 체크하고 허용되지 않았다면, 토스트 메세지를 띄운다.
- 허용된 상태라면 캡처한 이미지 uri를 저장한다.
물론 cameraRoll 라이브러리에는 saveToCameraRoll 말고도 앨범접근, 사진 삭제 등 다양한 methods가 제공되니 필요에 따라 찾아서 사용하면 된다.
4. 실행
실행해보면 잘 작동하는 것을 확인할 수 있다.
728x90