본문 바로가기

Flutter

[Flutter] Firebase의 Realtime Database 활용 app 만들기 2/3

반응형

VS code 에서 추가 작업

앞선 포스팅에서 필요한 설치를 했으니, 이제 코드 부분에 수정이 필요합니다.

2025.08.17 - [Flutter] - [Flutter] Firebase의 Realtime Database 활용 app 만들기 1/2

 

[Flutter] Firebase의 Realtime Database 활용 app 만들기 1/2

Multi-Platform Support with Single SourceFlutter는 Windows, Linux, Mac, Android, iOS, Web 등 다양한 플랫폼에서 실행 가능한 앱을 하나의 소스코드로 만들 수 있게 해줍니다. 예를 들어 간단한 메모 앱을 생각해봅시

joeyhwang.tistory.com

 

main.dart

main.dart 파일에서는 아래 3종의 수정이 필요합니다.

① firebase_core.dart, firebase_options.dart 패키지 import

② Firebase 초기화가 완료될 때까지 기다렸다가 widget이 실행되도록 수정

③ 테스트를 위해 floatingActionButton에 login 기능(AuthGate) 할당

 

아래가 전체 main.dart 코드이고 각 번호로 Comments를 붙여놨습니다.

이렇게 수정하고 나면, 2개의 AuthGate 관련 코드에 Error가 보일겁니다.

당연하죠. 아직 안 만들었으니까요.

import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';		// ① 추가 코드
import 'firebase_options.dart';					// ① 추가 코드
import 'authgate.dart';						// ① 추가 코드

Future<void> main() async {					// ② async 단어 추가
  WidgetsFlutterBinding.ensureInitialized();			// ② 추가 코드
  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); // ② 추가 코드
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text('You have pushed the button this many times:'),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // ③ 수정 부분 시작
          showDialog(context: context, builder: (context) => const AuthGate());
          // ③ 수정 부분 끝
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

 

이제 로그인의 핵심인 AuthGate class를 만들어야합니다.

새로운 파일을 하나 생성하고, authgate.dart라고 이름 붙인 후에, 아래 코드 전체를 붙입니다.

 

추가로,

2025.08.17 - [Flutter] - [Flutter] Firebase의 Realtime Database 활용 app 만들기 1/2 의 마지막 부분에서 작업했던 Client ID 들을 각각 해당하는 부분('Paste your client ID') 부분에 붙여주면 끝입니다.

import 'dart:io';import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:firebase_ui_oauth_google/firebase_ui_oauth_google.dart';
import 'package:flutter/material.dart';

class AuthGate extends StatelessWidget {
  const AuthGate({super.key});

  String get clientId {
    if (Platform.isAndroid) {
      return 'Paste your client ID'; // Android client ID
    } else {
      return 'Paste your client ID'; // Webapp client ID
    }
  }
  
  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(
      stream: FirebaseAuth.instance.authStateChanges(),
      builder: (context, snapshot) {
        if (!snapshot.hasData) {
          return FractionallySizedBox(
            widthFactor: 0.9,
            heightFactor: 0.9,
            child: Card(
              elevation: 8,
              shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(24),
              ),
              color: Theme.of(context).colorScheme.surface,
              child: Padding(
                padding: const EdgeInsets.symmetric(
                  horizontal: 14,
                  vertical: 14,
                ),
                child: SignInScreen(
                  providers: [
                    EmailAuthProvider(),
                    GoogleProvider(clientId: clientId),
                  ],
                  subtitleBuilder: (context, action) {
                    if (action == AuthAction.signIn) {
                      return const SizedBox(height: 24);
                    }
                    return const SizedBox.shrink();
                  },
                ),
              ),
            ),
          );
        }
        return FractionallySizedBox(
          widthFactor: 0.9,
          heightFactor: 0.4,
          child: Card(
            elevation: 8,
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(24),
            ),
            color: Theme.of(context).colorScheme.surface,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              mainAxisSize: MainAxisSize.min,
              children: [
                const SizedBox(height: 16),
                Text(
                  'You are logged in!',
                  style: Theme.of(context).textTheme.headlineSmall,
                ),
                const SizedBox(height: 12),
                TextButton.icon(
                  onPressed: () {
                    FirebaseAuth.instance.signOut();
                    Navigator.of(context).pop();
                  },
                  icon: const Icon(Icons.logout),
                  label: const Text('Sign out'),
                  style: TextButton.styleFrom(
                    foregroundColor: Theme.of(context).colorScheme.primary,
                    textStyle: Theme.of(context).textTheme.titleMedium,
                  ),
                ),
                const SizedBox(height: 12),
              ],
            ),
          ),
        );
      },
    );
  }
}

 

