[C#] Nancy를 사용하여 간단한 Restful Web Hosting 시작하기

게임 서버 관리툴을 만들기 위해서 어떠한 방식이 좋을까 고민하다가 각 머신에 restful web server를 설치해서 특정 명령어를 받아서 처리하도록 하면 되겠다 싶어서 검색해보니 Nancy라는 라이브러리가 있습니다.

아주 간단하게 Resful Web API를 구성할 수 있도록 만들어져 있습니다.

우선 Visual Studio Nuget package manager에서 Nancy.SelfHosting을 설치합니다.

그리고 아래의 코드에서 확장을 시작할 수 있습니다.

using Nancy;
using Nancy.Hosting.Self;
using System;

namespace NancyTest
{
    public class MainModule : NancyModule
    {
        public MainModule() {
            Get["/"] = x => { return "Hello World"; };
            Post["/config"] = x => {
                return 200;
            };
        }
    }

    class Program
    {
        static void Main(string[] args) {
            var hostConfigs = new HostConfiguration {
                UrlReservations = new UrlReservations() { CreateAutomatically = true }
            };
            Uri uri = new Uri("http://localhost:1234");
            using (var host = new NancyHost(hostConfigs, uri)) {
                host.Start();
                Console.WriteLine("http://localhost:1234 hosting started!");
                Console.ReadLine();
            }
        }
    }
}

 

[Firebase] GooglePlay 로그인 실패. the Google id_token is not allowed to be used with this application.

Firebase를 사용한 GooglePlay 인증을 사용하던 중 어느날 갑자기 로그인 실패 오류가 발생하기 시작했습니다.

아무리 검색해 봐도 원인을 파악하기가 힘들어 Firebase Support에 문의를 해보니 다행히 문제를 해결할 수 있었습니다.

문제의 원인은 Firebase Project와 Google Project가 제대로 일치하지 않아서 발생하는 문제였습니다. 그동안은 어째서 잘 동작해왔는지가 오히려 의문스러운 원인...

해결 방법은 아래와 같습니다.

  1. FirebaseConsole로 이동합니다.
  2. 메뉴에서 Authentication -> 로그인방법 -> Google 을 선택합니다.

  3. 외부 프로젝트의 클라이언트 ID 허용(선택사항) 부분에 GooglePlay 인증에 사용한 OAuth 2.0 ClientID를 입력 후 추가해 줍니다.

 

이것으로 문제의 해결이 가능합니다.

잘 되다가 갑자기 문제가 발생한 부분에 대해서는 추가 문의후 기록을 남길 예정.

[Unity3D] Google Play Games Plugin에서 ERROR_NOT_AUTHORIZED 에러가 발생할 때

Google Play Games Plugin을 Unity에 붙이고 로그인을 시도하면 ERROR_NOT_AUTHORIZED 에러가 발생하면서 로그인이 안되는 경우가 있습니다.

이 문제는 Google Play Console의 설정을 제대로 하지 않은 경우게 발생합니다.

문제 해결을 위해서 두가지를 확인해야 합니다.

첫번째는 Unity에서 GPGS의 설정입니다.

  1. Unity에서 <Window-Google Play Games-Setup-Android setup...> 메뉴를 선택합니다.

  2. 아래와 같은 창이 뜹니다. 이 창의 항목들을 설정해 줘야 합니다.

  3. Directory to save constant, Constants class name은 적당하게 입력해 줍니다.
    Directory to save constant : Resource Definition 에 정의된 값들을 저장한 C# 파일을 생성할 폴더 위치
    Constants class name : Resource Definition에 정의된 값들을 저장한 C# Class의 이름
  4. Resources Definition은 Google Play Console에서 가져옵니다.
    업적, 이벤트 중 하무거나 하나 추가하고나면 '리소스 받기' 메뉴가 나타납니다. 업적과 이벤트를 하나도 추가하지 않고 받아올 수도 있을텐데 버튼이 등장하지 않네요.

  5. Web App Client ID는 입력을 해도 되고 안해도 되는 부분인데 Firebase나 외부 로그인 모듈을 사용하려면 입력해 줍니다.

두번째는 Google Play Console의 설정입니다.

  1. Google Play Console API 사이트에 접속합니다.
    https://console.developers.google.com
  2. OAuth 2.0 클라이언트 ID에서 Android 클라이언트 정보가 있는지 확인해 봅니다.
    (아마 별다른 셋팅이 없었다면 없을 겁니다.)

  3. '사용자 인증 정보 만들기' 를 클릭하고 'OAuth 클라이언트 ID'를 선택합니다.

  4. 아래와 같은 화면이 있고 '서명 인증서 지문' 과 '패키지 이름'을 입력해야 합니다.

  5. Google Play Console의 프로젝트에서 SHA-1 인증서 지문을 복사하여 4번 항목의 '서명 인증서 지문' 부분에 붙여넣습니다.

    만약 인증서를 업로드 하라거나 어쩌구 메시지가 뜨면 APK를 빌드할 때 사용한 key store를 등록해야 합니다. 관련 정보는 해당 메뉴의 도움말을 참고하세요.
    업로드 인증서를 실수로 입력하는 경우가 많으니 주의!

4번 항목의 '패키지 이름'은 Unity에서 APK를 빌드할 때 사용한 것을 넣어줍니다.

위의 두가지가 조금이라도 잘못 설정되어 있으면 로그인이 제대로 안됩니다.

[Unity3D] Google Play Games Plugin에서 ERROR_NOT_AUTHORIZED 오류로 로그인 실패 또는 IdToken 받아오기 실패

Unity에서 Google 로그인을 구현하기 위해서는 Google Play Games Service Plugin(gpgs)을 사용해야 합니다.

저는 Firebase를 통해서 Google Play, Facebook, Guest 로그인을 구현하는 과정이었고, Firebase에서 Google Play 인증을 위해서는 Google Play에서 IdToken을 받아서 Firebase 인증 모듈에 전달해줘야 합니다.

처음 만난 문제는 gpgs에서 로그인은 성공하여 Social.localUser.id 정보는 들어 있지만 IdToken, Email, ServerAuthCode 등의 정보는 비어있어서 Firebase에 인증 정보를 넘길 수 없었습니다.

이때의 gpgs 초기화 코드는 아래의 상태였습니다.

// GPG를 Activate()하면 Social.localUser가 GPG의 계정 정보로 설정됨
// 안드로이드 빌더 초기화
PlayGamesClientConfiguration config = new PlayGamesClientConfiguration.Builder()
    .RequestServerAuthCode(false)
    .RequestIdToken()
    .RequestEmail()
    .Build();

PlayGamesPlatform.InitializeInstance(config);

// 구글 플레이 로그를 확인할려면 활성화
PlayGamesPlatform.DebugLogEnabled = true;

// 구글 플레이 활성화
PlayGamesPlatform.Activate();

분명히 config를 통해서 RequestIdToken()을 호출하여 요청을 추가하였음에도 불구하고 IdToken 항목이 비어있었습니다.

Unity Log를 확인한 것으로는 원인을 찾을 수 없었고, Android Studio의 Logcat으로 디바이스 로그를 확인하던 중 이상한 부분을 발견할 수 있었습니다.

06-11 22:50:17.497 7610-7663/? I/Unity: Try google play login
06-11 22:50:17.510 7610-7663/? I/Unity: Starting Auth with token client.
06-11 22:50:17.563 7610-7663/? W/Unity: !!! [Play Games Plugin DLL] 06/11/18 22:50:17 +09:00 WARNING: Creating new PlayGamesPlatform
 
 (Filename: /Users/builduser/buildslave/unity/build/artifacts/generated/common/runtime/DebugBindings.gen.cpp Line: 51)
06-11 22:50:17.564 7610-7663/? I/Unity: [Play Games Plugin DLL] 06/11/18 22:50:17 +09:00 DEBUG: Activating PlayGamesPlatform.
06-11 22:50:17.565 7610-7663/? I/Unity: [Play Games Plugin DLL] 06/11/18 22:50:17 +09:00 DEBUG: PlayGamesPlatform activated: GooglePlayGames.PlayGamesPlatform
06-11 22:50:17.566 7610-7663/? I/Unity: [Play Games Plugin DLL] 06/11/18 22:50:17 +09:00 DEBUG: Activating PlayGamesPlatform.
06-11 22:50:17.567 7610-7663/? I/Unity: [Play Games Plugin DLL] 06/11/18 22:50:17 +09:00 DEBUG: PlayGamesPlatform activated: GooglePlayGames.PlayGamesPlatform
06-11 22:50:17.568 7610-7663/? I/Unity: [Play Games Plugin DLL] 06/11/18 22:50:17 +09:00 DEBUG: Creating platform-specific Play Games client.
 [Play Games Plugin DLL] 06/11/18 22:50:17 +09:00 DEBUG: Creating Android IPlayGamesClient Client
06-11 22:50:17.578 7610-7663/? D/TokenFragment: Creating fragment
06-11 22:50:17.579 7610-7610/? D/TokenFragment: onStart()
06-11 22:50:17.585 7610-7610/? D/TokenFragment: onResume called
 Building client for: a98c718 (a:false e:true i:true wc: 619017498880-4eeh5dlhl8jso58368gv4tf0s2qs4s8i.apps.googleusercontent.com f: false)
06-11 22:50:17.587 7610-7663/? I/Unity: ---- [0] -- 105
06-11 22:50:17.592 7610-7610/? W/PopupManager: You have not specified a View to use as content view for popups. Falling back to the Activity content view. Note that this may not work as expected in multi-screen environments
06-11 22:50:17.617 5637-6375/? D/[WeatherGearO(220318052351)]: {[EF07ED23AAA1263A1FC0BD061AAAD81CFEF15A971ABD51417EE09B7660DD4FB818A9462C7397822725FFF2738B19ADA7]}
06-11 22:50:17.648 7610-7610/? D/TokenFragment: No connected Games API
06-11 22:50:17.649 7610-7610/? E/TokenFragment: Setting result error code to: 13
06-11 22:50:17.653 5637-5637/? D/[WeatherGearO(220318052351)]: {[20CE3D41AD5C8B99E86585ABAB0BF03E702BEB2FC2CA5F53D66FB562B77F4529B627A611ACF593EFCAECBBA4E800B8A9081BC429F8CCD72700680F6A1D6A48CC]}
06-11 22:50:17.657 5637-5637/? D/[WeatherGearO(220318052351)]: {[E5B16E2CDC4F169AEF5B4319C5BDF7110156A5C36B5B4FD8C066ADFAD237FF3B8D85C1771AE8244AE78CE8BB9C6079741D01C71F84AB90238AB7DED8E9D360BC]}
06-11 22:50:17.658 5637-5637/? D/[WeatherGearO(220318052351)]: {[E5B16E2CDC4F169AEF5B4319C5BDF711320D5E9C4351D1F5E6CB8FF1DF59CF2C64BE1F0F10EBA2467C1DD93AB2A27A40A65FAEFDFFB43F75B64AAEDA7C3A5B59]}
06-11 22:50:17.659 5637-5637/? D/[WeatherGearO(220318052351)]: {[20CE3D41AD5C8B99E86585ABAB0BF03EE5160ED4AAE0971C0D182570D628C6CD0253855F5B1B3CDBA2912A6CEF37A6C4]}
06-11 22:50:17.668 5637-5637/? D/[WeatherGearO(220318052351)]: {[20CE3D41AD5C8B99E86585ABAB0BF03E856D7DF2593883BBCF72D0E06237841289C8E379B2D1A1A78B856DF6D06ACDC0]}
06-11 22:50:17.672 5637-5637/? D/[SA_SDK]SAAgent: SAAgent - onDestroy:SAWeather_Service
06-11 22:50:17.673 5637-6370/? W/[SA_SDK]SAAgent: Performing agent cleanup
06-11 22:50:17.673 5637-6370/? I/[SA_SDK]SASocket: Connection is already closed
06-11 22:50:17.675 5637-5637/? D/[WeatherGearO(220318052351)]: {[EF07ED23AAA1263A1FC0BD061AAAD81CA3F446FA4E808076CF16D0F746E839D242804AFF8476C203988BABCD46197438]}
06-11 22:50:17.676 5637-6370/? I/[SA_SDK]SAAgent: Agent ID retrieved successfully for com.samsung.accessory.saweather.service.SAWeather_Service Agent ID:37723
06-11 22:50:17.676 5909-5947/? I/SAFrameworkConnection: Clean up fwk connection agentId:37723 com.samsung.android.gearoplugin
06-11 22:50:17.680 5909-6078/? V/SAFrameworkConnection: Removed incremental update callback for:/system/weather2_0
06-11 22:50:17.680 5637-6370/? D/[SA_SDK]SAAdapter: Agent callback removed. Current size - 10
06-11 22:50:17.685 7610-7610/? D/TokenPendingResult: Calling onResult for callback: GooglePlayGames.Android.TokenResultCallback result: Status: Status{statusCode=ERROR, resolution=null} email: <null> id:<null> access: <null>
06-11 22:50:17.708 5173-30288/? I/AuthChimeraService: Executing send connection operation
06-11 22:50:17.715 5173-28166/? W/FirebaseAuth: [PhoneNumberAuthPostProcessor] postProcess starts
 [PhoneNumberAuthPostProcessor] postProcess ends
06-11 22:50:17.716 7610-7858/? D/FirebaseAuth: Notifying id token listeners about user ( tY2DUCs391aFgwIVLufabvlvSwP2 ).
06-11 22:50:17.732 7610-7610/? D/GamesUnitySDK: Performing Android initialization of the GPG SDK
06-11 22:50:17.771 7610-7610/? I/Unity: Building GPG services, implicitly attempts silent auth
06-11 22:50:17.773 7610-7610/? I/GamesNativeSDK: Using existing jar.
06-11 22:50:17.776 7610-7610/? I/GamesNativeSDK: Writing 1941 bytes to jar file
06-11 22:50:17.779 7610-7610/? W/zygote: Skipping duplicate class check due to unrecognized classloader
06-11 22:50:17.784 7610-7610/? I/GamesNativeSDK: Using existing jar.
 Writing 1066 bytes to jar file
06-11 22:50:17.787 7610-7610/? W/zygote: Skipping duplicate class check due to unrecognized classloader
06-11 22:50:17.793 7610-7610/? W/PopupManager: You have not specified a View to use as content view for popups. Falling back to the Activity content view. Note that this may not work as expected in multi-screen environments
06-11 22:50:17.794 7610-7897/? I/GamesNativeSDK: Auth operation started: SIGN IN
 Connecting to Google Play...
06-11 22:50:17.814 7610-7663/? I/Unity: [Play Games Plugin DLL] 06/11/18 22:50:17 +09:00 DEBUG: Starting Auth Transition. Op: SIGN_IN status: 13
06-11 22:50:17.815 7610-7610/? D/TokenFragment: Done with processRequest, result is pending.
06-11 22:50:17.815 7610-7663/? I/Unity: [Play Games Plugin DLL] 06/11/18 22:50:17 +09:00 DEBUG: Invoking callbacks, AuthState changed from silentPending to Unauthenticated.
06-11 22:50:17.816 7610-7610/? D/FirebaseApp: Notifying auth state listeners.
 Notified 0 auth state listeners.
06-11 22:50:17.850 5173-10655/? W/GamesServiceBroker: Client connected with SDK 12211000, Services 12685025, and Games 59040048
06-11 22:50:17.850 5173-5886/? W/GamesServiceBroker: Client connected with SDK 12211000, Services 12685025, and Games 59040048
06-11 22:50:17.861 7610-7663/? I/Unity: [Play Games Plugin DLL] 06/11/18 22:50:17 +09:00 DEBUG: there are pending auth callbacks - starting AuthUI
06-11 22:50:17.880 7610-7663/? I/Unity: Token[0:8] = eyJhbGci
06-11 22:50:17.909 5173-3007/? W/GamesServiceBroker: Client connected with SDK 13004000, Services 12685025, and Games 59040048
06-11 22:50:17.974 5173-7898/? I/AsyncOpDispatcher: 44-AuthAccountWithNoServerAuthCallback
06-11 22:50:18.085 5112-8279/? I/System.out: (HTTPLog)-Static: isSBSettingEnabled false
06-11 22:50:18.181 3254-3254/? I/android.hardware.wifi@1.0-service: getLinkLayerStats
06-11 22:50:18.200 3788-3811/? D/StorageManagerService: getExternalStorageMountMode : 2
06-11 22:50:18.201 3788-3811/? D/StorageManagerService: getExternalStorageMountMode : 3
06-11 22:50:18.208 3788-3811/? D/StorageManagerService: getExternalStorageMountMode : final mountMode=2, uid : 10220, packageName : com.skt.prod.phonebook
06-11 22:50:18.217 3788-3811/? I/ApplicationPolicy: isApplicationExternalStorageWhitelisted:com.skt.prod.phonebook user:0
06-11 22:50:18.217 3788-3811/? D/ApplicationPolicy: isApplicationExternalStorageWhitelisted: DO is not enabled on user 0. Allowed.
06-11 22:50:18.217 3788-3811/? D/ActivityManager: package com.skt.prod.phonebook, user - 0 is SDcard whitelisted
06-11 22:50:18.217 3788-3811/? I/ApplicationPolicy: isApplicationExternalStorageBlacklisted:com.skt.prod.phonebook user:0
06-11 22:50:18.217 3788-3811/? D/ApplicationPolicy: isApplicationExternalStorageBlacklisted: DO is not enabled on user 0. Allowed.
06-11 22:50:18.241 5112-8279/? W/Auth: [GetToken] GetToken failed with status code: NeedPermission
06-11 22:50:18.257 3788-3811/? W/ActivityManager: Slow operation: 60ms so far, now at startProcess: returned from zygote!
 Slow operation: 60ms so far, now at startProcess: done updating battery stats
06-11 22:50:18.258 3788-3811/? W/ActivityManager: Slow operation: 60ms so far, now at startProcess: building log message
06-11 22:50:18.258 3788-3811/? I/ActivityManager: Start proc 7899:com.skt.prod.phonebook/u0a220 for service com.skt.prod.phonebook/.sync.SyncManagerService
06-11 22:50:18.258 3788-3811/? W/ActivityManager: Slow operation: 61ms so far, now at startProcess: starting to update pids map
 Slow operation: 61ms so far, now at startProcess: done updating pids map
 Slow operation: 63ms so far, now at startProcess: done starting proc!
06-11 22:50:18.260 7899-7899/? E/Zygote: isWhitelistProcess - Process is Whitelisted
06-11 22:50:18.273 7899-7899/? W/SELinux: SELinux selinux_android_compute_policy_index : Policy Index[2], Con:u:r:zygote:s0 RAM:SEPF_SM-G950N_8.0.0_0005, [-1 -1 -1 -1 0 1]
06-11 22:50:18.276 7899-7899/? I/SELinux: SELinux: seapp_context_lookup: seinfo=trustonicpartner, level=s0:c512,c768, pkgname=com.skt.prod.phonebook 
06-11 22:50:18.301 5173-7321/? W/Auth: [GoogleAuthUtil] GoogleAuthUtil
06-11 22:50:18.326 5173-3007/? W/GamesServiceBroker: Client connected with SDK 13004000, Services 12685025, and Games 59040048
06-11 22:50:18.330 7610-7610/? I/TokenFragment: onConnected called
06-11 22:50:18.339 3788-4468/? I/ClientCertificateManager Service: fixContextInfoForMP() returning Caller uid: 10220 ,Container id: 0
 fixContextInfoForMP() returning Caller uid: 10220 ,Container id: 0
 ClientCertificateManager.isPremiumContainer() : false for user : 0
06-11 22:50:18.341 5173-3007/? W/GamesServiceBroker: Client connected with SDK 13004000, Services 12685025, and Games 59040048
06-11 22:50:18.355 3788-4622/? I/ClientCertificateManager Service: fixContextInfoForMP() returning Caller uid: 10220 ,Container id: 0
06-11 22:50:18.356 3788-4622/? I/ClientCertificateManager Service: fixContextInfoForMP() returning Caller uid: 10220 ,Container id: 0
 ClientCertificateManager.isPremiumContainer() : false for user : 0
06-11 22:50:18.371 7899-7899/? D/ActivityThread: Added TimaKeyStore provider
06-11 22:50:18.372 5173-7898/? I/AsyncOpDispatcher: 44-AuthAccountWithNoServerAuthCallback
06-11 22:50:18.375 3788-4323/? I/ActivityManager: DSS on for com.skt.prod.phonebook and scale is 1.0
06-11 22:50:18.457 3788-4323/? W/AppOps: Bad call: specified package com.google.android.play.games under uid 10382 but it is really 10250
 java.lang.RuntimeException: here
 at com.android.server.AppOpsService.getOpsRawLocked(AppOpsService.java:1402)
 at com.android.server.AppOpsService.checkPackage(AppOpsService.java:1106)
 at com.android.internal.app.IAppOpsService$Stub.onTransact(IAppOpsService.java:169)
 at android.os.Binder.execTransact(Binder.java:682)
06-11 22:50:18.487 7899-7916/? I/vndksupport: sphal namespace is not configured for this process. Loading /vendor/lib/egl/libGLES_mali.so from the current namespace instead.
06-11 22:50:18.525 5173-3007/? W/GamesServiceBroker: Client connected with SDK 13004000, Services 12685025, and Games 59040048
06-11 22:50:18.528 7899-7899/? D/FirebaseApp: com.google.firebase.auth.FirebaseAuth is not linked. Skipping initialization.
06-11 22:50:18.544 7899-7899/? D/FirebaseApp: com.google.firebase.crash.FirebaseCrash is not linked. Skipping initialization.
06-11 22:50:18.551 7899-7916/? D/libEGL: loaded /vendor/lib/egl/libGLES_mali.so
06-11 22:50:18.557 7899-7899/? I/FA: App measurement is starting up, version: 11020
 To enable debug logging run: adb shell setprop log.tag.FA VERBOSE
06-11 22:50:18.571 7610-7610/? V/GamesNativeSDK: Play Games callback indicates connection.
06-11 22:50:18.593 7610-7897/? I/GamesNativeSDK: Successfully connected to Google Play.
06-11 22:50:18.598 7899-7899/? I/FA: To enable faster debug mode event logging run:
 adb shell setprop debug.firebase.analytics.app com.skt.prod.phonebook
06-11 22:50:18.604 3788-4323/? D/SamsungAlarmManager: Cancel Alarm calling from uid:10220 pid :7899 / op:PendingIntent{bddad2c: PendingIntentRecord{42e53f5 com.skt.prod.phonebook broadcastIntent}}
06-11 22:50:18.611 7899-7899/? I/FirebaseInitProvider: FirebaseApp initialization successful
06-11 22:50:18.619 7610-7663/? I/Unity: [Play Games Plugin DLL] 06/11/18 22:50:18 +09:00 DEBUG: Starting Auth Transition. Op: SIGN_IN status: VALID
06-11 22:50:18.632 5173-10310/? I/System.out: (HTTPLog)-Static: isSBSettingEnabled false
06-11 22:50:18.664 3788-4468/? D/ConnectivityService: filterNetworkStateForUid() uid: 10220 networkInfo: [type: WIFI[] - WIFI, state: CONNECTED/CONNECTED, reason: (unspecified), extra: "starter_5G", failover: false, available: true, roaming: false, metered: false]
06-11 22:50:18.674 3788-4468/? W/StorageManager: getStorageLowBytes lowPercent : 5, lowBytes : 2913012121, maxLowBytes : 524288000
06-11 22:50:18.679 3788-5348/? W/AppOps: Bad call: specified package com.google.android.play.games under uid 10382 but it is really 10250
 java.lang.RuntimeException: here
 at com.android.server.AppOpsService.getOpsRawLocked(AppOpsService.java:1402)
 at com.android.server.AppOpsService.checkPackage(AppOpsService.java:1106)
 at com.android.internal.app.IAppOpsService$Stub.onTransact(IAppOpsService.java:169)
 at android.os.Binder.execTransact(Binder.java:682)
06-11 22:50:18.680 3788-4468/? W/StorageManager: getStorageLowBytes lowPercent : 5, lowBytes : 2913012121, maxLowBytes : 524288000
06-11 22:50:18.681 7610-7663/? I/Unity: [Play Games Plugin DLL] 06/11/18 22:50:18 +09:00 DEBUG: Entering internal callback for PlayerManager#InternalFetchSelfCallback
06-11 22:50:18.682 3788-4468/? W/AppOps: Bad call: specified package com.google.android.play.games under uid 10382 but it is really 10250
 java.lang.RuntimeException: here
 at com.android.server.AppOpsService.getOpsRawLocked(AppOpsService.java:1402)
 at com.android.server.AppOpsService.checkPackage(AppOpsService.java:1106)
 at com.android.internal.app.IAppOpsService$Stub.onTransact(IAppOpsService.java:169)
 at android.os.Binder.execTransact(Binder.java:682)
06-11 22:50:18.682 7610-7663/? I/Unity: [Play Games Plugin DLL] 06/11/18 22:50:18 +09:00 DEBUG: Populating User
06-11 22:50:18.687 3788-4468/? W/StorageManager: getStorageLowBytes lowPercent : 5, lowBytes : 2913012121, maxLowBytes : 524288000
06-11 22:50:18.691 3788-4468/? W/StorageManager: getStorageLowBytes lowPercent : 5, lowBytes : 2913012121, maxLowBytes : 524288000
06-11 22:50:18.696 3788-4468/? W/AppOps: Bad call: specified package com.google.android.play.games under uid 10382 but it is really 10250
 java.lang.RuntimeException: here
 at com.android.server.AppOpsService.getOpsRawLocked(AppOpsService.java:1402)
 at com.android.server.AppOpsService.checkPackage(AppOpsService.java:1106)
 at com.android.internal.app.IAppOpsService$Stub.onTransact(IAppOpsService.java:169)
 at android.os.Binder.execTransact(Binder.java:682)
06-11 22:50:18.713 7610-7663/? I/Unity: [Play Games Plugin DLL] 06/11/18 22:50:18 +09:00 DEBUG: Found User: [Player: 'PlayerID' (id g44786123847612328794)]
06-11 22:50:18.714 7610-7663/? I/Unity: [Play Games Plugin DLL] 06/11/18 22:50:18 +09:00 DEBUG: Maybe finish for User
06-11 22:50:18.714 3788-4468/? W/StorageManager: getStorageLowBytes lowPercent : 5, lowBytes : 2913012121, maxLowBytes : 524288000
06-11 22:50:18.715 7610-7663/? I/Unity: [Play Games Plugin DLL] 06/11/18 22:50:18 +09:00 DEBUG: Auth not finished. User=[Player: 'PlayerID' (id g44786123847612328794)] achievements=
06-11 22:50:18.719 3788-5348/? W/AppOps: Bad call: specified package com.google.android.play.games under uid 10382 but it is really 10250
 java.lang.RuntimeException: here
 at com.android.server.AppOpsService.getOpsRawLocked(AppOpsService.java:1402)
 at com.android.server.AppOpsService.checkPackage(AppOpsService.java:1106)
 at com.android.internal.app.IAppOpsService$Stub.onTransact(IAppOpsService.java:169)
 at android.os.Binder.execTransact(Binder.java:682)
06-11 22:50:18.720 3788-4468/? W/AppOps: Bad call: specified package com.google.android.play.games under uid 10382 but it is really 10250
 java.lang.RuntimeException: here
 at com.android.server.AppOpsService.getOpsRawLocked(AppOpsService.java:1402)
 at com.android.server.AppOpsService.checkPackage(AppOpsService.java:1106)
 at com.android.internal.app.IAppOpsService$Stub.onTransact(IAppOpsService.java:169)
 at android.os.Binder.execTransact(Binder.java:682)
06-11 22:50:18.748 7610-7663/? I/Unity: [Play Games Plugin DLL] 06/11/18 22:50:18 +09:00 DEBUG: Entering internal callback for AchievementManager#InternalFetchAllCallback
06-11 22:50:18.749 7610-7663/? I/Unity: [Play Games Plugin DLL] 06/11/18 22:50:18 +09:00 DEBUG: Populating Achievements, status = VALID
06-11 22:50:18.793 7899-7899/? W/Notification: Use of stream types is deprecated for operations other than volume control
 See the documentation of setSound() for what to use instead with android.media.AudioAttributes to qualify your playback use case
06-11 22:50:18.814 7610-7663/? I/Unity: [Play Games Plugin DLL] 06/11/18 22:50:18 +09:00 DEBUG: Found 1 Achievements
06-11 22:50:18.815 7610-7663/? I/Unity: [Play Games Plugin DLL] 06/11/18 22:50:18 +09:00 DEBUG: Maybe finish for Achievements
06-11 22:50:18.816 7610-7663/? I/Unity: [Play Games Plugin DLL] 06/11/18 22:50:18 +09:00 DEBUG: Auth finished. Proceeding.
06-11 22:50:18.817 7610-7663/? I/Unity: [Play Games Plugin DLL] 06/11/18 22:50:18 +09:00 DEBUG: Invoking Callbacks: System.Action`2[System.Boolean,System.String]
06-11 22:50:18.820 7610-7663/? I/Unity: Gpgs authenticate success.

위의 로그에서 아래의 한줄을 발견할 수 있었습니다.

06-11 22:50:18.241 5112-8279/? W/Auth: [GetToken] GetToken failed with status code: NeedPermission

Permission이라는 힌트를 가지고 두가지 해결방법을 검색해 볼 수 있었습니다.

첫번째는 AndroidManifest.xml 파일에
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
권한을 추가해서 해결이 되었다는 내용이었습니다만 이걸로는 해결되지 않았습니다.

두번째는 config에 AddOauthScope를 추가해 보라는 내용이었고 이걸으로 해결할 수 있었습니다.
이 해결책을 보고 AddOauthScope 함수의 선언부를 보았더니 아래와 같은 주석이 달려 있었습니다.

/// <summary>
/// Requests an Oauth scope from the user.
/// </summary>
/// <remarks>
/// Not setting one will default to 'games_lite' and will not show a consent
/// dialog to the user. Valid examples are 'profile' and 'email'.
/// Full list: https://developers.google.com/identity/protocols/googlescopes
/// To exchange the auth code with an id_token (or user id) on your server,
/// you must add at least one scope.
/// </remarks>
/// <returns>The builder.</returns>
public Builder AddOauthScope(string scope)
{
    if (mScopes == null) mScopes = new List<string>();
    mScopes.Add(scope);
    return this;
}

아무것도 설정하지 않을경우 'games_lite' 라는 scope가 설정된다고 하는데... 주석에 달려 있는 링크를 따라가보니 games_lite라는 scope는 존재하지 않았습니다.

https://developers.google.com/identity/protocols/googlescopes

그래서 위 링크에 있는 scope에서 Google Play Game Service와 관련된 scope를 추가하여 초기화 코드를 아래와 같이 수정하였습니다.

// GPG를 Activate()하면 Social.localUser가 GPG의 계정 정보로 설정됨
// 안드로이드 빌더 초기화
PlayGamesClientConfiguration config = new PlayGamesClientConfiguration.Builder()
    .AddOauthScope("profile")
    .AddOauthScope("email")
    .AddOauthScope("https://www.googleapis.com/auth/games")
    .AddOauthScope("https://www.googleapis.com/auth/plus.login")
    .RequestServerAuthCode(false)
    .RequestIdToken()
    .RequestEmail()
    .Build();
PlayGamesPlatform.InitializeInstance(config);

// 구글 플레이 로그를 확인할려면 활성화
PlayGamesPlatform.DebugLogEnabled = true;

// 구글 플레이 활성화
PlayGamesPlatform.Activate();

이 코드를 통해서 해결하긴 했는데... 문제는 이 코드를 수정한 업데이트를 디바이스에 적용하고 즉시 수정되진 않고 또다른 에러가 발생하면서 로그인에 실패합니다.

이제는 Unity Log에서도 볼 수 있는 ERROR_NOT_AUTHORIZED 에러가 발생하게 됩니다. 이 경우에 캐싱된 로그인 정보를 강제로 SignOut 처리를 해준 후 다시 로그인을 시도하거나 게임을 삭제 후 다시 설치하여 실행하면 됩니다.

그러면 Google Play 로그인과 함께 권한을 물어보는 윈도우가 열리게 되고 허용을 선택하면 로그인에 성공하게 됩니다.

Document랑 예제 좀 탄탄하게 정리해주면 안되나...

[Unity3D] SceneVew에서 targetparametercountexception이 발생할 때

Unity에서 Editor 기능으 구현하다보니 SceneView에서 TargetParameterCountException이 발생하면서 SceneView에 아무것도 보이지 않는 현상이 발생했습니다.

CustomEditor에서 SceneView에 뭔가 표시하기 위한 방식은 아래와 같이 두가지가 있습니다.  이 두가지 스타일을 섞어서 사용할 경우 Exception이 발생합니다. 한가지 형태로 통일하면 Exception을 해결할 수 있습니다.

void OnEnable() {
    SceneView.onSceneGUIDelegate += OnSceneGUI;
}

void OnSceneGUI(SceneView sv) {}
[CustomEditor(typeof(SomeType))]
class SomeType : Editor {
    void OnSceneGUI() {}
}

 

AWS EC2에 ssh로 접속 시 timeout 될 때…

Aws lambda에 서버 로직을 업데이트 하기 위한 EC2 Instance를 생성했는데 ssh 접속을 시도할 때 마다 timeout 오류가 발생하여 원인을 한참동안 파악하다보니 RouteTable 설정의 문제였습니다.

이전에 생성했던 EC2 Instance를 Target으로 하는 RouteTable을 재활용했더니 Target이 사라진 BlackHole 상태가 되어 있었습니다.

Target을 새로 생성한 Instance로 교체해 주었더니 문제없이 잘 접속되었습니다.

CentOS minimal을 virtualBox에 설치하기

게임서버가 aws lambda의 python을 사용하고 있어서 관련 환경을 맞춰주려고 virtualbox에 centos 7을 설치해봤습니다.

아래의 링크에서 minimal버전을 다운로드 받습니다. minimal을 다운로드 받으면 terminal만 보이는 최소한의 버전이 설치됩니다.

그런데 다운로드 받는 경로에 따라서 yum repository의 주소가 달라지는것 같아요. Kaist링크 것을 다운로드 받는걸 추천합니다.

https://www.centos.org/download/

VirtualBox에서 새로 만들기를 눌러서 이름에 CentOS 7이라고 적어줍니다. 이렇게 하니까 기본적으로 어느정도 설정을 알아서 해줍니다.

적당히 다음다음 눌러서 다운로드 받은 ISO 파일을 설정해서 Install CentOS 7 메뉴를 선택해 줍니다.

 

설치가 끝나면 다음 명령을 실행해 주니 알아서 repository 갱신까지 하는 것 같아요.

sudo yum update

sudo yum upgrade

 

neovim에 YouCompleteMe 설치하기

우선 Vundle을 설치합니다.

mkdir -p ~/.config/nvim/bundle
git clone https://github.com/VundleVim/Vundle.vim.git ~/.config/nvim/bundle/Vundle.vim

Neovim은 pip를 사용하여 설치해 줍니다.

pip install neovim

~/.config/nvim/init.vim 파일을 생성하여 아래와 같이 내용을 작성합니다.

set nocompatible
filetype off

set rtp+=~/.config/nvim/bundle/Vundle.vim
call vundle#begin('~/.config/nvim/bundle')

Plugin 'VundleVim/Vundle.vim'
Plugin 'Valloric/YouCompleteMe'

call vundle#end()

nvim을 재시작 후 :Plugininstall 명령을 입력해줍니다.

설치가 종료되면 다시 nvim을 재시작할 때 오류가 발생하지 않으면 되는데 아마 다음과 같은 오류가 발생할 수도 있습니다.

YouCompleteMe unavailable: requires Vim compiled with Python 2.x support

이 경우에는 다음과 같이 neovim을 upgrade 해 주면 실행이 됩니다.

sudo pip2 install --upgrade neovim

 

다른 워드프레스 사이트