[친구하자] Capacitor 앱 Custom Splash Screen 구현하기

Capacitor로 빌드한 앱에서 Splash Screen을 React로 직접 구현한 내용에 대해 다룹니다.

  • 이번 포스팅에선 Capacitor로 빌드한 앱에서 여러 아이콘이 순차적으로 표시되는 커스텀 스플래시 스크린을 구현하는 방법을 정리했다.
  • 왜 Custom splash screen이 필요했나?
    • Capacitor의 기본 splash screen은 단일 정적 이미지만 지원한다.🔗링크
    • 나는 여러 아이콘을 순차적으로 보여주는 애니메이션을 구현하고 싶어 React 컴포넌트로 직접 구현하였다!

목차


1. 필요한 패키지 설치

먼저 스플래시 스크린 관련 패키지를 설치하자.

나는 pnpm을 사용하고 있었으므로 pnpm으로 설치했다.

pnpm add @capacitor/splash-screen
pnpm add -D @capacitor/assets

2. Capacitor 설정

  • capacitor.config.ts 파일에 스플래시 스크린 설정을 추가하자.
  • ‼️ 커스텀 스플래시를 사용하므로 네이티브 스플래시는 최소화!
/// <reference types="@capacitor/splash-screen" />

import type { CapacitorConfig } from "@capacitor/cli";

const config: CapacitorConfig = {
  // ... 기타 설정
  plugins: {
    SplashScreen: {
      launchShowDuration: 0, // 커스텀 스플래시를 사용하므로 0으로 설정
      launchAutoHide: true, // 자동으로 숨길지 여부
      launchFadeOutDuration: 0, // 페이드 아웃 애니메이션 시간 (커스텀 스플래시에서 처리)
      backgroundColor: "#ffffff", // 배경색 (hex 형식) - 커스텀 스플래시와 동일하게 설정
      // ... 기타 설정
    },
  },
};

export default config;

3. 커스텀 스플래시 스크린 컴포넌트 생성

client/components/CustomSplashScreen.tsx 파일을 생성한다.

Props 정의

interface CustomSplashScreenProps {
  onComplete: () => void; // 스플래시 완료 시 콜백
  icons?: string[]; // 표시할 아이콘 배열
  iconDuration?: number; // 각 아이콘 표시 시간(ms)
  minDisplayDuration?: number; // 최소 표시 시간(ms)
  animationType?: "slide-up" | "fade" | "none";
  backgroundColor?: string;
}

핵심 로직

export const CustomSplashScreen = ({
  onComplete,
  icons = [],
  iconDuration = 500,
  minDisplayDuration = 2000,
  animationType = "slide-up",
  backgroundColor = "#ffffff",
}: CustomSplashScreenProps) => {
  const [currentIconIndex, setCurrentIconIndex] = useState(0);
  const [isVisible, setIsVisible] = useState(true);

  // 1. 네이티브 스플래시 스크린 즉시 숨기기
  useEffect(() => {
    const hideNativeSplash = async () => {
      try {
        await SplashScreen.hide();
      } catch (error) {
        // 웹 환경에서는 에러가 발생할 수 있으므로 무시
      }
    };
    hideNativeSplash();
  }, []);

  // 2. 아이콘 순차 표시 로직
  useEffect(() => {
    if (icons.length === 0) {
      const timer = setTimeout(() => {
        setIsVisible(false);
        setTimeout(onComplete, 300);
      }, minDisplayDuration);
      return () => clearTimeout(timer);
    }

    // 아이콘 전환 인터벌
    const iconInterval = setInterval(() => {
      setCurrentIconIndex((prev) => {
        if (prev < icons.length - 1) {
          return prev + 1;
        }
        return prev;
      });
    }, iconDuration);

    // 총 표시 시간 계산
    const totalAnimationDuration = icons.length * iconDuration;
    const actualDuration = Math.max(totalAnimationDuration, minDisplayDuration);

    const completeTimer = setTimeout(() => {
      setIsVisible(false);
      setTimeout(onComplete, 300);
    }, actualDuration);

    return () => {
      clearInterval(iconInterval);
      clearTimeout(completeTimer);
    };
  }, [icons, iconDuration, minDisplayDuration, onComplete]);

  // ... 렌더링 로직
};
  • 아이콘 슬라이드 애니메이션과 텍스트 추가 등 개인의 디자인에 맞게 React 코드를 수정해서 꾸며주면 된다!!

4. App.tsx에 통합

메인 앱 컴포넌트에 커스텀 스플래시 스크린을 통합합니다.

import { CustomSplashScreen } from "./components/CustomSplashScreen";

const AppRoutes = () => {
  const [showSplash, setShowSplash] = useState(true);

  // 스플래시 스크린에 표시할 아이콘들
  const splashIcons = [
    "/splash-icons/icon1.png",
    "/splash-icons/icon2.png",
    "/splash-icons/icon3.png",
    // ... 더 많은 아이콘
  ];

  const handleSplashComplete = () => {
    setShowSplash(false);
  };

  if (showSplash) {
    return (
      <CustomSplashScreen
        onComplete={handleSplashComplete}
        icons={splashIcons}
        iconDuration={400}
        minDisplayDuration={2000}
        animationType="slide-up"
      />
    );
  }

  // ... 나머지 앱 로직
};

🍎 핵심 구현 포인트 🍎

1. 네이티브 스플래시와 커스텀 스플래시 분리

  • launchShowDuration: 0으로 설정하여 네이티브 스플래시를 즉시 숨김
  • SplashScreen.hide()를 컴포넌트 마운트 시 호출

2. 텍스트 깜빡임 방지

아이콘과 텍스트를 별도의 div로 렌더링하여 아이콘이 변경될 때 텍스트가 깜빡이지 않도록 구현

3. 부드러운 애니메이션

CSS transitioncubic-bezier 타이밍 함수를 사용하여 자연스러운 전환 효과 구현

4. 최소 표시 시간 보장

minDisplayDuration을 설정하여 애니메이션이 너무 빨리 끝나도 최소 시간은 보장

5. 이미지 준비

아이콘 이미지는 public/splash-icons/ 디렉토리에 저장합니다.

public/
  splash-icons/
    icon1.png
    icon2.png
    icon3.png

‼️ 주의사항

  • 이미지는 반드시 public 폴더에 저장 (빌드 시 자동 포함)
  • 웹 환경에서는 SplashScreen.hide()가 에러를 발생시킬 수 있으므로 try-catch 처리 필요
  • Android 12 이상에서는 네이티브 스플래시 API가 강제 적용되므로 초기 0.5초는 네이티브 스플래시가 보일 수 있음

🍀 참고 문헌