유튜브, 인스타그램 등 어플을 사용하다 보면 공유하기 기능을 볼 수 있다.
해당 공유하기 기능을 구현하기 위해 조사를 해보았고. 파이어베이스를 사용한 구현은 2025년부터 지원을 안 하는것으로 확인되었다.
따라서 직접 딥링크를 사용한 공유하기 기능을 구현해보았다.
먼저 카카오톡 등으로 공유하기를 했을때 보통 썸네일, title, description과 같은 정보들이 나타나게 된다. 해당 기능을 구현하기 위해 먼저 SSR를 사용한 nextJS 프로젝트를 하나 셋팅한 뒤 AWS emplify에 배포해주었다.
위 정보가 같이 나타나게 하기 위해 메타데이터를 사용했다.
나는 title, description, thumbnailImage, date등의 정보를 포함하고 있는 대회를 공유할 수 있는 기능을 개발했고, 전체적인 흐름을 다음과 같이 잡았다.
nextJS프로젝트 셋팅 -> appRouter를 사용하여 SSR, 이때 해당 페이지에 접속하면 앱에서 대회 정보를 가져오는 엔드포인트의 API로 요청을 보내 같은 대회 데이터 정보를 가지고왔다. 이후 메타데이터를 사용하여 title, description, thumnailImage등의 정보를 먼저 보여주었다. -> 링크를 클릭했을 경우 앱이 설치되어있는 경우는 앱이 실행되면서 딥링크를 타고 해당 대회 스크린으로 이동, 설치되어있지 않은 경우는 앱스토어, 구글 플레이스토어의 해당 앱으로 연결
import { env } from "@/env";
import { SnackBarProps, SnackBarType } from "app/components/ui/types";
import { formatPeriod } from "app/utils/date";
import { Platform, Share } from "react-native";
interface ShareEventParams {
eventId: string;
title?: string;
progressStartAt?: string;
progressEndAt?: string;
locationName?: string;
locationAddress?: string;
showSnackBar: <T extends SnackBarType>(
type: T,
props: SnackBarProps[T]
) => void;
}
/**
* 이벤트 정보를 공유합니다.
* @param params 이벤트 정보 및 스낵바 표시 함수
*/
export async function shareEvent(params: ShareEventParams): Promise<void> {
try {
// 환경에 따라 딥링크 경로 결정
// Production: /event/{eventId}
// Development: /dev/event/{eventId}
const deepLinkPath =
env.NODE_ENV === "production"
? `event/${params.eventId}`
: `dev/event/${params.eventId}`;
// 딥링크 URL 생성
const eventUrl = `${env.DEEP_LINK_DOMAIN}/${deepLinkPath}`;
// 공유 메시지 구성
const shareMessage = `${params.title ?? ""}
${formatPeriod(params.progressStartAt, params.progressEndAt).label}
${params.locationName ?? ""}
${params.locationAddress ?? ""}
`;
const result = await Share.share({
message: shareMessage,
title: params.title ?? "Prize 대회",
url: Platform.OS === "ios" ? eventUrl : undefined, // iOS는 url 사용
});
if (result.action === Share.sharedAction) {
if (result.activityType) {
// 공유 성공 (특정 앱으로 공유됨)
console.log("공유 완료:", result.activityType);
} else {
// 공유 성공 (일반 공유)
console.log("공유 완료");
}
} else if (result.action === Share.dismissedAction) {
// 공유 취소됨
console.log("공유 취소");
}
} catch (error) {
console.error("공유 실패:", error);
params.showSnackBar("default", {
message: "공유에 실패했습니다.",
bottom: 100,
});
}
}
먼저 RN에서 공유하기를 press했을때 실행되는 함수이다. react-native가 제공하는 Share를 사용했다. nextJS로 미리 셋팅해놓은 SSR 페이지 링크를 던져준다.
nextJS에서는 해당 경로로 요청이 들어올 경우 API서버에 대회 정보를 요청해서 가져온 뒤 deppLink URL을 생성한다.
useEffect(() => {
const userAgent = navigator.userAgent || navigator.vendor;
const isIOS = /iPad|iPhone|iPod/.test(userAgent);
const isAndroid = /android/i.test(userAgent);
const isMobile = isIOS || isAndroid;
if (!isMobile) {
return;
}
const deepLinkUrl = `${DEEP_LINK_SCHEME}event/${eventId}`;
if (isIOS) {
const startTime = Date.now();
const timeout = 2500;
window.location.href = deepLinkUrl;
const handleVisibilityChange = () => {
if (document.hidden) {
window.removeEventListener(
"visibilitychange",
handleVisibilityChange
);
}
};
window.addEventListener("visibilitychange", handleVisibilityChange);
setTimeout(() => {
window.removeEventListener("visibilitychange", handleVisibilityChange);
if (Date.now() - startTime < timeout + 100) {
window.location.href = APP_STORE_URL;
}
}, timeout);
} else if (isAndroid) {
const startTime = Date.now();
const timeout = 2500;
const intentUrl = `intent://event/${eventId}#Intent;scheme=com.example`;
window.location.href = intentUrl;
const handleVisibilityChange = () => {
if (document.hidden) {
window.removeEventListener(
"visibilitychange",
handleVisibilityChange
);
}
};
window.addEventListener("visibilitychange", handleVisibilityChange);
setTimeout(() => {
window.removeEventListener("visibilitychange", handleVisibilityChange);
if (Date.now() - startTime < timeout + 100) {
window.location.href = PLAY_STORE_URL;
}
}, timeout);
}
}, [eventId]);
이후 위와 같이 앱이 설치되어있을경우 딥링크 url을 들고 앱을 실행시켜준다. 앱이 설치되어 있지 않은 것으로 간주될경우 timeout을 주어 앱스토어, 구글 플레이 스토어로 이동시킨다.
RN에서는 앱의 시작지점인 EntryPoint에서 전역으로 관리될 navigationRef를 하나 만들어주었고. Provider를 하나 추가 생성하여
useEffect(() => {
// 앱이 꺼져있을 때 딥링크로 열린 경우
const handleInitialURL = async () => {
try {
const initialUrl = await Linking.getInitialURL();
if (initialUrl) {
console.log("Initial deep link URL:", initialUrl);
handleDeepLink(initialUrl);
}
} catch (error) {
console.error("Failed to get initial URL:", error);
}
};
위처럼 DeepLink를 들고 앱이 실행된 경우에 대한 처리를 진행해주었다.
firebase dynamic link 없이 next SSR페이지를 직접 띄워 공유하기를 처리해줬는데, 시간은 좀 걸렸지만 원리를 좀 더 정확하게 이해하며 기능을 구현할 수 있었던 것 같다.
'React-Native' 카테고리의 다른 글
| [RN] 안드로이드 에뮬레이터 harfbuzz text shaping으로 인한 프로세스 종료 (0) | 2026.01.07 |
|---|---|
| [RN] Google Spread Sheet를 이용한 다국어 처리 설계 (0) | 2025.12.30 |
| [RN] React-Native에 Toss PG 연결하기 (version1) (0) | 2025.12.23 |
| [RN] Expo eas IOS 빌드 & TestFlight테스트 (0) | 2025.12.22 |
| [RN] Expo54버전 채널톡 연동 NOT_INITIALIZED 이슈 (0) | 2025.12.18 |