Unity 멤버십

Unity에서 Hybe Game Platform Service(이하, Platform) 연동을 위한 Unity SDK 사용법에 대해서 설명합니다.

요구사항

Unity용 Platform SDK를 사용하기 위한 요구 사항은 아래와 같습니다.

  • 최소 사양 : 2021.3.1f

  • OS : Windows, Mac OS x86/silicon

2021.3.1f 이후 버전에서 테스트 되었습니다.

연동 준비

SDK 설치

Unity에서 Platform SDK를 사용하기 위한 프로젝트를 구성하는 방법은 다음과 같습니다.

  1. 지정된 메뉴에서 SDK를 다운로드 합니다.

  2. Unity에서 Assets > Import Package > Custom Package... 메뉴를 차례로 선택한 후 HyPlatformPlugin.unitypackage 파일을 선택합니다.

  3. Import 팝업에서 [import] 버튼을 클릭하여 SDK를 현재 프로젝트에 설치합니다.

폴더 설명

Platform SDK 에 포함된 구성은 다음과 같습니다.

폴더 명
용도

AppAuth

iOS Apple 인증(Signin) 라이브러리 파일

Editor Default Resources

Firebase에서 사용하는 이미지 리소스

ExternalDependencyManager

Android, iOS 외부 모듈 종속성(dependency)를 체크하는 DLL. Unity 에디터의 Assets/External Depency Manger 하위에 OS별 Dependency 체크 메뉴에 관련 기능이 표시됩니다.

Firebase

Firebase 라이브러리 파일

GoogleSignIn

GoogleSignIn 라이브러리

HyPlatform

Platform 플러그인 DLL 파일. Android, iOS, Windows로 각각의 DLL이 위치합니다.

Resources/Platform/dev

실행환경(dev)에 디폴트 설정 파일(PlatformConfig.json)이 위치합니다.

HyPlatformSample

SDK를 이용한 플랫폼 로그인 샘플

- Scene/LoginScene : 샘플 Scene

윈도우 환경에서 유니티 에디터의 PlayMode에서 로그인 테스트 가능합니다.

윈도우에서 검증 한 후에 안드로이드, IOS에서 확인하세요.

Config 파일 설정하기

Platform SDK 동작에 필요한 필수 정보를 Config 파일에 입력합니다.

이름
용도
예시

webClientId

플랫폼에서 제공하는 Web Client ID

serviceId

플랫폼에서 발급하는 게임 서비스 ID

ApiKey

플랫폼에서 제공하는 API Key

AuthDomain

웹을 통해서 인증하는 경우 인증 업체(google, apple)의 인증 정보가 리다이렉션 되는 도메인. 플랫폼에서 제공합니다.

hyplatform-b66f4.web.app

SteamAppID

스팀 AppID, 스팀 연동하는 경우에 필요. 개발사에서 퍼블리싱할 앱을 스팀에 등록한 후 게임사에 전달합니다.

1234567

SteamIdentity

개발사에서 제공하는 스팀 identity

test-dev-10040000

CustomScheme

게임별 웹에서 진행하는 Signin 결과를 수신하는 Custom URI

game1, hyplatform

Config 파일은 실행 환경(dev, stage, prod 등)에 따라 별도의 파일로 분리되어 사용해야 합니다.

실행 환경은 개발사에서 원하는 임의의 문자열을 사용합니다.

실행 환경에 따라 Config 파일의 위치는 다음과 같습니다.

기본 위치는 Resources/Plattform/실행환경명/PlatformConfig.json 입니다.

  • Resources/Platform/dev/PlatformConfig.json

  • Resources/Platform/prod/PlatformConfig.json

Custom URL Scheme 설정 설정 파일에 계정 연동시 사용되는 Custom URL을 지정할 수 있습니다.

{
  "CustomScheme": "hyplatform"
}

계정 연동 로그인 창(PC: 웹뷰, AOS: Custom Tab, IOS: SafariView)의 계정 연동을 위해 반드시 설정이 필요합니다.

OS 별로 Custom URl Scheme를 별도로 설정해야 합니다. 아래 환경 설정 항목에서 세부 설정 가이드를 참고하세요.

사용가능 문자 : 영숫자, - (7days 와 같이 숫자로 시작할 수 없습니다.)

Android 환경 설정

사전에 제공받은 Firebase 설정 파일(google-services.json)을 아래 위치에 복사합니다.

위치 : Asset/google-services.json

원하는 임의의 폴더에 위치해서 동작에는 영향은 없습니다.

google-services.json 파일을 제공받기 위해서는 사전에 적용할 게임 클라이언트의 안드로이드 APK 구성할 때 사용한 Keystore 파일의 SHA-1 값을 플랫폼에 전달해야 합니다.

AndroidManiest.xml

커스텀 탭을 적용한 Apple, Line, X 로그인 연동에 필요한 딥링크를 설정합니다.

아래 예제는 Custom URL Scheme 으로 "hyplatform"을 지정하는 intent-filter 예제입니다.

<activity>
  <intent-filter android:autoVerify="true">
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.BROWSABLE" />
    <category android:name="android.intent.category.DEFAULT" />
    <!-- Signin 리다이렉트 Custom uri -->
    <data
        android:host="signin"
        android:scheme="hyplatform"/>
  </intent-filter>
</activity>

CustomTab 지원 브라우저 쿼리를 위한 설정 추가

안드로이드 API 30 이상 버전을 타겟으로 할 경우 기본 브라우저가 CustomTab을 지원하는지 확인하기 위해 queries 설정을 추가해야합니다.

<manifest>
  <queries>
	  <!-- intent에 action은 하나만 존재할 수 있으므로 이미 다른 intent가 있다면 따로 만들어줍니다.  -->
    <intent>
      <action android:name="android.support.customtabs.action.CustomTabsService" />
    </intent>
  </queries>
