[Unity] Kakao login - iOS (2/2)

개요

이번 포스팅에서는 지난 포스팅에 이어서 AppDelegate를 오버라이딩하고 Objective-C 의 native code를 Unity로 가져와 실행할 bridge 코드 작성 부분을 다루도록 하겠습니다. 🙌

  • AppDelegate 오버라이딩 하기
  • Bridge 코드 작성하기

이 두 가지 작업을 하는 이유에 대해 먼저 개괄적으로 얘기해보면,

먼저, AppDelegate는 간단히 말하면 App이 해야할 일을 대신 구현한다는 의미로 앱이 실행될 때, 앱이 백그라운드로 전활될 때, 앱이 종료될 때 등의 앱의 전반적인 life cycle 전환에 따라 앱이 처리해 줘야할 작업들을 정의해 줄 수 있는 class입니다.

Kakao developers - 카카오 로그인 - iOS SDK 해당 문서를 보면 AppDelegate 설정이라는 단계가 있고 해당 클래스에 구현해 주어야 할 메서드를 기술해 두었습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
...
if ([KOSession isKakaoAccountLoginCallback:url]) {
return [KOSession handleOpenURL:url];
}
...
}

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
options:(NSDictionary<NSString *,id> *)options {
...
if ([KOSession isKakaoAccountLoginCallback:url]) {
return [KOSession handleOpenURL:url];
}
...
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
[KOSession handleDidBecomeActive];
}

이 부분을 Unity에서 구현해 주기 위해서는 Unity에서 해당 class를 오버라이딩할 수 있도록 제공하는 API를 이용해서 구현해 주어야 합니다.

다음으로, Bridge 코드는 iOS의 Native code로 작성된 메서드를 Unity에서 호출하기 위한 연결 고리 역할을 하는 코드가 필요한데, 이 부분을 작성한 코드라고 일단은 생각해 주시면 될 것 같습니다.


giphy_im_ready

자 그럼 하나하나 차근차근 진행해 보도록 하겠습니다.😎



AppDelegate 오버라이딩

Unity로 export된 xcode 프로젝트에는 AppDelegate 클래스가 구현된 AppDelegate.h.m파일이 생성되지 않습니다.

그러면 어떻게 구현해..?

유니티 매뉴얼에 보면, 이 부분에서 힌트를 얻을 수 있습니다.

아.. Unity는 UnityAppController라는 클래스를 통해 AppDelegate의 역할을 수행하는구나..


실제로 export된 xcode에서 해당 스크립트를 열어보면,

iOS App의 생명주기 별 실행할 delegate 메서드 들이 구현되어 있는 것을 볼 수 있습니다.

사실 이 파일에 카카오에서 지시하는 메서드들을 선언하고 호출해도 됩니다.


하지만, export하고 생성된 프로젝트에서 매 번 코드를 재작성하는 것은 비효율적이죠.

Unity에서는 이와 같은 작업을 Unity 프로젝트 내에서 할 수 있도록 매크로를 지원합니다.

export된 xcode 프로젝트를 열어서 생성된 UnityAppController.h파일을 열어보면

이렇게 subclassing을 통해 메서드를 오버라이딩 할 수 있도록 가이드하는 부분이 있습니다.


IMPL_APP_CONTROLLER_SUBCLASS매크로를 이용해서 subclassing을 하는 건데, 이 부분만 따라하면 완성입니다. 생각보다 간단해요.

지난 포스팅에서 생성했던 Unity 프로젝트에서 Assets/Plugins/iOS/ 경로에 OverrideAppDelegate.m파일을 xcode로 생성하여 위치 시켜줍니다.


그리고 다음과 같이 작성해 주세요.

1
2
3
4
5
6
7
8
9
10
11
12
#import "UnityAppController.h"

@interface OverrideAppDelegate : UnityAppController
@end

IMPL_APP_CONTROLLER_SUBCLASS(OverrideAppDelegate)

@implementation OverrideAppDelegate

// Override in here

@end

이렇게 작성한 후, kakaoSDK를 import 시켜주고 @implementation 안에 주석 부분에 overriding 하고자 하는 메서드를 아래와 같이 작성하면 끝입니다.

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
#import "UnityAppController.h"
#import <KakaoOpenSDK/KakaoOpenSDK.h>

@interface OverrideAppDelegate : UnityAppController
@end

IMPL_APP_CONTROLLER_SUBCLASS(OverrideAppDelegate)

@implementation OverrideAppDelegate

// Override to UnityAppController.mm
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
// [super application:application openURL:url sourceApplication:sourceApplication annotation:annotation];

if ([KOSession isKakaoAccountLoginCallback:url]) {
return [KOSession handleOpenURL:url];
}
}

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
options:(NSDictionary<NSString *,id> *)options {

// [super application:application openURL:url options:options];

if ([KOSession isKakaoAccountLoginCallback:url]) {
return [KOSession handleOpenURL:url];
}
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
[super applicationDidBecomeActive:application];

[KOSession handleDidBecomeActive];
}

@end

여기서 주의해 주셔야 할 부분이 [super ...] 부분인데, 기존에 정의된 super 클래스의 delegate부분을 그대로 sub class에 가져온 후 자신이 재정의하고자 하는 함수를 추가작업 해주셔야 에러를 내지 않고 build할 수 있습니다.


만약, 본인이 작성한 프로젝트를 빌드하는 과정에서 첫 번째나 두 번째 delegate 메서드에서 에러를 뿜는다면 주석([super ...])을 제거하고 한 번 빌드해보시길 권장드립니다.


참고로, Kakao에서 가이드 하는 세가지 delegate 메서드들 중에

첫 번째 메서드는 아래와 같이 9.0 이후로 Deprecated된 메서드입니다.


