본문 바로가기

dev/flutter

flutter 카카오 로그인

 

 

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

 

 

1. 애플리케이션 등록

 

 

1) 안드로이드 플랫폼 등록

 

 

- 키해시

 

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

 

2) IOS 플랫폼 등록 (번들 ID만 넣어도 된다)

 

 

 

 

2. 카카오 로그인 활성화

 

권한이 필요한 동의항목은 후에 신청을 해야함.

 

 

 

3. 안드로이드

 

1) AndroidManifest.xml

 

<!-- 카카오 로그인 -->
<activity 
    android:name="com.kakao.sdk.auth.AuthCodeHandlerActivity"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />

        <!-- Redirect URI: "kakao${NATIVE_APP_KEY}://oauth" -->
        <data android:host="oauth" android:scheme="kakao${NATIVE_APP_KEY}" />
    </intent-filter>
</activity>

 

 

4. IOS

 

1) Info.plist

 

<!-- 외부 URL 스키마 설정 -->
<key>LSApplicationQueriesSchemes</key>
<array>
    <!-- 네이버 로그인 -->
    <string>naversearchapp</string>
    <string>naversearchthirdlogin</string>

    <!-- 카카오 로그인 추가 -->
    <string>kakao49048364251e558642d55464ee16838a</string>
    <string>kakaokompassauth</string>
    <string>storykompassauth</string>
</array>


<array>
    <!-- 네이버 로그인 -->
    <dict>
        <key>CFBundleTypeRole</key>
        <string>Editor</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>naver</string>
        </array>
    </dict>
    <!-- 카카오 로그인 추가 -->
    <dict>
        <key>CFBundleTypeRole</key>
        <string>Editor</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>kakao49048364251e558642d55464ee16838a</string>
        </array>
    </dict>
</array>

 

2) AppDelegate.swift

 

  // 기존 네이버 로그인 코드를 아래로 수정
  override func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    if url.absoluteString.hasPrefix("kakao"){
      super.application(app, open:url, options: options)
      return true
    } else if url.absoluteString.contains("thirdPartyLoginResult") {
      NaverThirdPartyLoginConnection.getSharedInstance().application(app, open: url, options: options)
      return true
    } else {
      return true
    }
  }

 

 

5. 패키지 설치

 

flutter pub add kakao_flutter_sdk // 카카오 공통 SDK 
flutter pub add kakao_flutter_sdk_user // 카카오 로그인 SDK
flutter pub add kakao_flutter_sdk_auth // 카카오 인증 SDK (필요시)

 

6. 코드 수정

 

import 'dart:developer';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:async';

import 'package:flutter_naver_login/flutter_naver_login.dart';
import 'package:kakao_flutter_sdk/kakao_flutter_sdk.dart';

final GlobalKey<ScaffoldMessengerState> snackbarKey =
    GlobalKey<ScaffoldMessengerState>();

