Post

플러터에서 카카오 로그인 구현

플러터에서 카카오 로그인 구현

프로젝트에서 카카오 로그인 기능이 필요하기 때문에 카카오 로그인을 플러터에서 구현한다 카카오 로그인후 토큰까지 확인해본다

1. 플러그인 설치와 앱키 설정

사용할 플러그인은 kakao_flutter_sdkflutter_dotenv이다 fluter pub add 명령어를 통해서 설치한다

카카오앱은 등록은 생략하고 네이티브 앱키를 이용해야한다 앱키는 노출하면 안되므로 .env파일을 root에 생성한다 생성한 파일에 키를 작성한다

KAKAO_NATIVE_APP_KEY=키입력

이제 앱키를 .env에서 가져와 사용하면 된다

1
2
3
4
5
6
7
8
9
10
11
12
// main.dart
import 'package:kakao_flutter_sdk/kakao_flutter_sdk_common.dart';

void main() async {
  await dotenv.load(fileName: '.env');

  KakaoSdk.init(
    nativeAppKey: dotenv.get('KAKAO_NATIVE_APP_KEY'),
  );

  runApp(MyApp());
}

또한 파일을 추가한것을 pubspec.yaml에 명시한다

1
2
3
4
flutter:
  uses-material-design: true
  assets:   # 아래를 추가한다
    - .env 

위설정을 하고 나면 프로젝트가 정상적으로 실행되어야한다 카카오 로그인은 Flutter의 minSdkVersion이 21보다 낮을 경우 문제가 발생할 수 있다

 

2. xml 파일 수정

Project/android/app/src/AndroidManifest.xml에 위치한 파일을 수정한다

1
<uses-permission android:name="android.permission.INTERNET" />

인터넷 사용권한 허용

커스텀 URL

커스텀 URL 스킴(Custom URL Scheme)은 사용자가 Android와 iOS 환경에서 카카오톡으로 로그인 후 서비스 앱으로 돌아오거나, 카카오톡 메시지 버튼 또는 링크로 서비스의 앱을 실행하는 데 사용한다

위 xml과 같은 파일을 수정한다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
        <!-- 카카오 로그인 커스텀 URL 스킴 설정 -->
        <activity 
            android:name="com.kakao.sdk.flutter.AuthCodeCustomTabsActivity"
            android:exported="true">
            <intent-filter android:label="flutter_web_auth">
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />

                <!-- "kakao${YOUR_NATIVE_APP_KEY}://oauth" 형식의 앱 실행 스킴 설정 -->
                <!-- 카카오 로그인 Redirect URI -->
                <data android:scheme="kakao${KAKAO_NATIVE_APP_KEY}" android:host="oauth"/>
            </intent-filter>
        </activity>

이제 xml에 사용한 변수를 정의해줘야한다

android 내부 local.properties에 KAKAO_NATIVE_APP_KEY를 정의한다

정의된 키를 사용하기 위해서 android/app/src/build.gradle을 수정

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def localProperties = new Properties() //추가
localProperties.load(new FileInputStream(rootProject.file("local.properties"))) //추가

android {
    namespace = "com.example.mapping_flutter"
    compileSdk = flutter.compileSdkVersion
    ndkVersion = flutter.ndkVersion

    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = JavaVersion.VERSION_1_8
    }

    defaultConfig {
        applicationId = "com.example.mapping_flutter"
        manifestPlaceholders["KAKAO_NATIVE_APP_KEY"] = localProperties.getProperty("KAKAO_NATIVE_APP_KEY") //추가 부분
        minSdk = 21
        targetSdk = flutter.targetSdkVersion
        versionCode = flutter.versionCode
        versionName = flutter.versionName
    }

 

3. 앱 등록

카카오 디벨롭에 들어가서 내 애플리케이션 > 앱설정 > 플랫폼으로 들어간다

패키지명 -> 앱id와 키 해시를 입력한다