</manifest>

IOS 환경 설정

사전에 제공받은 Firebase 설정 파일(GoogleService-Info.plist)을 아래 위치에 복사합니다.

위치 : Asset/GoogleService-Info.plist 원하는 임의의 폴더에 위치해서 동작에는 영향은 없습니다.

Custom URL Scheme 설정

Google, Line Signin 이후 게임으로 돌아오기 위해서는 URL Scheme 을 등록 해야 한다.

Project Settings > Player > IOS > Other Settings > Configuraion > Supported URL Schemes

하위에 요소 추가 후 게임에 할당된 URL Scheme을 입력합니다. 아래는 Custom URL Scheme 으로 "hyplatform"을 지정하는 경우입니다.

Steam 환경 설정

아래와 같이 환경 별 스팀 정보를 설정한다.

PlatformConfig.json (prod)

{	
   -- 중략 --
	"BuildEnv": "prod",
  "SteamAppID": 2484250,
  "SteamIdentity": "astra-prod-10040100"
}
속성
용도
예시

SteamAppID

연동할 스팀앱 ID

SteamIdentity

스팀 ID 토큰 (개발사에서 발금)

PlatformConfig.json (qa)

{
   -- 중략 --
  "BuildEnv": "qa",
  "SteamAppID": 2581010,
  "SteamIdentity": "astra-qa-10040040"
}

SDK Define Symbols

Define Constraints
설명

HYBE_USE_ENTERPRISE_SDK

엔터프라이즈 환경에 대응하는 SDK를 사용하도록 합니다. (현재 iOS 환경만 별도로 엔터프라이즈 SDK를 제공합니다.)

API 연동

API Flow

  1. API 초기화

  2. 플랫폼 로그인

    1. Google/Apple

  3. 로그인 결과 콜백 수신

    1. 약관 동의

    2. 로그인 성공/실패

  4. 게임 서버 로그인

로그인 Flow

버전

Hybe.Platform.Version.CurrentVersion

SDK 배포 버전 값을 갖습니다. SDK 버전 정보를 확인 및 노출하고 싶을 때 사용할 수 있습니다.

초기화

게임의 첫 번째 씬(Scene)에서 SDK를 초기화합니다.

초기화 함수(Mount) 가 비동기 함수로 제공됩니다.

  • Firebase 초기화

  • 푸시 초기화

  • 접속 국가 정보 로딩

  • 결제 Agent 등록

  • 웹뷰 Agent 등록

bool bPlatformInitialized = false; //SDK 초기화 상태 플래그

private void Awake()
{

PlatformSupervisor.Mount("dev").ContinueWithOnMainThread( task =>
{
	if(task.Result == true)
	{
    		bPlatformInitialized = true;
      
		PlatformSupervisor.SetAuthEventDelegate(OnLoginSuccess, OnLoginFailur);
		PlatformSupervisor.SetLogoutEventDelegate(OnLogoutSuccess, OnLogoutFailur);
		PlatformSupervisor.SetMessagingEventDelegate(OnMessageReceived);

#if UNITY_STANDALONE_WIN
		PlatformSupervisor.SetSteamEventDelegate(OnSteamConnected); //Steam Support
#endif

		//3. 결제 이벤트를 처리하는 IBillingAgent를 설정한다.
		BillingPlatform.RegisterBillingAgent(new ClientBillingAgent());
		
		//4. 웹뷰 Agent를 등록한다.
		PlatformSupervisor.SetWebviewAgent(new StarterWebviewAgent());
	}
	else
	{
		Debug.LogError("Platform SDK Init Failur");
		return;
	}
});

}

윈도우에서 스팀을 연동하는 경우 아래와 같이 스팀 이벤트 delegate를 추가합니다.

private void Awake()
{
           ---- 중 략 ----
    PlatformSupervisor.SetLogoutEventDelegate(OnLogoutSuccess, OnLogoutFailur);
#if UNITY_STANDALONE_WIN
    PlatformSupervisor.SetSteamEventDelegate(OnSteamConnected);
#endif
}

실행 환경 설정하기

PlatformSupervisor.Mount("dev");

초기화 함수는 인자로 임의의 실행 환경 정보를 입력 받습니다. ex) dev, stage, qa, prod, live …

입력된 실행 환경 정보는 실행시 로딩하는 설정 파일(PlatformConfig.json)을 구분하는데 사용합니다.

로그인은 두 종류로 구분해서 사용하겠습니다.

플랫폼 로그인

  • 인증 제공 업체(Google/Apple)를 통해서 인증 한 후 인증 결과를 Platform에 전송하여 검증 후 Platform 서비스에 인증을 수행하는 과정

  • 인증에 성공하는 경우 클라이언트는 IMID를 수신합니다.

게임 서버 로그인

  • 플랫폼 로그인 성공 후에 수신한 IMID를 이용해서 게임 서버에 연동하는 과정

  • IMID를 수신한 게임 서버는 Platform에 수신한 IMID의 유효성 검증을 해야 합니다. 자세한 내용은 서버 API 연동 가이드(링크필요) 를 참고하세요.

로그인 환경 설정

Aandoid 구글 로그인 환경 설정

구글 로그인 기능을 사용하기 위해서는 플랫폼의 Firebase 의 안드로이드앱 등록시 사용할 SHA-1 값을 사전에 플랫폼에 전달하여 googles-service.json 파일을 제공받아야 합니다.

SHA-1은 안드로이드 APK 구성할 때 사용한 Keystore 파일의 SHA-1값입니다.

애플 로그인 환경 설정

플랫폼으로부터 제공 받은 Firebase 설정 파일(GoogleService-Info.plist)을 Asset 폴더 하위에 복사합니다.

이벤트 델리게이트 등록

PlatformSupervisor.SetAuthEventDelegate

플랫폼 인증 연동에 필요한 델리게이트(콜백)을 등록한다.

