flutter_기본

flutter - firebase API 연결

studyapps 2025. 8. 16. 19:35

안녕하세요~ Flutter로 앱 개발을 시작한 저와 같은 초보분들..혹시 API 키를 코드에 그대로 넣고 계신가요? 이렇게 코드 짰다가 GPT에게 혼이 났네요....ㅠ.ㅠ

 API 키를 안전하게 지키는 방법, 바로 Firebase Cloud Functions를 이용해 서버를 구축하는 뻘짓을 방금 끝낸 관계로....정리겸 해서 포스팅 합니다.

 

Flutter 코드에 API 키를 직접 넣으면, 누군가 마음만 먹으면 앱 파일을 분석해서 키를 훔쳐갈 수 있다고 하네요. GPT 가 이 이야기를 하면서 얼마나 혼내던지...이 키로 과도한 요청을 보내거나 악의적인 용도로 사용하면 모든 책임은 키 주인인 우리에게 돌아온다고....그래서 Flutter 앱이 직접 API를 호출하는 대신, 우리만의 안전한 중간다리(서버)를 만들어 문제를 해결 하는 과정을 보겠습니다.

 

1. Firebase 도구 설치 및 로그인

먼저 Node.js가 설치되어 있어야 합니다. 터미널을 열고 아래 명령어로 Firebase 개발 도구를 설치하고 로그인해주세요.

# Firebase CLI 설치
npm install -g firebase-tools

# Firebase 로그인 (웹 브라우저가 열리면 개발용 계정으로 로그인!)
firebase login

 

2. Flutter 프로젝트에 Firebase Functions 추가

작업 중인 Flutter 프로젝트의 최상위 폴더에서 아래 명령어를 실행합니다.

firebase init functions

몇 가지 질문이 나올 텐데, Use an existing project (기존 프로젝트 사용), JavaScript를 선택하고 나머지는 Yes로 답해주시면 functions라는 폴더가 생성됩니다. =>서버의 심장부!

 

3. Blaze 요금제로 업그레이드 

최신 Cloud Functions는 외부 인터넷으로 요청을 보내는 기능 등을 위해 Blaze(종량제) 요금제가 필수입니다. '유료'라는 말에 겁먹었지만...매월 200만 번 호출 등 엄청난 무료 제공량으로,  그정도가 아닌 인상은 사실상 돈이 나갈 일이 없다고 한다. 그래도 일단 사용량을 모니터링 하면서.. Firebase 콘솔에서 안내에 따라 카드를 등록하고 업그레이드 필요

 

4. API 키, Secret Manager에 보관

 최신이고 안전한 Secret Manager를 사용한해서 진행. 터미널에 아래 명령어를 입력해 LIBRARY_API_KEY에 API 키를 넣어준다. 

# 값 입력

firebase functions:secrets:set LIBRARY_API_KEY

# 잘 만들어졌는지 목록 확인

firebase functions:secrets:ls

 

5. 서버 코드 작성 및 배포 (index.js)

이제 서버가 할 일을 코드로 알려줄 차례입니다. functions 폴더로 이동해서 axios 설치하고, index.js 파일을 아래처럼 수정합니다.

# functions 폴더로 이동
cd functions
# 통신에 필요한 axios 설치
npm install axios

 

functions/index.js (최신 Gen 2 코드)

const {onCall} = require("firebase-functions/v2/https");
const {defineSecret} = require("firebase-functions/params");
const axios = require("axios");

// 사용할 비밀 키 정의
const libraryApiKey = defineSecret("LIBRARY_API_KEY");

exports.getPopularBooks = onCall({
  region: "asia-northeast3", // 서울 리전
  secrets: [libraryApiKey],   // 이 함수가 비밀 키를 사용하도록 허용
}, async (request) => {
  const apiKey = libraryApiKey.value();
  const apiUrl = `_API_URL?authKey=${apiKey}&...`;
  
  try {
    const response = await axios.get(apiUrl);
    return response.data;
  } catch (error) {
    throw new Error("API 요청 실패");
  }
});

이제 코드를 서버에 올립시다! 프로젝트 루트 폴더에서 아래 명령어를 실행하세요.

firebase deploy --only functions

 

2. Flutter 앱과 Firebase 연결하기

서버 준비가 끝났으니, 이제 앱과 연결할 차례입니다.

 

0. (필수) Firebase 콘솔에 내 앱 등록하기

flutterfire configure가 내 앱을 인식하게 하려면, 먼저 Firebase 콘솔에 방문해서 등록을 해야 합니다.

  1. Firebase 콘솔 > 프로젝트 개요 > '앱 추가'에서 안드로이드 아이콘 클릭
  2. 'Android 패키지 이름' 에는 내 Flutter 프로젝트의 android/app/build.gradle 파일에 있는 applicationId 값을 정확히 입력.
  3. '앱 등록' 버튼을 누른 뒤, 다음 단계들(파일 다운로드 등)은 모두 건너뜀! (이 작업은 flutterfire가 대신 해줌).

1. FlutterFire 도구로 자동 설정

터미널에서 아래 명령어로 Flutter와 Firebase를 연결을  설치하고 실행

# FlutterFire CLI 설치 (한 번만 하면 됨)
dart pub global activate flutterfire_cli

# 자동 설정 실행
flutterfire configure

(y/n) 질문에는 **n**을 (새로 검색해서 진행 필요)

플랫폼 선택에서는 ios, macos를 스페이스바로 체크 해제 (상황에 따라 다르다)

이 과정을 마치면 lib/firebase_options.dart 파일이 생성된다.

 

2. Flutter 코드 수정

pubspec.yaml에 firebase_core, cloud_functions를 추가하고, main.dart를 아래와 같이 수정

import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:cloud_functions/cloud_functions.dart';
import 'firebase_options.dart'; // 방금 성공적으로 생성된 파일

Future<void> main() async {
  // Flutter 앱이 실행되기 전에 Firebase를 먼저 초기화.
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  runApp(const MyApp());
}

 

 

main.dart 핵심 fetchData 함수

Dart
 
Future<void> fetchData() async {
  setState(() => isLoading = true);
  try {
    final functions = FirebaseFunctions.instanceFor(region: 'asia-northeast3');
    final callable = functions.httpsCallable('getPopularBooks');
    final result = await callable.call<Map<String, dynamic>>();
    
    var docs = result.data['response']['docs'] as List<dynamic>;
    # 이건 데이터 형식에 따라서 다르다
    setState(() {
      data = docs.map<Map<String, dynamic>>((item) => item['doc'] as Map<String, dynamic>).toList();
    });
  } catch (e) {
    setState(() => errorMessage = "에러 발생: $e");
  } finally {
    setState(() => isLoading = false);
  }
}

 

'flutter_기본' 카테고리의 다른 글

flutter : analysis_options.yaml : 경고 줄이기  (2) 2025.08.03
dart 기본 문법 - List  (3) 2025.07.30
함수를 변수에 할당  (0) 2024.07.16
flutter 테마 지정 (1)  (0) 2024.07.13