문의 시 사용하시는 SDK 버전 정보와 플랫폼(Android / iOS) 및 디벨로퍼스 앱ID를 알려주세요.
minSdkVersion 21 / Android -flutter로 개발중/ ID 1054732
안녕하세요. flutter로 kakao 로그인을 구현하던 중 오랫동안 해결하지 못했던 이슈를 해결하게 되었는데 이해가 되지 않아 글을 쓰게 되었습니다. 현상은 카카오로그인을 마치면 앱의 로직을 수행하지 않고, 앱이 종료되는 이슈였습니다. 에러는 아래와 같았습니다.
E/AndroidRuntime( 9789): Caused by: java.lang.ClassNotFoundException: Didn’t find class “com.kakao.sdk.auth.AuthCodeHandlerActivity” on path:
android/app/src/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" />
<!-- "kakao${YOUR_NATIVE_APP_KEY}://oauth" 형식의 앱 실행 스킴 설정 -->
<!-- 카카오 로그인 Redirect URI -->
<data android:host="oauth" android:scheme="kakao블러" />
</intent-filter>
</activity>
변경 후 (잘 작동):
<activity android:name="com.kakao.sdk.flutter.AuthCodeCustomTabsActivity">
<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" />
<!-- Redirect URI, "kakao${YOUR_NATIVE_APP_KEY}://oauth" 형식 -->
<data android:scheme="kakao블러" android:host="oauth"/>
</intent-filter>
</activity>
로그인 코드는 아래와 같았습니다.
// 카카오 로그인 관련 패키지 import
import 'package:kakao_flutter_sdk/kakao_flutter_sdk.dart';
final _storage = FlutterSecureStorage();
class LoginPage extends StatefulWidget {
const LoginPage({Key? key}) : super(key: key);
@override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
late VideoPlayerController _controller;
@override
void initState() {
super.initState();
_controller = VideoPlayerController.asset('assets/login.mp4')
..initialize().then((_) {
setState(() {});
});
_controller.setLooping(true);
_controller.play();
}
// 카카오 로그인 시작하기 버튼 클릭 시 동작하는 함수
void _loginWithKakao() async {
try {
bool isInstalled = await isKakaoTalkInstalled();
print("KakaoTalk Installed: $isInstalled");
if (isInstalled) {
// 카카오톡으로 로그인 시도
try {
var token = await UserApi.instance.loginWithKakaoTalk();
print('카카오톡으로 로그인 성공: ${token.accessToken}');
await sendTokenToServerAndNavigate(token.accessToken);
} catch (error) {
// 카카오톡으로 로그인 시도 실패
print('카카오톡으로 로그인 실패: $error');
if (error is PlatformException && error.code == 'CANCELED') {
return; // 사용자가 로그인을 취소한 경우
}
// 카카오 계정으로 로그인 시도
var token = await UserApi.instance.loginWithKakaoAccount();
await sendTokenToServerAndNavigate(token.accessToken);
}
} else {
// 카카오 계정으로 로그인 시도
var token = await UserApi.instance.loginWithKakaoAccount();
await sendTokenToServerAndNavigate(token.accessToken);
}
} catch (error) {
print('로그인 실패: $error');
// 로그인 실패 처리 로직
}
}
// 서버에 토큰을 전송하고, 성공적으로 응답을 받으면 홈 페이지로 이동
Future<void> sendTokenToServerAndNavigate(String token) async {
User user = await UserApi.instance.me();
final response = await http.post(
// Uri.parse('http://127.0.0.1:8000/kakao_login/'),
Uri.parse('https://블러com/kakao_login/'),
headers: {
'Content-Type': 'application/json',
},
body: jsonEncode(<String, String>{
'token': token,
'kakao_user_id': '${user.id}',
}),
);
if (response.statusCode == 200) {
var jsonResponse = jsonDecode(response.body);
var accessToken = jsonResponse['access'];
var refreshToken = jsonResponse['refresh'];
var userId = jsonResponse['user_id'];
await _storage.write(key: 'accessToken', value: accessToken);
await _storage.write(key: 'refreshToken', value: refreshToken);
await _storage.write(key: 'userId', value: userId);
Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (context) => HomePage()));
} else {
print('서버로부터 응답을 받는데 실패했습니다: ${response.body}');
// 여기에 실패 처리 로직을 추가하세요.
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
// 배경 동영상
_controller.value.isInitialized
? SizedBox.expand(
child: FittedBox(
fit: BoxFit.cover,
child: SizedBox(
width: _controller.value.size.width,
height: _controller.value.size.height,
child: VideoPlayer(_controller), // 비디오 플레이어
),
),
)
: SizedBox.expand(
child: FittedBox(
fit: BoxFit.cover,
child: SizedBox(
width: _controller.value.size.width,
height: _controller.value.size.height,
child: Image.asset('assets/login.png',
블러
],
),
),
),
],
),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
둘의 차이를 모르겠고, 어떤 부분이 원인이었는지 모르겠습니다. 감사합니다.