애플 로그인을 위해서는 애플 개발자 계정이 존재해야 했고, 이 개발자 계정을 준비하는데 시간이 조금 걸렸기에 구글이나 카카오 로그인 보다 조금은 시간이 걸렸다.
하지만, 카카오와 다르게 파이어베이스 자체적으로 애플 로그인을 지원해주고, 플러터에도 애플 로그인 구현을 쉽게 해주는 라이브러리가 있기 때문에 그렇게 어렵지는 않았다.
애플 로그인을 구현하려면 애플 개발자 계정이 있어야 한다.
계발자 계정을 발급 받은 이후 인증서를 발급 받고 어플리케이션을 먼저 등록해야 한다.
애플 개발자 페이지의 계정탭에 가면 다음과 같이 인증서, 식별자 및 프로파일을 등록할 수 있는 부분이 보인다.
해당 옵션 중 인증서와 식별자를 등록해주도록 한다.
그 후 내가 생성했던 플러터 프로젝트를 Xcode에서도 설정해주어야 한다.
Xcode의 Runner 탭에 간 후 Signing & Capabilities에 가면 상단에 +Capability 탭이 보이는데 이때 유로 개발자 계정이라면 Sign in with Apple을 설정해줄 수 있다.
추가를 해주고 Signing 탭의 하단에 아래와 같이 Sign in with Apple이 선택 되었다면 정상적으로 추가를 한 것이다.
해당 프로젝트는 Firebase Auth를 사용해서 로그인을 구현할 예정이다.
파이어베이스 콘솔에 가서 Authentication 탭에서 아래와 같이 Apple을 추가해준다.
구글 로그인과 방식을 사실 동일하다.
Future<User?> signInWithApple() async {
final credential = await SignInWithApple.getAppleIDCredential(
scopes: [
AppleIDAuthorizationScopes.email,
AppleIDAuthorizationScopes.fullName,
],
);
final oauthCredential = OAuthProvider("apple.com").credential(
idToken: credential.identityToken,
accessToken: credential.authorizationCode,
);
final userCredential = await _firebaseAuth.signInWithCredential(oauthCredential);
final user = userCredential.user;
final idToken = await user!.getIdToken();
// Optionally get FCM token for push notifications
FirebaseMessaging messaging = FirebaseMessaging.instance;
String? token = await messaging.getToken();
await _storeUserInfoInPrefs(user, token);
// 가입 경로 추가
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString("social_type", "A");
int userCheck = await this.isRegistered(user!.uid!);
if(userCheck != 0){
updateMessagingToken(userCheck, token!);
authenticateFromServer(idToken, user!.uid!);
Get.to(HomeScreen());
}else{
Get.to(SignupScreen());
}
return user;
}
Firebase Auth에서 제공하는 SignInWithApple 함수로 credentials를 갖고 오고, Firebase Cloud Messaging 토큰을 발급 받고, 유저 정보들을 다른 화면에서도 사용 가능하도록 SharedPreferences에 담은 후 이미 가입 된 유저라면 홈 화면에, 그렇지 않다면 가입 화면에 보내주는 함수이다.
여기서 한가지 이슈가 발생했는데, 애플로그인의 경우 이메일과 유저명을 "" 빈 스트링으로 보내는 것으로 확인이 됐다.
그렇기 때문에 유저를 식별할 수 있는 Firebase에서 제공해주는 uid를 이메일 대안으로 사용해 해당 정보를 저장하고 해당 정보를 사용해 대조하려고 한다.
그렇기 때문에 가입을 하는 화면에서도 해당 정보를 반영할 수 있도록 변경을 해주었다.
SharedPreferences prefs =
await SharedPreferences.getInstance();
String? email = prefs.getString("email");
String? name = prefs.getString("displayName");
//애플은 null을 주기 때문에 이메일 대신 uid 사용
if (email!.length == 0) {
email = prefs.getString("userId");
}
if(name!.length == 0){
final generator = UniqueNamesGenerator(config: Config(dictionaries: [adjectives, colors, animals]));
name = generator.generate();
}
var response =
await sendUnguardedPostRequest('$baseUrl/user', {
'email': email,
"name": name,
"nickname": _nickNameController.text,
"pw": pw,
"socialType": prefs.getString("social_type"),
});
await authService.loginUserNow(
email!, pw);
await sendPatchRequest('$baseUrl/user',
{'token': prefs.getString("message")});
Get.to(const WelcomeScreen());
애플의 경우는 "" 빈스트링을 던져주기 때문에 빈 스트링을 받을 경우에 이메일을 유저 고유 식별값엔 uid로 설정을 해주고 유저명 역시 UniqueNameGenerator패키지를 이용해서 빈 스트링이 왔을떄 임의로 생성을 해주도록 한다.
그 후 해당 정보들을 Post request로 db에 저장을 해준다.
정상적으로 해당 유저가 아래와 같이 생성 된 것을 확인할 수 있다.
정상적으로 이메일을 받을 수 있는 방법이 있다면 좋겠는데, 이 부분에 대해서 아시는 분은 댓글을 남겨 주시거나 혹은 추후에 해당 이슈를 찾아서 고친다면 수정을 하도록 하겠다.