void SetAuthEventDelegate(Action<string> loginSuccessDelegate,
                          Action<string> loginFailurDelegate)

파라미터

  • loginSuccessDelegate 로그인 성공 시 호출

  • loginFailurDelegate 로그인 실패 시 호출

PlatformSupervisor.SetLogoutEventDelegate

플랫폼 로그아웃 시 수신하는 델리게이트(콜백)을 등록한다.

void SetLogoutEventDelegate(Action logoutSuccessDelegate, 
                            Action<string> logoutFailurDelegate, 
                            Action withDrawDelegate)

파라미터

  • logoutSuccessDelegate 로그 아웃 성공 시 호출

  • logoutFailurDelegate 로그 아웃 실패 시 호출

  • withDrawDelegate 계정 탈퇴 시 호출

로그인

PlatformSupervisor.Signin

플랫폼 로그인을 수행한다.

public void Signin(SigninMethod signinMethod, bool bEnableAutologin)

파라미터

  • signinMethod 로그인 종류, SigninMethod 참고

  • bEnableAutologin 자동 로그인 플래그

public enum SigninMethod
{
    IM,
    GOOGLE,
    APPLE,
    STEAM,
    LINE,
    X,
    FACEBOOK,
    GUEST,
}

구글 로그인 적용 예시

public void OnClickGoogleLogin()
{
    PlatformSupervisor.Signin(SigninMethod.GOOGLE, false);
}

자동 로그인

이전 로그인 했던 정보를 이용해서 인증 과정을 생략하고 플랫폼 로그인을 수행합니다.

자동 로그인 해제

PlatformSupervisor.Signout() 호출 시 로그인 정보가 초기화 됩니다.

스팀 로그인의 자동 로그인

스팀의 자동 로그인을 처리할 때는 현재 스팀 클라이언트에 로그인 되어있는 계정의 아이디 정보를 활용하므로 스팀 계정이 변경 되면 기존에 이용하던 IMID의 자동 로그인은 실패하게 됩니다.

PlatformSupervisor.DoAutoLogin

플랫폼 자동 로그인을 수행한다.

public void DoAutoLogin(Action<bool> callback)

파라미터

  • callback 결과를 리턴 받을 콜백

자동 로그인 가능 상태 즉, 이전 로그인 정보가 존재하여 자동 로그인을 시도하는 경우 true가 전달되고, 이전 로그인 기록이 없어서 자동 로그인을 시도하지 않는 경우 false가 전달됩니다.

자동 로그인의 성공/실패는 등록한 로그인 핸들러(OnLoginSuccess, OnLoginFailur)로 전달됩니다.

PlatformSupervisor.DoAutoLogin((bTrying) =>
{
  // 자동 로그인을 정상 시도하는 경우
  if(bTrying)
  {
      //로그인 버튼 숨김 처리
      UpdateLoginUI(bLogined: false, bTryLogin: true);
  }
});

게스트 로그인 UDID 생성 출처

OS
UDID
저장

Android

UnityEngine.SystemInfo.deviceUniqueIdentifier

iOS

UnityEngine.SystemInfo.deviceUniqueIdentifier

키체인

Windows

UnityEngine.SystemInfo.deviceUniqueIdentifier

MacOS

UnityEngine.SystemInfo.deviceUniqueIdentifier

Delegate 구현

Platform 로그인 연동 과정에서 발생하는 이벤트를 등록된 Delegate에 전달하며, 게임 클라이언트는 Delegate를 구현하여 Platform과 커뮤니케이션 합니다.

OnLoginSuccess

using Hybe.Platform.Entity;

void OnLoginSuccess(string resultJson)
{
    LoginResult res = LoginResult.FromJson(resultJson);
    Debug.Assert(res.resultCode == ResultCode.SUCCESS);

    // TODO : 수신된 로그인 정보를 이용해서 게임사의 서버 로그인 진행
}

Platform 로그인 결과는 JSON 문자열로 전달되며 Hybe.Platform.Entity를 통해 LoginResult 객체로 변환하여 사용할 수 있습니다.

public class LoginResult
{
    public string loginToken;
    public string imid;
    public string countryCode; // 가입시점의 국가 코드 (ex. KR, JP 등)
}

수신 된 imId 를 사용해서 개발사의 서버에 전달하여 게임을 계속해서 진행합니다.

OnLoginFailur

void OnLoginFailur(string resultJson)
{
    HyError error = HyError.FromJson(resultJson);

    // TODO : 로그인 에러 실패 프로세스 구현
}

다양한 원인으로 플랫폼 로그인에 실패하는 경우 호출되는 Delegate입니다.

Platform 로그인 결과는 JSON 문자열로 수신 되며 Hybe.Platform.Entity를 통해 HyError 로 변환하여 사용할 수 있습니다.

public class HyError
{
    public Code code;
    public string message;
}

public enum Code
{
    UNKNOWN_ERROR = 0,
    NO_INITIALIZE = 1,
    SIGNIN_FAIL = 2, //Google/Apple Signin
    PLATFORM_LOGIN_FAIL = 3, //Platform login
    AUTO_LOGIN_FAIL = 4, //Auto login fail
    WITHDRAW_ACCOUNT = 5, //계정 탈퇴 회원
    CANCELED = 6, //취소됨
}

에러 코드별 전달되는 message는 다음과 같습니다.

Code
message
설명

SIGNIN_FAIL

google sigin failure

안드로이드에서 Google Signin 환경 에러

Apple SignIn failed

iOS Apple Signin 실패

Apple Signin Error

iOS Apple Signin 오류 발생

Unknown login error

PLATFORM_LOGIN_FAIL

DORMANT_ACCOUNT

휴면유저

Already log in

로그아웃하지 않고 로그인 시도

Steam login not supported

스팀 로그인 미지원 환경에서 로그인 시도하는 경우

