[팀 프로젝트] 스케줄러 모바일 어플리케이션 구축
회고

[팀 프로젝트] 스케줄러 모바일 어플리케이션 구축

작성일: 2026년 02월 03일·...

2023년 7월 ~ 12월 동안 진행되었던 모바일 어플리케이션 팀 프로젝트 회고입니다.


💡 Project Info

프로젝트명: KnockKnock

팀명: 4-Others

기간: 5월 21일 ~ 7월 말 (약 2개월)

플랫폼: iOS / Android (React Native)

한 줄 소개: 실사용이 가능한 개인화된 일정 관리 앱 (To-Do List 개선 프로젝트)


1. 기획 및 초기 세팅

화면 기획서
Notion Image

📅 기획 배경

기존의 To-Do List 프로젝트는 미완성 상태로 배포조차 되지 않은 상황이었다. 우리 팀(4-Others)은 이를 개선하여 실제 마켓에 배포 가능한 수준의 앱으로 발전시키기로 결정했다.

  • 필수 기능: 로그인/회원가입, 카드 스와이프 카테고리, 캘린더 조회, 검색, 마이페이지, 알림
  • 화면 기획서: Figma Link
  • 🛠 기술 스택 선정: React Native CLI

    Expo 대신 React Native CLI를 선택했다. 초기 세팅이 까다롭지만 다음과 같은 확실한 이점이 있었다.

  • React 베이스: 러닝 커브 최소화
  • 크로스 플랫폼: iOS와 Android 동시 지원
  • 확장성: Expo와 달리 사용 가능한 라이브러리에 제한이 없음
  • ⚙️ 환경 설정 (Troubleshooting)

    프로젝트 시작부터 환경 설정 오류와 맞서 싸워야 했다. 특히 Mac 환경에서의 의존성 관리가 핵심이었다.

  • CocoaPods 설치 (Ruby 기반): sudo gem install cocoapodspod setup
  • JDK & IDE: JDK 11, Xcode, Android Studio 설치
  • 프로젝트 생성
  • $ npm install typescript @types/react @types/react-native --save-dev
    $ react-native init front


    2. 핵심 기능 구현

    Notion Image

    Splash Screen을 활용한 자동 로그인

    앱의 아이덴티티를 보여주면서 백그라운드에서 로그인 프로세스를 처리하는 방식을 택했다.

  • 전략: AsyncStorage에 Access/Refresh Token 저장 → 스플래시 화면 진입 시 토큰 유효성 검사 → 자동 로그인
  • 구현: 보안되지 않은 비동기 저장소인 AsyncStorage를 사용하되, 편의성을 위해 Promise를 반환하는 모듈로 래핑했다.
  • Code: authUtil.ts (AsyncStorage 모듈)

    import AsyncStorage from '@react-native-async-storage/async-storage';
    
    // 데이터 접근
    const storageGetValue = async (key: string) => {
      try {
        const value = await AsyncStorage.getItem(key);
        return value !== null ? JSON.parse(value) : null;
      } catch (e: any) {
        console.log(e.message);
        return null;
      }
    };
    
    // 데이터 저장
    const storageSetValue = async (key: string, value: any) => {
      try {
        if (value !== null) {
          await AsyncStorage.setItem(key, JSON.stringify(value));
        }
      } catch (e: any) {
        console.log(e.message);
      }
    };
    // ...삭제 및 리셋 함수 포함
    🤔 Retrospective

    간단한 방법이지만, 보안이 중요한 실무에서는 EncryptedStorage나 키체인 같은 더 보안성이 높은 저장소를 고려해야 할 것 같다.

    Notion Image

    회원가입 프로세스 리팩토링 (Stack → Tab)

    Before (Stack Navigation)

    초기에는 약관 동의 → 이메일 → 비밀번호 순의 단일 흐름이었다. 하지만 백엔드 API 구조상 '이메일+비밀번호'를 먼저 보내 인증번호를 받는 방식이 필요했고, Stack 방식으로는 데이터 유지와 컴포넌트 언마운트 관리가 까다로웠다.

    After (Material Top Tabs)

    Material Top Tabs를 활용해 회원가입 단계를 탭으로 구성하고, navigation.setParams를 통해 상위 레벨에서 입력 데이터를 관리하도록 구조를 변경했다.

    // SignUpTab.tsx
    const SignUpTab: React.FC<onLoginProps> = ({onLogin}) => {
      // ...Progress Bar 로직 생략
      return (
        <SafeAreaView style={{flex: 1}}>
          <Tab.Navigator tabBar={props => <></>}> {/* 탭 바 숨김 */}
            <Tab.Screen name="SignAgree" component={SignAgree} />
            <Tab.Screen name="SignPassword" component={SignPassword} />
            <Tab.Screen name="SignEmail" component={SignEmail} />
            {/* ... */}
          </Tab.Navigator>
        </SafeAreaView>
      );
    };


    3. 소셜 로그인 (OAuth2) 도전과 실패, 그리고 해결

    Notion Image

    실패: React Native Webview

    초기에는 웹 개발 방식처럼 Webview를 띄워 Redirect URL을 가로채는 방식을 시도했다.

  • 결과: Google의 보안 정책상 인증 과정에서 Webview 지원이 중단되어 "Disallowed User Agent" 오류 발생.
  • 성공: Firebase SDK

    Google이 제공하는 모바일 SDK인 Firebase Authentication을 도입하여 해결했다.

  • Android: google-services.json 등록 및 SHA1 키 설정
  • iOS: Bundle ID 등록 및 GoogleService-Info.plist 설정
  • Notion Image
  • Code
  • const socialLogin = async (providerType: 'GOOGLE' | 'KAKAO') => {
        try {
          if (providerType === 'GOOGLE') {
            const userInfo = await GoogleSignin.signIn();
            // 백엔드에 ID Token 전달
            postId(userInfo.user.id, providerType);
          } 
          // ... Kakao 로직
        } catch (error) {
          console.log('Login Failed', error);
        }
    };

    4. 앱 배포 (Google Play Store)

    개발만큼이나 복잡했던 배포 과정을 정리한다.

    1. Package Name 변경

    RN CLI로 프로젝트를 생성하면 기본 패키지명이 설정되는데, 배포 전 이를 고유한 이름으로 변경해야 한다. MainActivity.java, AndroidManifest.xml, build.gradle 등 여러 파일의 수정이 필요했다.

    2. Keystore (서명 키) 생성

    안드로이드 앱의 신원 증명을 위한 키 생성 작업.

    keytool -genkey -v -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000

    3. 빌드 및 최적화

    android/app/build.gradle에서 enableSeparateBuildPerCPUArchitectureenableProguardInReleaseBuildstrue로 설정하여 용량을 최적화하고 난독화를 적용했다.

  • AAB 빌드 (스토어 게시용): cd android && ./gradlew bundleRelease
  • APK 빌드 (테스트용): cd android && ./gradlew assembleRelease
  • 4. 스토어 등록 및 심사

  • 준비물: 앱 아이콘(512px), 그래픽 이미지(1024x500), 스크린샷, 개인정보처리방침(Google Docs 활용).
  • 현재 상태: 프로덕션 + 공개 테스트로 제출하여 심사 대기 중.

  • 마치며

    이번 프로젝트를 통해 기획부터 개발, 그리고 스토어 배포를 위한 빌드 설정까지 앱 개발의 A to Z를 경험했다. 특히 백엔드 API 명세에 맞춰 프론트엔드 구조를 갈아엎었던 리팩토링 과정과, Webview 보안 이슈를 Firebase로 해결한 과정이 기억에 남는다.