코드는 사실... 별게 없습니다. firebase_ui_auth, firebase_ui_oauth_google 패키지에서 제공하는

SignInScreen이라는 widget에 EmailAuthProvider와 GoogleProvider를 넘겨주면, 기본 UI 및 동작을 만들어서 반환해줍니다.

나머지 코드는 심미적으로 개선을 위한 데코레이션 코드들이니 차근차근 보시면 될 것 같습니다.

 

이제 기본적으로 잘 동작을... 해야합니다만... Android app에서 로그인하려면 firebase console 사이트에서 SHA-1 key를 등록해줘야합니다. 먼저 SHA-1 key를 생성합시다.

 

VS code의 TERMINAL 창에서 아래 명령어를 한줄씩 입력합니다.

cd android
./gradlew signingReport

 

아래와 같은 내용이 출력되면 그 중 SHA1 코드를 Copy합니다.

뭔가 중복되어서 많이 나오지만 SHA1 key는 모두 동일하니, 마지막 SHA1 key를 copy해 두면 됩니다.

Starting a Gradle Daemon (subsequent builds will be faster)

~~~~~~~~~~~~~~~~~~~~~~~~~~

> Task :google_sign_in_android:signingReport
Variant: debugAndroidTest
Config: debug
Store: C:\Users\~~~~\.android\debug.keystore
Alias: AndroidDebugKey
MD5: 12:34:56:78:9A:BC:DE:F0:12:34:56:78:9A:BC:DE:F0
SHA1: 12:34:56:78:9A:BC:DE:F0:12:34:56:78:9A:BC:DE:F0:12:34:56:78
SHA-256: 12:34:56:78:9A:BC:DE:F0:12:34:56:78:9A:BC:DE:F0:12:34:56:78:12:34:56:78:9A:BC:DE:F0:12:34:56:78:9A:BC
Valid until: 2055??8??7???좎슂??[좎슂??[
----------

[Incubating] Problems report is available at: file:///C:/Programming/flutterWorks/jorganizer/build/reports/problems/problems-report.html

Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0.

You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.

For more on this, please refer to https://docs.gradle.org/8.12/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation.

BUILD SUCCESSFUL in 17s
10 actionable tasks: 6 executed, 4 up-to-date

 

자, 이제 firebase console로 가서 복사해둔 SHA1 key를 등록하겠습니다.

https://console.firebase.google.com/

 

Project Overview 옆의 Gear icon을 클릭해서 Project settings로 진입하면,

기본 선택되어있는 General 탭이 보입니다.

아래로 쭉 Scroll 해서 Your apps 카드로 이동합니다.

 

앞서 VS code TERMINAL에서 입력한 명령들로 이미 앱이 추가되어있을겁니다.

Android apps 중 원하는 app의 이름을 클릭하고, Add fingerprint를 누른 후에 팝업창에 복사해둔 키를 입력하면 끝납니다.

등록된 SHA-1 키가 잘 보이면 이제 브라우저는 닫으셔도 됩니다. 

 

 

실제 동작은 아래와 같습니다. 첫화면에서 floating button을 누르면 Sign-in dialog를 띄웁니다. Sign in에 성공하면 Log in 중이라는 메세지와 함께 Sign out 버튼을 보여줍니다. 이때 Dialog 외부를 터치하면 Dialog는 닫힙니다.

 

Sign in 상태에서 floating button을 다시 누르면 Log in 중이라는 메세지를 보여주는 3번째 사진으로 넘어갑니다.

 

자 이제 Authentification까지는 구현이 완료되었습니다.

이제 Realtime database로 Cloud에 data를 저장하고 여러 기기에서 sync해서 사용할 수 있는 코드를 구현해보겠습니다.

다음 포스트에서...

반응형