Platform login API Fail

게임 플랫폼 연동 에러 - 네트워크/서버 에러 등

Steam no prepare

스팀 연결 실패

Auth Fail

Google/Apple/Line 등 3rd Party Signin 에러

NOT_ALLOWED_AGE

일본에서 PC 런처로 미성년자(16세)일 경우

FAIL_LOCK_REQUEST

로그인 중복 요청

Unknown error

CANCELED

Login Cancel

로그인 취소

OnWithDraw

계정 탈퇴 요청이 완료된 후 호출되는 Delegate입니다.

void OnWithDraw()
{
    // 탈퇴가 요청되었으므로 기존에 로그인 되어있던 정보를 초기화 합니다.
    // 탈퇴를 요청한 계정은 PlatformSupervisor.SignOut을 수행할 수 없기 때문에 
    // 대신 ForceSignOut 함수를 사용합니다.
    PlatformSupervisor.ForceSignOut();
    
    // TODO:
    // ex) 계정 선택 창으로 이동
}

OnShowWebview

void OnShowWebview(string url)
{
    //TODO 지정된 URL로 인게임 웹뷰를 팝업합니다.
}

로그인 과정에서 웹뷰 팝업이 필요할 때 호출되는 Delegate입니다. 인자로 전달된 약관 동의 URL을 웹뷰로 팝업합니다.

호출되는 경우는 다음과 같습니다.

  • 로그인 팝업

    • PC : 모든 플랫폼 로그인 입력(Google, Apple, Line, X, 이메일)

    • Android : 이메일 로그인

      • Apple, Line, X는 안드로이드 Custom Tab을 사용합니다.

    • iOS : 이메일 로그인

      • Google, Line, X는 iOS SFSafariView를 사용합니다.

  • 서비스 이용 동의

  • 대표 이메일 설정

  • 본인 인증

OnLogoutSuccess

로그 아웃이 성공적으로 진행되는 경우 호출되는 Delegate 입니다.

void OnLogoutSuccess()
{
  //TODO : 로그 아웃 이후 프로세스를 구현한다.
  //       ex) 다른 계정 또는 서버 접속 UX를 출력한다.
}

OnLogoutFailur

로그 아웃이 실패한 경우에 호출되는 Delegate입니다. 주로 모바일 환경에서 네트워크 오류로 서버에 로그아웃 요청이 전달되지 않았거나 결과를 수신하지 못한 경우에 발생한다.

다시 로그아웃을 요청하여 로그아웃 과정을 완료하세요.

void OnLogoutFailur(string message)
{
}

OnSteamConnected

윈도우에서 스팀 연동을 하는 경우에 호출되는 Delegate로 연동 성공/실패 시 호출됩니다.

  private void OnSteamConnected(string message)
  {
      if (string.IsEmptyOrNot(message) == false)
      {
          Log($"Steam Connected, ID = {message}");
      }
      else
      {
          Log("Steam Disonnected");
      }
  }

파라미터로 전달되는 정보(message)는 다음과 같습니다.

  • 성공할 경우, 스팀 ID

  • 실패한 경우, 빈 문자열

PlatformSupervisor.CancelSignin

로그인 진행 과정을 취소합니다. (윈도우 전용)

로그인 웹뷰를 직접 종료하는 경우에 호출해야 합니다. 호출하면 OnLogoutFailur() delegate가 호출됩니다.

public void OnClickCancelLogin()
{
    PlatformSupervisor.CancelSignin();
}

void OnLoginFailur(string resultJson)
{
    HyError error = HyError.FromJson(resultJson);
    if(error.message == "Login Cancel")
			Debug("로그인이 취소되었습니다");
    else
			Debug("로그인 실패");
}

PlatformSupervisor.Signout

플랫폼 로그아웃을 수행합니다. 실패시 LogoutFailur Delegate가 호출됩니다.

PlatformSupervisor.ForceSignout

플랫폼 로그 아웃 없이 SDK 로그인 정보를 리셋합니다.

실패시 LogoutFailur Delegate가 호출됩니다.

PlatformSupervisor.ProcessWithDraw

로그인 된 현재 계정의 탈퇴 프로세스를 시작합니다.

탈퇴 웹 페이지를 띄우고 탈퇴시 OnWithDraw() 이벤트를 수신합니다.

PlatformSupervisor.RefreshVerifyTokenAsync

async Task<string> RefreshVerifyTokenAsync()

게임 서버에 로그인에 필요한 loginVerifyToken을 구합니다.

플랫폼 로그인 연동으로 플랫폼과 게임 서버가 Verification을 통해서 연동된 상태이어야 합니다. 그렇지 않으면, 빈값을 리턴받는다.

Return

  • loginVerifyToken 문자열, NOT JSON 실패한 경우 String.Empty 가 전달된다.

PlatformSupervisor.RefreshVerifyTokenAsync().ContinueWith(task =>
{
    string verifyLoginToken = task.Result;
    Debug.Log($"Platform Login Refresh Token : {verifyLoginToken}");
});

웹뷰를 SDK에 연동하기

public interface IWebviewAgent
{
	void CloseWebview();
  	void OnWebviewClosed();  
	void OnShowWebview(string url);
	bool OnUrlChanged(string url)
	void OnReceiveMessage(string actionJson, Action<string> callback)
	void OnReceiveConsoleMessage(string source, int line, string message)
}

OnCloseWebview

void CloseWebview()

SDK에서 자체적으로 웹뷰를 닫아줄 때 호출되는 핸들러입니다.

OnWebviewClosed

웹뷰가 닫혔을 때 게임 구현측에서 호출해줘야 하는 함수입니다.

class MyWebview : IWebviewAgent
{
    // ...
    
    // 웹뷰를 닫아줍니다.
    public void Close()
    {
        // 코드 생략 ...
        
        // OnWebviewClosed 함수를 호출해줌.
        ((IWebviewAgent)this).OnWebviewClosed();
    }
    
