배운것들을 정리합니다.
三昧境

Flutter/tip

[플러터 Flutter] 소셜로그인 카카오톡 2 social login with Kakao 2

ujo_orr 2024. 7. 12. 21:45
 

[플러터 Flutter] 소셜로그인 카카오톡 1 social login with Kakao 1

Flutter 3.22.2Dart 3.4.3DevTools 2.34.3AndroidStudio 17.0.10 koalamac 기준으로 작성되었습니다.들어가기 앞서 카카오톡 플러터 공식문서도 있음 참고 부탁드립니다.https://developers.kakao.com/docs/latest/ko/flutter/getting

ujo-orr.tistory.com

 


 

우선 프로바이더 패키지를 설치하여 프로젝트에 적용시킵니다.

 

[플러터 Flutter] 상태관리 Provider, MultiProvider

상태관리란?애플리케이션의 상태(state)를 관리하는 것을 의미합니다.상태는 사용자 인터페이스(UI)와 상호작용하거나 애플리케이션의 내부 동작을 관리하는 데 필요한 데이터를 나타냅니다.상

ujo-orr.tistory.com

 

kakao_login_service.dart

이렇게 kakao_login_service.dart파일을 하나 생성해줍니다.

 

Kakao Developers

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

developers.kakao.com

KakaoDevelopers의 문서 내용을 참고하여

// 카카오 로그인 구현 예제

// 카카오톡 실행 가능 여부 확인
// 카카오톡 실행이 가능하면 카카오톡으로 로그인, 아니면 카카오계정으로 로그인
if (await isKakaoTalkInstalled()) {
  try {
      await UserApi.instance.loginWithKakaoTalk();
      print('카카오톡으로 로그인 성공');
  } catch (error) {
    print('카카오톡으로 로그인 실패 $error');

    // 사용자가 카카오톡 설치 후 디바이스 권한 요청 화면에서 로그인을 취소한 경우,
    // 의도적인 로그인 취소로 보고 카카오계정으로 로그인 시도 없이 로그인 취소로 처리 (예: 뒤로 가기)
    if (error is PlatformException && error.code == 'CANCELED') {
        return;
    }
    // 카카오톡에 연결된 카카오계정이 없는 경우, 카카오계정으로 로그인
    try {
        await UserApi.instance.loginWithKakaoAccount();
        print('카카오계정으로 로그인 성공');
    } catch (error) {
        print('카카오계정으로 로그인 실패 $error');
    }
  }
} else {
  try {
    await UserApi.instance.loginWithKakaoAccount();
    print('카카오계정으로 로그인 성공');
  } catch (error) {
    print('카카오계정으로 로그인 실패 $error');
  }
}

이 구문은 로그인을 위한 로직입니다.

try {
  await UserApi.instance.logout();
  print('로그아웃 성공, SDK에서 토큰 삭제');
} catch (error) {
  print('로그아웃 실패, SDK에서 토큰 삭제 $error');
}

그리고 이 구문은 로그아웃을 위한 로직입니다.

// 사용자 정보요청 로직

try {
      user = await UserApi.instance.me();
      print('사용자 정보 요청 성공'
          '\n회원번호: ${user?.id}'
          '\n닉네임: ${user?.kakaoAccount?.profile?.nickname}');
      notifyListeners();
    } catch (error) {
      print('사용자 정보 요청 실패 $error');
    }

공식문서에 나와있는 로직은 아니지만

사용자 정보요청 로직도 사용하여 회원번호와 닉네임을 받을수 있는 로직도 사용해보겠습니다.

// kakao_login_service.dart

class KakaoLoginService extends ChangeNotifier {
  User? user;

  Future<void> login() async {
    if (await isKakaoTalkInstalled()) {
      try {
        await UserApi.instance.loginWithKakaoTalk();
        print('카카오톡으로 로그인 성공');
        await _fetchUserInfo(); // 사용자 정보 가져오기
      } catch (error) {
        print('카카오톡으로 로그인 실패 $error');

        if (error is PlatformException && error.code == 'CANCELED') {
          return;
        }
        try {
          await UserApi.instance.loginWithKakaoAccount();
          print('카카오계정으로 로그인 성공1');
          await _fetchUserInfo(); // 사용자 정보 가져오기
        } catch (error) {
          print('카카오계정으로 로그인 실패1 $error');
        }
      }
    } else {
      try {
        await UserApi.instance.loginWithKakaoAccount();
        print('카카오계정으로 로그인 성공2');
        await _fetchUserInfo(); // 사용자 정보 가져오기
      } catch (error) {
        print('카카오계정으로 로그인 실패2 $error');
      }
    }
    notifyListeners();
  }