키 해시는 아래의 명령어로 찾을 수 있다 하지만 아래로 얻은 해시값으로 로그인이 안되었다 키 오류 발생

keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64

main.dart에서 키값을 추출할 수 있었다

 

4. main.dart

이제 카카오톡 로그인을 실행하기 위해서 위젯을 생성한다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import 'package:flutter/material.dart';
import 'package:kakao_flutter_sdk_user/kakao_flutter_sdk_user.dart';
import 'package:kakao_flutter_sdk/kakao_flutter_sdk_common.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await dotenv.load(fileName: '.env');

  KakaoSdk.init(nativeAppKey: dotenv.get('KAKAO_NATIVE_APP_KEY'));

  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Kakao Login Demo',
      home: const MyHomePage(title: 'Kakao Login'),
    );
  }
}

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

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  String? _userNickname;
  String? _userProfileImage;

  Future<void> _loginWithKakao() async {
    try {
      if (await isKakaoTalkInstalled()) { //앱 존재하는 경우
        OAuthToken token = await UserApi.instance.loginWithKakaoTalk();
        print('카카오톡으로 로그인 성공 ${token.accessToken}');
      } else { //앱이 존재하지 않는 경우
        OAuthToken token = await UserApi.instance.loginWithKakaoAccount();
        print('카카오톡으로 로그인 성공 ${token.accessToken}');
      }
      _fetchUserInfo(); //유저정보를 가져옴
    } catch (error) {
      print(await KakaoSdk.origin);
      print('Login failed: $error');
    }
  }

  Future<void> _fetchUserInfo() async {
    try {
      User user = await UserApi.instance.me();
      setState(() {
        print(user); //유저정보를 모두 보기 위함
        _userNickname = user.kakaoAccount?.profile?.nickname;//닉네임, 이미지만 가져옴
        _userProfileImage = user.kakaoAccount?.profile?.thumbnailImageUrl;
      });
    } catch (error) {
      print('Failed to get user info: $error');
    }
  }

  Future<void> _logout() async {
    try {
      await UserApi.instance.logout();
      setState(() {
        _userNickname = null;
        _userProfileImage = null;
      });
    } catch (error) {
      print('Logout failed: $error');
    }
  }

  @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>[
            _userProfileImage != null
                ? CircleAvatar(
                    backgroundImage: NetworkImage(_userProfileImage!),
                    radius: 40,
                  )
                : const Icon(Icons.account_circle, size: 80),
            const SizedBox(height: 10),
            Text(
              _userNickname ?? '로그인 해주세요',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: _userNickname == null ? _loginWithKakao : _logout,
              child: Text(_userNickname == null ? '카카오 로그인' : '로그아웃'),
            ),
          ],
        ),
      ),
    );
  }
}

위 코드는 로그인을 하면 유저 데이터중 닉네임, 프로필 사진을 가져와서 저 이후 닉네임의 유무로 로그인을 확인한다 로그아웃은 저장한 데이터를 null로 다시 넣어 데이터를 초기화한다

1
2
I/flutter ( 8616): 카카오톡으로 로그인 성공 jnK-84QiddghSqciI91qZELqq0X0fbDAAAAAAQorDKgAAAGUzAOlsdafsadfsdf
I/flutter ( 7540): {id: *******, properties: {nickname: 김민정}, kakao_account: {profile_nickname_needs_agreement: false, profile: {nickname: 김민정}}, connected_at: 2024-11-02T10:59:32.000Z}

위 데이터는 가져온 유저 정보와 accesstoken이다 초기 앱설정시 닉네임만 가져오도록 설정해서 profile에 nickname만 존재한다 만약 사진까지 허용하면 사진도 같이 받을 수 있다

위 코드에서 print(await KakaoSdk.origin);를 통해서 직접 키 해시를 확인하고 카카오 앱 설정에서 확인한 키 값으로 교체했더니 카카오 로그인이 정상적으로 실행되었다

This post is licensed under CC BY 4.0 by the author.