    // ...
}

OnShowWebview

SDK에서 자체적으로 웹뷰를 통해 특정 URL 페이지를 보여주고자 할 때 호출하는 함수입니다.

OnUrlChanged

bool OnUrlChanged(string url)

웹뷰 URL이 변경될 때 SDK에 URL 정보를 전달해야합니다.

OnReceiveMessage

void OnReceiveMessage(string actionJson, Action<string> callback)

웹뷰에서 Unity로 이벤를 전송하는 경우 SDK에 정보를 전달해야합니다.

OnReceiveConsoleMessage

void OnReceiveConsoleMessage(string source, int line, string message)

웹뷰 콘솔 로그를 수신하는 경우 SDK에 정보를 전달해야합니다.

웹뷰 플러그인(vuplex) 연동(Windows)

URL : https://developer.vuplex.com/webview/overview 유료 플러그인으로 SDK 배포에 포함되지 않습니다. vuplex 웹뷰 라이선스 가이드 바로가기

웹뷰 인스턴스(prefab) 생성 후에 아래와 같이 SDK에 연동해야 합니다.

var webview = mainWebViewPrefab.WebView as IWebView;
if (webview != null)
{
    var Self = this;
    //3.1 URL 변경 이벤트 핸들러
    webview.UrlChanged += (sender, eventArgs) => {
        // 웹뷰 URL이 변경되는 경우
        if( ((IWebviewAgent)Self).OnUrlChanged(eventArgs.Url))
        {
            mainWebViewPrefab.Visible = false;
        }
    };

    //3.2 웹뷰 콘솔 로그 이벤트 핸들러
    // 웹뷰 console log를 WebviewAgent에게 전달한다. (옵션)
    webview.ConsoleMessageLogged += (sender, eventArgs) => {
        ((IWebviewAgent)Self).OnReceiveConsoleMessage(eventArgs.Source, eventArgs.Line, eventArgs.Message);
    };

    //3.3 웹뷰(JavaScript)에서 유니티로 이벤트 전달 시 호출되는 이벤트 핸들러
    //    WebviewAgent에게 수신한 데이터를 전달한다.
    webview.MessageEmitted += (sender, eventArgs) => {
        ((IWebviewAgent)Self).OnReceiveMessage(eventArgs.Val전ㅊue, (result) => 
        { 
            if (!string.IsNullOrEmpty(result))
            {
                (mainWebViewPrefab.WebView as IWebView)?.PostMessage(result);
            }
        });
    };
}

웹뷰 플러그인(Gree) 연동

URL :https://github.com/gree/unity-webview

SDK에 포함해서 배포됩니다.

웹뷰 인스턴스 생성 후에 아래와 같이 SDK에 연동해야 합니다. 아래는 gree webview 샘플에서 cb 파라미터에 적용한 예입니다.

webViewObject.Init(
  cb: (msg) =>
  {
      //JavaScript -> Unity 이벤트 전달
      var result = ActionDelegator.Instance.RunAction(msg);
      if (string.IsNullOrEmpty(result) == false)
      {
          webViewObject.EvaluateJS($"window.unityEventHandler({result})");
      }
  },

JavaScript에서 SDK로 전달하는 이벤트를 처리합니다.

웹뷰에서 SDK에서 제공하는 JavaScript 함수 호출 시 수신한 데이터를 SDK로 전달하고 결과를 웹뷰로 다시 리턴하는 기능입니다

전체 코드 예시)

public void ShowWebview(string url)
{
    webViewObject = (new GameObject("WebViewObject")).AddComponent<WebViewObject>();
    webViewObject.Init(
        cb: (msg) =>
        {
            //JavaScript -> Unity 이벤트 전달
            var result = ActionDelegator.Instance.RunAction(msg);
            if (string.IsNullOrEmpty(result) == false)
            {
                webViewObject.EvaluateJS($"window.unityEventHandler({result})");
            }
        },
        err: (msg) =>
        {
            HyDebug.Log(string.Format("CallOnError[{0}]", msg));
        },
        started: (msg) => { HyDebug.Log($"WebView Started : {msg}"); },
        hooked: (msg) => { HyDebug.Log($"WebView Hooked : {msg}"); },
        ld: (msg) =>
        {
            HyDebug.Log(string.Format("CallOnLoaded[{0}]", msg));
#if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX || UNITY_IOS
        // NOTE: the following js definition is required only for UIWebView; if
        // enabledWKWebView is true and runtime has WKWebView, Unity.call is defined
        // directly by the native plugin.
#if true
        var js = @"
            if (!(window.webkit && window.webkit.messageHandlers)) {
                window.Unity = {
                    call: function(msg) {
                        window.location = 'unity:' + msg;
                    }
                };
            }
        ";
#else
        // NOTE: depending on the situation, you might prefer this 'iframe' approach.
        // cf. <https://github.com/gree/unity-webview/issues/189>
        var js = @"
            if (!(window.webkit && window.webkit.messageHandlers)) {
                window.Unity = {
                    call: function(msg) {
                        var iframe = document.createElement('IFRAME');
                        iframe.setAttribute('src', 'unity:' + msg);
                        document.documentElement.appendChild(iframe);
                        iframe.parentNode.removeChild(iframe);
                        iframe = null;
                    }
                };
            }
        ";
#endif
#elif UNITY_WEBPLAYER || UNITY_WEBGL
        var js = @"
            window.Unity = {
                call:function(msg) {
                    parent.unityWebView.sendMessage('WebViewObject', msg);
                }
            };
        ";
#else
            var js = "";
#endif
        },
        enableWKWebView: true);
#if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX
webViewObject.bitmapRefreshCycle = 1;
#endif
    webViewObject.SetMargins(0, 0, 0, 0);
    webViewObject.SetVisibility(true);

    if (url.StartsWith("http"))
    {
        webViewObject.LoadURL(url.Replace(" ", "%20"));
    }
}
#endif
}