그 하단의 두 번째 메서드인 application:openURL:options: 메서드가 바로 대체제로 가이드 되는 메서드인데, 추가 옵션을 제외하고 기능은 첫 번째 메서드와 동일한 메서드입니다.


이 메서드는 9.0+ 의 OS 버전에서 지원되는 메서드로 아마 카카오가 SDK의 OS버전의 호환 문제로 두 가지다 기술해 놓은 것으로 보입니다.

그런데, 카카오 SDK도 9.0이상의 버전을 지원한다고 하네요.🤔


그래서 굳이..? 싶어서 첫 번째 delegate 메서드를 지우고 빌드해 봤는데 정상작동합니다.

따라서, 만약 프로젝트 세팅에서 9.0이상의 버전으로 타겟팅해서 빌드하신다면 첫 번째 delegate 메서드는 지우셔도 될 것 같습니다.

일단 저는 되더라구요..ㅎㅎ (안 된다면 죄송..ㅎ)



iOS Native code 작성

다음으로, 이제 카카오 SDK의 메서드를 호출해서 로그인을 구현하기 위해 네이티브 코드를 작성할껀데, Unity에서 swift를 작성하기 위해서는 추가적인 Bridge작업이 필요해서 저는 Obj-C로 구현했습니다.

먼저, 저는 다른 소셜 로그인도 추가될 것을 고려해서 directory를 위와 같이 구성하고 KakaoGetSocialUnityBridge.mm이라는 파일을 위치시켰는데, Kakao directory는 없어도 무방합니다.

그리고 파일 내부에 다음과 같이 코드를 작성합니다.

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
#import <KakaoOpenSDK/KakaoOpenSDK.h>

extern "C" {
void _sendKakaoLogin()
{
// Close old session
if ( ! [[KOSession sharedSession] isOpen] ) {
NSLog(@"in isOpen condition");
[[KOSession sharedSession] close];
NSLog(@"Old session closed");
}

// session open with completion handler
[[KOSession sharedSession] openWithCompletionHandler:^(NSError *error) {
if (error) {
NSLog(@"login failed. - error: %@", error);
}
else {
NSLog(@"login succeeded.");
}

// get user info
[KOSessionTask userMeTaskWithCompletion:^(NSError * _Nullable error, KOUserMe * _Nullable me) {
if (error){
NSLog(@"get user info failed. - error: %@", error);
} else {
NSLog(@"get user info. - user info: %@", me);
}
}];
}];
}
}

여기서 실제로 login하는 메서드는 [[KOSession sharedSession] openWithCompletionHandler:^(NSError *error)의 메서드이고,

[KOSessionTask userMeTaskWithCompletion:^(NSError * _Nullable error, KOUserMe * _Nullable me)의 메서드는 성공한 로그인 유저의 정보 객체를 받는 메서드 입니다.

저는 C++문법이 사용 가능한 Objective-C++(.mm)으로 플러그인을 구현하였는데,

유니티 - 매뉴얼: iOS 용 플러그인 빌드를 보시면 이와 같은 경우 extern "C" 를 통해 Name Manging 문제를 피하라고 나와 있으니 그대로 따라줍니다.

(name mangling에 대한 자세한 내용은 이 글을 참고하시면 좋을 것 같습니다.)



Bridge code 작성

이제 마지막으로 native code를 호출할 Bridge 코드를 작성해 볼껀데, Unity에서 iOS 메서드를 호출하기 위해서는 유니티 - 매뉴얼: iOS 용 플러그인 빌드에도 쓰여있다시피, [DllImport ("__Internal")]와 같이 명시적으로 불러와 주어야 합니다.

DLLImport는 C/C++로 작성된 Native DLL 함수를 호출할 필요가 있을 때, 메서드를 호출해 주는 역할을 합니다 (자세한 내용은 여기 MS 문서에..)

그리고 여기서 __Internal키워드는 XBox나 iOS와 같은 특정 플랫폼의 static linking을 위해 정의된 키워드 이므로 iOS플러그인을 사용할 우리는 이 키워드를 사용해야 합니다.


따라서, 아래와 같이 Assets directory 아래 편한 곳에

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;
using AOT;

public class FrameworkBridge : MonoBehaviour
{
#if UNITY_IOS
public static void SendLoginKakaoIOS()
{
Debug.Log("@kakao - login bridge function called");
if (Application.platform == RuntimePlatform.IPhonePlayer)
{
_sendKakaoLogin();
}
}

[DllImport("__Internal")]
static extern void _sendKakaoLogin();

#endif
}

이와 같이 작성한 스크립트를 추가해 주고, 원하는 로그인 지점에서 SendLoginKakaoIOS() 이 메서드를 호출만 해주면 아래와 같이 Kakao Login이 호출되고 동의항목에 따라 로그인한 유저 정보가 출력되는 모습을 보실 수 있습니다. 🥳



결론

뭔가 두서없이 쓴 것 같기도 한데, 아마 제 1,2번 글을 따라서 하셨다면 로그인하는 부분에 대해서는 에러가 없을꺼에요. (없어야 하고..)

제가 이 글에서 다루지는 않았지만, 기본적으로 Kakao Developers > 시작하기 > 애플리케이션 등록 이 링크에 나온 애플리케이션 등록과정은 거치셔야 카카오 로그인을 구현하실 수 있습니다.

(1편에다가 썻어야 했는데…)

Unity에 대한 전반적인 지식없이 구현을 시작해서 부족한 부분이 많고 틀린 부분도 아마 있을 껍니다. 만약 잘못 작성된 내용이나 코드가 있다면 가감없이 피드백 부탁드리겠습니다.😄


전체 코드는 여기 Github 링크에서 확인하실 수 있습니다.


참고