void main() {

  WidgetsFlutterBinding.ensureInitialized();

  // runApp() 호출 전 Flutter SDK 초기화
  KakaoSdk.init(
    nativeAppKey: '${네이티브키}',
    javaScriptAppKey: '${자바스크립트키}',
  );

  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      scaffoldMessengerKey: snackbarKey,
      theme: ThemeData(
        primarySwatch: Colors.green,
        primaryColor: const Color(0xFF00c73c),
        canvasColor: const Color(0xFFfafafa),
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);
  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String? accessToken;
  String? expiresAt;
  String? tokenType;
  String? refreshToken;
  String? naverName;
  String? naverPhoneNumber;
  String? naverEmail;
  String? naverId;

  int? kakaoId;
  String? kakaoEmail;
  String? kakaoNickname;
  String? kakaoProfileImage;

  /// Show [error] content in a ScaffoldMessenger snackbar
  void _showSnackError(String error) {
    snackbarKey.currentState?.showSnackBar(
      SnackBar(
        backgroundColor: Colors.red,
        content: Text(error.toString()),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text(
          'Flutter Naver Login Sample',
          style: TextStyle(color: Colors.white),
        ),
      ),
      body: ListView(
        children: [
          const SizedBox(height: 12.0),
          Column(
            children: [
              const SizedBox(height: 6.0),
              Text('accessToken: $accessToken'),
              const SizedBox(height: 6.0),
              Text('refreshToken: $refreshToken'),
              const SizedBox(height: 6.0),
              Text('tokenType: $tokenType'),
              const SizedBox(height: 6.0),
              Text('name: $naverName'),
              const SizedBox(height: 6.0),
              Text('phone: $naverPhoneNumber'),
              const SizedBox(height: 6.0),
              Text('email: $naverEmail'),
              const SizedBox(height: 6.0),
              Text('id: $naverId'),
              const SizedBox(height: 12.0),
              InkWell(
                onTap: () {
                  naverLogin();
                },
                child: Image.asset('assets/naver_log_in.png', height: 60),
              ),
              const SizedBox(height: 12.0),
              InkWell(
                onTap: () async {
                  naverLogout();
                },
                child: Image.asset('assets/naver_log_out.png', height: 60),
              ),
            ],
          ),
          const SizedBox(height: 12.0),
          const Divider(thickness: 3),
          const SizedBox(height: 12.0),
          Column(
            children: [
              const SizedBox(height: 6.0),
              Text('nickname: $kakaoNickname'),
              const SizedBox(height: 6.0),
              Text('email: $kakaoEmail'),
              const SizedBox(height: 6.0),
              Text('id: $kakaoId'),
              const SizedBox(height: 6.0),
              if(kakaoProfileImage != null)
              Image.network(kakaoProfileImage!, errorBuilder: (context, error, stackTrace) => Container(), width: 100,),
              const SizedBox(height: 12.0),
              InkWell(
                onTap: () {
                   kakaoLogin();
                },
                child: Image.asset('assets/kakao_log_in.png', height: 60),
              ),
            ],
          ),
        ],
      ),
    );
  }

  void naverLogin() async{
    try{
      final NaverLoginResult user = await FlutterNaverLogin.logIn();
      log("네이버 로그인 결과: $user");
      NaverAccessToken res = await FlutterNaverLogin.currentAccessToken;

      log("네이버 로그인 결과: $res");

      setState(() {
        accessToken = res.accessToken;
        tokenType = res.tokenType;
        refreshToken = res.refreshToken;

        naverId = user.account.id.toString();
        naverName = user.account.name;
        naverEmail = user.account.email;
        naverPhoneNumber = user.account.mobile
          .replaceAll('+82', '0')
          .replaceAll('-', '')
          .replaceAll(' ', '')
          .replaceAll('+', '');
      });

    }catch(error){
      print('naver login error $error');
    }
  }

  Future<void> naverLogout() async {
    try {
      await FlutterNaverLogin.logOut();
      setState(() {
        accessToken = null;
        tokenType = null;
        naverName = null;
        naverPhoneNumber = null;
        naverEmail = null;
      });
    } catch (error) {
      _showSnackError(error.toString());
    }
  }

  // 카카오 로그인 구현 예제
  void kakaoLogin() async {
    // 카카오톡 설치 여부 확인
    if (await isKakaoTalkInstalled()) {
      try {
        await UserApi.instance.loginWithKakaoTalk();
        log('카카오톡으로 로그인 성공');

        try {
          User user = await UserApi.instance.me();
          setState(() {
            kakaoEmail = user.kakaoAccount?.email;
            kakaoNickname = user.kakaoAccount?.profile?.nickname;
            kakaoId = user.id;
            kakaoProfileImage = user.kakaoAccount?.profile?.profileImageUrl;
          });
        } catch (error) {
          print('사용자 정보 요청 실패 $error');
        }
      } catch (error) {
        log('카카오톡으로 로그인 실패 $error');
        
      }
    } else {
    	log('카카오톡으로 로그인 실패');
        await UserApi.instance.loginWithKakaoAccount(); // 카카오계정으로 로그인
        ...
    }
  }

}