스팀 API

IsSteamOverlaySupport

static public bool IsSteamOverlaySupport()

스팀에서 실행되는 경우 스팀의 오버레이 기능이 활성화 되어 있는지 체크합니다.

스팀 결제 기능을 사용하기 위해서는 스팀앱에서 오버레이 기능이 활성화 되어 있어야 합니다.

결제 등 스팀 오버레이 기능이 필요한 경우 오버레이 활성화 상태를 조회하여 유저에게 사전 가이드하는 용도로 사용합니다.

GetSteamInfo

static public SteamInfo GetSteamInfo()

스팀 정보를 조회합니다.

public class SteamInfo
{
  public ulong Id;
  public string Language;
  public string Currency;
}
속성
용도
예시

Id

스팀 ID

Language

언어

ko

Currency

통화

KRW

마케팅 수신 동의 API

GetAgreementStatus

static async Task<AgreementPayload> GetAgreementStatus()

마케팅 수신 동의 정보를 조회합니다.

리턴

  • AgreementPayload 플랫폼에 등록된 약관 동의 결과

public class AgreementPayload
{
  public bool advertising;   // 마케팅 수신 동의
  public bool adPush;        // 앱 푸시 수신 동의
  public bool adNightPush;   // 야간 푸시 수신 동의
}

UpdateAgreements

async Task<AgreementPayload> UpdateAgreements(AgreementPayload agreementPayload )

유저로 부터 입력 받은 약관 동의 결과를 플랫폼에 전송합니다.

파라미터

  • AgreementPayload 유저에게 입력 받은 약관 동의 정보

리턴

  • AgreementPayload 플랫폼에 등록된 약관 동의 결과

마케팅 정보 동의(advertising) 속성이 false 로 되어있으면 푸시 수신 동의는 유저가 설정한 푸시(ad_push), 야간 수신(night_ad_push) 동의 정보에 관계없이 항상 false로 처리됩니다.

배너 API

GetBanners

async Task<HyResult<Banner[]>> PlatformSupervisor.GetBanners(string mappingId, string fallbackLanguage = null)

배너 구좌(mappingId)에 대한 배너 목록을 요청합니다.

Parameter
Description

mappingId

배너 구좌 ID (담당 기술 PM에게 문의)

fallbackLanguage

현재 사용중인 언어(SetClientLanguage로 설정된)에 대한 배너가 없을시 사용될 대체 언어 설정

public readonly struct BannerContentImageInfo
{
    public readonly string key;
    public readonly string url;
    public readonly int no;
}

public readonly struct BannerContent
{
    public readonly uint bannerContentId;
    public readonly string languageCode;
    public readonly string title;
    public readonly string subTitle;
    public readonly string landingType;
    public readonly string landingUrl;
    public readonly BannerContentImageInfo[] imageInfos;
}

public readonly struct Banner
{
    public readonly uint bannerId;
    public readonly uint bannerInfoId;
    public readonly string defaultLanguageCode;
    public readonly string[] platforms;
    public readonly ulong exposureStartAt;
    public readonly ulong? exposureEndAt;
    public readonly int? exposeOrder;
    public readonly ulong createdAt;
    public readonly ulong? updatedAt;
    public readonly BannerContent content;
}

Banner 객체의 주요 멤버는 다음과 같습니다.

title
배너 타이틀, 웹뷰 타이블 또는 별도 UI 구성시 타이틀 영역에 출력

exposureStartAt

배너 노출 시작 시간, unix UTC timestamp 클라이언트의 로컬 시간으로 변환한 후에 적용해야 합니다.

exposureEndAt

배너 노출 종료 시간, unix UTC timestamp 클라이언트의 로컬 시간으로 변환한 후에 적용해야 합니다.

content

배너에 대한 컨텐츠 정보를 담고있으며, 하위 정보는 아래와 같습니다.

  • imageInfos : 배너 이미지 URL

  • landingType

    • NONE

      • 설정안함

    • DEEPLINK

      • 딥링크

    • CURRENT_TAB

      • 현재창이동

    • NEW_TAB

      • 새창이동

  • landingUrl: 이미지 클릭시 이동되는 URL

게시판 API

string PlatformSupervisor.GetBoardUrl(string boardId)

통합CMS에서 설정한 게시판의 URL을 요청합니다.

boardId

담당 기술PM을 통해서 안내받으실 수 있습니다.

클라이언트 이벤트 로그 연동

PlatformSupervisor.SendEvent

유저 행동 로그 수집을 위해 클라이언트 사이드 이벤트 로그를 전송 합니다.

void SendEvent(Dictionary<string, object> clientEvent)
void SendEvent(Dictionary<string, object>[] clientEvents)

파라미터

  • clientEvent 단일 이벤트를 전송할 파리미터를 포함하는 Dictionary

  • clientEvents 여러개 이벤트를 전송할 파리미터를 포함하는 Dictionary 한번에 최대 100개 까지 전송할 수 있다. (권장하지는 않음)

적용 예)

var clientEvent = new Dictionary<string, object>()
{
    ["srl"] = "external_device_id",
    ["event_name"] = "00_060_FirstLogin",
    ["external_device_id"] = "deviceUniqueId",
    ["external_device_type"] = 0,
    ["service_id"] = "100200200"
};
PlatformSupervisor.SendEvent(clientEvent);

이벤트 및 파라미터 세부 스펙은 별도로 전달 드리는 로그 명세서를 참고하세요. log_type,os_type, cre_time은 SDK 에서 생성하여 전달합니다.

기타 API

PlatformSupervisor.GetLocationCode()

호출한 클라이언트의 국가 코드를 리턴 합니다. PlatformSupervisor 초기화 후에 호출 가능합니다.

