이번에 <전자두뇌 정총무>라는 이름의 토이 프로젝트를 진행하던 중에 앱 내부에서 이미지를 만들어 공유해야되는 소요가 발생했다. 전자두뇌 정총무는 모임의 정산을 도와주는 앱인데, 정산 결과를 이미지 형태로 손쉽게 공유할 수 있도록 기능을 구현하려고 했기 때문이다. 각설하고 구현 방법은 다음과 같다.
이미지를 공유하기 위해서는 먼저 이미지를 만들어야 한다. 구글링 결과 컴포넌트를 스크린샷 찍듯이 찍어 이미지로 만들어주는 라이브러리를 발견했다. 이름은 react-native-view-shot이고 문서 링크는 여기에 있다.
사용방법도 아주 간단하다. 이미지화할 컴포넌트를 ViewShot으로 감싸고, ViewShot의 ref를 이용해 ref.current.capture()를 실행하면 된다.
import ViewShot from "react-native-view-shot";
function ExampleCaptureOnMountManually {
const ref = useRef();
useEffect(() => {
// on mount
ref.current.capture().then(uri => {
console.log("do something with ", uri);
});
}, []);
return (
<ViewShot ref={ref} options={{ fileName: "Your-File-Name", format: "jpg", quality: 0.9 }}>
<Text>...Something to rasterize...</Text>
</ViewShot>
);
}
//코드 출처: https://github.com/gre/react-native-view-shot
이제 컴포넌트를 캡쳐하는 과정은 끝났다. 이렇게 찍은 이미지를 공유하기만 하면 된다. react native에서는 자체적으로 Share라는 기능을 제공한다. Share를 사용하면 별도의 라이브러리를 설치할 필요 없이 아주 간단하게 공유 기능을 구현할 수 있다.
import React from 'react';
import { Share, View, Button } from 'react-native';
const ShareExample = () => {
const onShare = async () => {
const result = await Share.share({
message:
'React Native | A framework for building native apps using React',
});
};
return (
<View style={{ marginTop: 50 }}>
<Button onPress={onShare} title="Share" />
</View>
);
};
export default ShareExample;
//코드 출처: https://reactnative.dev/docs/share
await Share.share(options) 형태로 선언하고 option을 주기만 하면 자동으로 공유하기 시트를 띄워주기 때문에 아주 간편하다.
우리가 ViewShot을 통해 얻은 것은 캡쳐한 사진의 uri주소이므로, 이것을 공유하기 위해서는 uri앞에 file://을 붙여 파일 형태로 바꿔주는 과정이 수반되어야 한다.
const onShare = async (uri) => {
const result = await Share.share({
url:`file://${uri}`
});
};
그리고 실행을 해보면 정상적으로 컴포넌트가 이미지 형태로 공유됨을 확인할 수 있다.
.
.
.
ios 에서만...
파일을 공유하기 위해서는 Share option에 url로 주어야 하는데, react native에서 기본적으로 제공하는 Share의 url은 ios만 지원하는 기능이었다. 때문에 android에서는 아무런 이미지도 뜨지 않았다. 혹시 몰라 message에 넣어 공유해보았지만 이미지 형태가 아니라 string 형태로 url이 공유될 뿐이었다.
다른 방법이 없나 찾아본 결과 react-native-share라는 라이브러리를 발견했다. 사용방법 자체는 이전에 사용했던 Share와 거의 동일하지만 url을 ios, android모두 지원한다는 특징이 있었다. 라이브러리 문서를 참고하여 코드를 작성해보았다.
const onShare = async () => {
const result = await Share.open(options);
};
세부적으로는 차이점이 더 많겠지만, 기본 사용법 중에는 Share.share형태가 아니라 Share.open으로 사용한다는 차이점 외에는 특별히 두드러지는 차이점은 발견할 수 없었다. (await Share.open의 결과값 형태도 다르게 나오긴 한다. share를 성공했을 때나 실패했을 때 실행할 함수를 설정하려면 이 결과값을 사용하면 된다.)
const onShare = async (uri) => {
const result = await Share.open({
url:`file://${uri}`
});
};
이제 android에서도 똑같이 작동을 해야 하겠지만 실제로는 여전히 제대로 작동하지 않았다. 그 이유는 android의 경우 uri에 자동으로 'file://'이 찍혀나오기 때문에 그냥 uri만 넘겨줘야 하기 때문이다.
const onShare = async (uri) => {
const result = await Share.open({
url:Platfrom.OS === 'ios' ? `file://${uri}` : uri
});
};
이렇게 component를 이미지로 바꾸고 공유까지 할 수 있는 기능을 구현했다.
잘 동작한다.