  Future<void> _fetchUserInfo() async {
    try {
      user = await UserApi.instance.me();
      print('사용자 정보 요청 성공'
          '\n회원번호: ${user?.id}'
          '\n닉네임: ${user?.kakaoAccount?.profile?.nickname}');
      notifyListeners();
    } catch (error) {
      print('사용자 정보 요청 실패 $error');
    }
  }

  Future<void> logout() async {
    try {
      await UserApi.instance.logout();
      print("로그아웃 성공");
      user = null; // 사용자 정보 초기화
      notifyListeners();
    } catch (error) {
      print("로그아웃 실패 $error");
    }
  }
}

그리고 provider에 있는 notifyListeners()를 활용하여 변경이 감지될시 알람이 주는 구문까지 추가하여 주겠습니다.

 


 

main.dart

 

runApp 내에 멀티프로바이더를 설정해주고
child 항목에 MyApp()을 넣습니다.

void main() {
  WidgetsFlutterBinding.ensureInitialized();

  KakaoSdk.init(nativeAppKey: '${YOUR NATIVE APP KEY}');

  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (context) => KakaoLoginService()),
      ],
      child: MyApp(),
    ),
  );
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: HomePage(),
    );
  }
}

 


 

homepage.dart

// 로그인 버튼
ElevatedButton(
 onPressed: () {
  Provider.of<KakaoLoginService>(context, listen: false).login();
 },
 child: Text("logout"))

// 로그아웃 버튼
ElevatedButton(
 onPressed: () {
  Provider.of<KakaoLoginService>(context, listen: false).logout();
 },
 child: Text("logout"))

이렇게 provider와 함께 KakaoLoginService를 사용하여 로그인, 로그아웃 버튼을 사용할 수 있습니다.

Provider.of<KakaoLoginService>(context, listen: false) 이 구문을 통해
provider패키지를 사용하여 KakaoLoginService 객체를 가져옵니다.
조금더 설명을 붙이자면

  • Provider.of
    • KakaoLoginService 타입의 프로바이더를 검색합니다.
    • 이는 ChangeNotifier Provider나 Provider로 제공된 객체를 찾습니다.
  • context
    • 현재 위젯의 빌드 컨텍스트 입니다.
    • 이를통해 트리 구조상 어디에서 Provider를 검색할지 결정합니다.
  • listen : false
    • 상태 변화에 대한 알림을 듣지 않겠다는 뜻입니다.
    • false로 설정하면 이 컨텍스트는 상태변화에 반응하지 않습니다.
    • 이는 보통 메서드 호출과 같이 단발성 작업에 사용됩니다.
class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Kakao login"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            GestureDetector(
              onTap: () {
                Provider.of<KakaoLoginService>(context, listen: false).login();
              },
              child: ClipRRect(
                borderRadius: BorderRadius.circular(50),
                child: Image.network(
                  "https://cdn-icons-png.flaticon.com/512/3984/3984330.png",
                  height: 200,
                  width: 200,
                ),
              ),
            ),
            SizedBox(height: 20),
            ElevatedButton(
                onPressed: () {
                  Provider.of<KakaoLoginService>(context, listen: false)
                      .logout();
                },
                child: Text("logout")),
            Consumer<KakaoLoginService>(
              builder: (context, kakaoLoginService, child) {
                if (kakaoLoginService.user != null) {
                  return Text(
                      '환영합니다, ${kakaoLoginService.user?.kakaoAccount?.profile?.nickname}');
                } else {
                  return Text('로그인해 주세요');
                }
              },
            ),
          ],
        ),
      ),
    );
  }
}

 

 


이렇게 카카오톡 로그인을 구현해보았습니다.

카카오톡으로 간편 가입같은 경우는 테스트앱이 아닌 비즈앱으로 변경했어야 했기때문에 시도해보진 못했으나 다음에 기회가 있으면 한번 해보고싶습니다.