리턴 : String

  private void OnStart()
  {
      string location = PlatformSupervisor.GetLocationCode();
      Log($"Location = {location}");
  }

PlatformSupervisor.GetUrl

string GetUrl(string urlType, string language)

인게임 사용하는 다양한 URL을 요청합니다.

urlType

URL 종류, 종류는 아래 표를 참고하세요.

language

게임 플레이 시 선택된 언어

URL 종류

SDK에서 미리 정의한 상수를 사용하세요.

용도
url 타입
SDK 정의 상수
설명

개인정보 처리방침

privacy_policy

HyString.PRIVACY_POLICY_URL

계정 센터(마이 페이지)

mypage

HyString.MYPAGE_URL

약관 보기

terms

HyString.TERMS_URL

고객센터

customer_center

HyString.CS_URL

커뮤니티

homepage

미정의

커뮤니티

한도 조회

payment_limit

미정의

계정 센터(한도 조회등)

일본 연령 확인

birth_required

미정의

연령 정보 등록하지 않은 일본 계정으로 PC에서 결제 진행하는 경우

쿠폰 등록

coupon

미정의

거래 내역

transaction_history

미정의

거래 내역 조회

string communityUrl = PlatformSupervisor.GetUrl("homepage", "ko"); // 커뮤니티

PlatformSupervisor.SetWritableStorageDir

bool SetWritableStorageDir(string dir)

SDK에서 로컬에 데이터를 저장할 경로를 설정한다.

언인스톨 시에 함께 삭제 될 수 있는 경로를 지정하는 것이 좋습니다.

dir

로컬 경로

리턴

  • 지정된 경로를 반영한 경우 true

PlatformSupervisor.SetWritableStorageDir(GetDownloadPath());

public static string GetDownloadPath()
    {
#if UNITY_EDITOR
        return $"{Application.dataPath}/../DownloadedAssetBundle";
#elif UNITY_STANDALONE
			return $"{LONGPATH_PREFIX}{Application.dataPath}/DownloadedAssetBundle";
#else
			return System.IO.Path.Combine(Application.persistentDataPath);
#endif
    }

PlatformSupervisor.ListenReturnToGameEvent

void ListenReturnToGameEvent(int timeoutSecond)

브라우저와 같은 외부 애플리케이션에서 게임 활성화 이벤트를 수신하는 기능을 제공합니다.

예를 들어) 외부 브라우저의 결제를 진행하고 게임으로 돌아오기 기능을 제공하는 경우, 브라우저에서 보내는 이벤트를 수신하기 위해서 호출합니다. 파라미터

  • timeoutSecond 이벤트 수신을 대기하는 최대 시간 타임 아웃 이후에 수신 되는 이벤트는 무시됩니다.

PlatformSupervisor.ShowReview

void ShowReview()

iOS, Android 에서 제공하는 리뷰 팝업이 노출됩니다. 각 OS 별 리뷰 팝업 정책은 아래를 참고하세요.

안드로이드 리뷰 정책 가이드

우수한 사용자 환경을 제공하기 위해 Google Play는 사용자에게 리뷰 대화 상자를 표시할 수 있는 빈도에 관한 시간 제한 할당량을 적용합니다. 이 할당량으로 인해 짧은 기간(예: 1개월 미만) launchReviewFlow 메서드를 두 번 이상 호출할 경우 대화 상자가 표시되지 않을 수도 있습니다.

참고: 구체적인 할당량 값은 구현 세부 정보이며 Google Play에서 예고 없이 변경할 수 있습니다.

IOS 리뷰 정책 가이드

SKStoreReviewController API를 사용하면 사용자가 손쉽게 앱에 대한 피드백을 제공할 수 있습니다. 1년에 최대 3번까지 평가를 요청할 수 있습니다. 사용자는 표준 프롬프트를 통해 평가를 제출하며 앱에서 나가지 않고도 리뷰를 작성하고 제출할 수 있습니다. 개발 모드에서 항상 팝업 됩니다.

안드로이드 앱 푸시 수신 동의 팝업 띄우기

설치 후 인게임에서 앱 푸시 수신 동의 팝업을 띄우기 위해서는

SDK 초기화 후에 다음과 같이 Permission을 확인해야 합니다.

아래는 샘플에 적용된 예시입니다.

private void Awake()
{
	PlatformSupervisor.Mount("dev").ContinueWithOnMainThread( task =>
	{
                -- 중 략 --
     CheckPushPermission();
	}
}

void CheckPushPermission()
{
  // 안드로이드 api level을 구한다.
  string androidInfo = SystemInfo.operatingSystem;
  int apiLevel = int.Parse(androidInfo.Substring(androidInfo.IndexOf("-") + 1, 2));
  Debug.Log("apiLevel: " + apiLevel);

  // 디바이스 api level이 33 이상이면 퍼미션 요청
  if (apiLevel >= 33 &&
      !Permission.HasUserAuthorizedPermission("android.permission.POST_NOTIFICATIONS"))
  {
      Permission.RequestUserPermission("android.permission.POST_NOTIFICATIONS");
  }
}`

약관 동의가 필요한 경우에 호출되는 Delegate입니다.

수신된 URL로 웹뷰를 띄웁니다.

iOS 푸시 설정

  • Unity-iPhone > General > Frameworks, libraries, And Embedded contents > [+]

    • UserNotifications.framework

    • UserNotificationsUI.framework

  • Unity-iPhone > Signing & Capabilities > 상단 라이브러리 추가 [+] 버튼

    • Push notification 추가

    • Background Modes

  • Unity-iPhone > Signing & Capabilities > Background Modes 선택

    • Remote notifications 체크

게스트 계정의 정회원 전환

게스트 로그인 수단으로 가입된 계정을 다른 인증 수단을 사용하는 정회원 계정으로 전환합니다.

정회원 전환은 오직 게스트 로그인 유저만 할 수 있으며, 그 외의 로그인 상태에서 API 호출시 실패를 리턴합니다.

정회원 전환이 성공적으로 완료되면 기존 게스트 로그인 수단은 IMID와 연결이 끊어지며 연동한 로그인 수단으로만 로그인 할 수 있습니다.

게스트 계정으로 다시 로그인을 시도할 경우 새로운 계정을 생성하는 과정을 수행하게 됩니다.

정회원 전환 API

Task<ConvertMemberResult> PlatformSupervisor.ConvertMember(SigninMethod method, UserBirthDay userBirthDay)

정회원 전환을 시작합니다.

로그인과 동일하게 웹뷰나 네이티브 인증 수단을 통한 유저 인증이 과정에 포함됩니다.

작업이 끝나면 ConvertMemberResult인스턴스를 리턴합니다.

struct ConvertMemberResult
{
    public readonly bool successful;        // 정회원 전환 성공 여부
    public readonly string errorMessage;    // 실패시 애러 메시지
    public readonly string resultCode;      // 결과 코드
    public readonly string countryCode;     // 가입시점의 국가 코드 (ex. KR, JP 등)
}

유저의 생일 정보 입력 요청

Task<string> PlatformSupervisor.ShowRequireGuestBirth()

게스트 유저의 경우 HYBE 플랫폼에서 연령 정보를 관리하지 않습니다. 따라서 인앱결제 기능을 사용하기 전에 유저로부터 연령 정보를 받기위해 해당 API를 사용합니다. 게스트 유저가 아닌 경우 JAPANESE_DATE_BIRTH_REQUIRED 응답 코드에 대해서만 처리해주면 됩니다.

웹뷰를 통해서 유저의 연령정보를 입력받을 수 있는 폼을 실행합니다. 실행이 완료되면 string (YYYYMMDD) 형태로 유저의 생일 값을 리턴합니다.

로그인 태그

유저의 마지막 로그인 정보를 담는 태그를 조회합니다. PlatformSupervisor.Mount가 완료된 이후에 사용 가능합니다.

SignInTag? PlatformSupervisor.GetLastSignInTag()
public struct SignInTag
{
    // 유저의 이메일 데이터입니다. 일부 Method(GUEST 등)의 경우 이메일이 비어있을 수 있습니다.
    public string MaskedEmail { get; }
    
    // 로그인 수단 데이터입니다.
    public string Method { get; }

    
    public SigninMethod MethodEnum { get; }
}

통합

Android 빌드하기

  • Project Settings > Other Settings

    • Scripting Backend : IL2CPP

  • Project Settings > Publishing Settings

    • Custom Keystore : Keystore Manager로 생성한 Keystore 정보 입력

  • Assert/google-services.json 파일 확인

iOS 빌드하기

  • Project Settings > Other Settings

    • Identification > bundle Identifier : Apple Developer Center에서 등록시 사용한 번들 ID

  • Assert/GoogleService-Info.plist 파일 확인

  • Cocodpads 설치

    • iOS Resolver 가 자동 설치합니다.

    • 설치 과정에서 오류가 발생한 경우

      • Ruby를 최신 버전으로 설치합니다.

      • 아래 커맨드를 실행 한 후 리부팅 합니다.

        sudo gem install -n /usr/local/bin cocoapods
  • pod install

    • XCode 빌드시 사용하는 firebase 소스를 설치하는 과정입니다.

    • 아래 커맨드를 실행합니다.

      pod install
      # 또는
      arch -arm64 pod install  (Macbook M1/M2 Silicon)
  • Unity-iPhone > Signing & Capabilities > 상단 라이브러리 추가 [+] 버튼

    • Sign in with Apple 추가

    • In-App Purchase 추가

    • Push Notifications 추가

  • Unity-iPhone > Build Settings > Build Options > Enable Bitcode : No 설정

  • UnityFramework > Build Settings > Build Options > Enable Bitcode : No 설정

iOS 빌드 및 실행 Troubleshooting

[FirebaseAnalytics][I-ACS800023] No pending snapshot to activate. SDK name: app_measurement 2023-05-17 23:57:28.218191+0900 PlayHybe[8477:1312194] 9.6.0 - [FirebaseAnalytics][I-ACS023012] Analytics collection enabled To disable automatic screen reporting, set the flag FirebaseAutomaticScreenReportingEnabled to NO (boolean) in the Info.plist

Info.plist 를 선택하고 FirebaseAutomaticScreenReportingEnabled를 추가한 후 NO를 선택합니다.

Unity-iPhone.xcodeproj Signing for "Unity-iPhone" requires a development team. Select a development team in the Signing & Capabilities editor.

Unity-iPhone > Signing & Capabilities 에서 인증 정보를 입력합니다.

설치된 앱에서 Apple 로그인 실행시 로그인 창이 나오지 않고 에러가 발생한 경우

Sign in with Apple 라이브러리를 추가하지 않는 경우입니다.

Unity-iPhone > Signing & Capabilities > 상단 라이브러리 추가 [+] 버튼 > Sign in with Apple 추가

링크에러 Undefined symbol: _FIRAuthErrorUserInfoUpdatedCredentialKey

M1, M2 맥북인 경우에 x86 라이브러리가 설치 되어 발생한다.

arch -arm64 pod install

계속해서 에러가 발생하는 경우

sudo arch -arm64 gem install ffi
arch -arm64 pod install

x86 라이브러리가 설치된 경우 unstall로 삭제한 후 진행한다.

sudo arch -arm64 gem uninstall ffi

IOS 구글/LINE 로그인 창 정보 입력 후 진행이 안되는 경우

Custom URL Schema 를 설정하는 않는 경우 로그인 진행이 되지 않습니다. 설정 가이드를 참고하세요.

Last updated