SessionID & UserID
Monkey Forums/Monkey Programming/SessionID & UserID
| ||
Looking at GameAnalytics. I need a good way to generate unique User & Session IDs. NOTE: the User ID should stay the same for each player across play sessions; if possible, it should remain the same across different games. NOTE: Unlike the User ID, the Session ID should change for every play session. Does anyone have any idea on how to do this? Any modules that would help? I can imagine it can be done if I used an online service for account management, but for simpler offline games and Apps that is not always an option. Also need to get a "build" number for each platform. |
| ||
Can you grab the user's email and use that? Session IDs can just be a random string of numbers and letters, or a time stamp. I don't think you'd need either for offline games and apps. The point of Unique IDs and Session IDs is so the server can track them over time. If there will be no online activity, these things aren't needed. |
| ||
Hah. Yeah obviously I did not mean to say "offline", what was I thinking? You are right! Kinda difficult to send analytics over the internet if offline. No I meant smaller games that don't use an account system = no email. Mac Adress, Device ID, something like that. I could use a timestamp + some random letters for SessionID. |
| ||
I've heard, but never confirmed, that some devices don't provide device IDs. So what you could do is generate a random string of numbers and digits to identify the device (something like, "UDH948sahd93HF848FHisudh847"). Ask the server if that already exists. If not, use it. Otherwise, regenerate the ID. Save the unique device ID to the device locally, then send it with each message. I think Apple at one time had device IDs, but they stopped using that because of security issues. |
| ||
Yeah, I'll generate a TimeStampID and save it to disk, then reuse that unless the app has an account sytem. For future reference UUID generation: [required the Md5 library!] Method GetUniqueTimeID:String() Local date:= GetDate() Local months:=["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] Local day:= ("0" + date[2])[ - 2 ..] Local month:=months[date[1]-1] Local year:=date[0] Local hour:=("0"+date[3])[-2..] Local min:=("0"+date[4])[-2..] Local sec:=("0"+date[5])[-2..] + "." + ("00"+date[6])[-3..] Local now:string = hour + ":" + min + ":" + sec + " " + day + " " + month + " " + year Return MD5(now) End |
| ||
generating a random string, with a magic number baked in, is probably a good way to ID someone. If you need/want something UIID/GUID compatible for your game for online purposes, you could also implement it server-side on first request to the client program, or grab one from an online service that provides this for you using HttpRequest. One such service: http://www.famkruithof.net/uuid/uuidgen |
| ||
I recently added iOS/Android GameAnalytics support to my Monkey game framework. I handled the generation of User & Session IDs, by accessing the platforms' native UUID APIs. iOS Native Code: // uuid.ios.cpp String Device_GetUUID() { CFUUIDRef UUIDObj = CFUUIDCreate( NULL ); CFStringRef UUIDStr = CFUUIDCreateString( NULL, UUIDObj ); int len = CFStringGetLength( UUIDStr ); char* buffer = (char *)calloc( 1, (len + 1) ); CFStringGetBytes( UUIDStr, CFRangeMake(0, len), kCFStringEncodingASCII, '0', false, (UInt8*)buffer, len, NULL ); String UUID = String( buffer ); free( buffer ); CFRelease( (CFTypeRef)UUIDStr ); CFRelease( (CFTypeRef)UUIDObj ); return UUID; } Android Native Code: // uuid.android.java import java.util.UUID; import java.util.Locale; class Device { public static String GetUUID() { return UUID.randomUUID().toString().toUpperCase( Locale.US ); } } Monkey Code: ' uuid.monkey #if TARGET="ios" or TARGET="android" import "native/device.${TARGET}.${LANG}" EXTERN PRIVATE #if TARGET="ios" function Device_GetUUID$() #else class Device method GetUUID$() end PRIVATE global _Device:= new Device #end #end '#if TARGET="ios" or TARGET="android" PUBLIC function deviceGetUUID$() #if TARGET="ios" return Device_GetUUID #elseif TARGET="android" return _Device.GetUUID #else Error "deviceGetUUID() Only Available On iOS/Android Targets!" #end end |
| ||
That is awesome! Do you have a full working version of your whole GameAnalytics? I used their REST API and wrote it in Monkey-only code to be as crossplatform as possible. I can send design events but still now too feature packed. I assume you wrapped their iOS & Android API's? |
| ||
I also use the REST API. :) UUID & MD5 is via the iOS & Android native APIs, HTTP is via native 3rd-Party SDKs and JSON support is via Damian Sinclar's JSON module (https://code.google.com/p/monkey-json). Even though I went native for UUID, MD5 & HTTP support, I believe there are Monkey-code-only equivalents for each. My Monkey GameAnalytics module: [monkeycode] #rem gameanalytics.monkey #end import gamebase.http import gamebase.json import gamebase.device import gamebase.director '############################################################################################################### PRIVATE const _BASE_URL := "http://api.gameanalytics.com/1/" const _KEY_USER_ID := "GameAnalytics_UserId" const _SESSION_RESUME_WINDOW := ((1000 * 60) * 5) 'How long after OnSuspend session id expires (5 minutes) global _extBaseURL$ ' base url + gameId global _gameKey$ global _secretKey$ global _buildId$ global _userId$ global _sessionId$ global _sessionResumeCutoff global _reqIdList:IntList '--------------------------------------------------------------------------------------------------------------- function _SubmitEvent:void( eventType$, eventId$, aux:JSONObject ) if httpIsOnline ' get/descard any previous request responses for local rid:= eachin _reqIdList if httpPoll( rid ) httpResponse( rid ) ' get & discard response _reqIdList.Remove( rid ) end end ' setup request body Local body_json:= new JSONObject() body_json.AddPrim( "event_id", eventId ) body_json.AddPrim( "user_id", _userId ) body_json.AddPrim( "build", _buildId ) body_json.AddPrim( "session_id", _sessionId ) if not (aux = NULL) for local name:= eachin aux.Names body_json.AddItem( name, aux.GetItem(name) ) end end local body_str:= body_json.ToJSONString ' setup request header Local header:= new StringMap<String> header.Add( "Content-Length", body_str.Length ) header.Add( "Content-Type", "application/json" ) header.Add( "Authorization", deviceGetMD5Hash( body_str + _secretKey ) ) ' construct complete request url local url:= _extBaseURL + eventType ' make the request & store request-id _reqIdList.AddLast( httpPost( url, body_str, header ) ) end end '############################################################################################################### PUBLIC '--------------------------------------------------------------------------------------------------------------- function GA_Init:void( gameKey$, secretKey$, buildId$ ) if not gameKey Error "GA_Init: Game Key Is Empty" if not secretKey Error "GA_Init: Secret Key Is Empty" if not buildId Error "GA_Init: Build Id Is Empty" _gameKey = gameKey _secretKey = secretKey _buildId = buildId _sessionId = deviceGetUUID ' NOTE: The user-id will persit until the app is uninstalled. On iOS, the id does ' have the potential to follow the user across device updates. _userId = gReg.GetString( _KEY_USER_ID, deviceGetUUID ) gReg.SetString( _KEY_USER_ID, _userId, true ) _extBaseURL = _BASE_URL + _gameKey + "/" _reqIdList = new IntList end '--------------------------------------------------------------------------------------------------------------- function GA_Suspend:void() _sessionResumeCutoff = Millisecs + _SESSION_RESUME_WINDOW end '--------------------------------------------------------------------------------------------------------------- function GA_Resume:void() if _sessionResumeCutoff < Millisecs _sessionId = deviceGetUUID end '--------------------------------------------------------------------------------------------------------------- function GA_User:void( eventId$, aux:JSONObject=NULL ) _SubmitEvent( "user", eventId, aux ) end function GA_Design:void( eventId$, aux:JSONObject=NULL ) _SubmitEvent( "design", eventId, aux ) end function GA_Quality:void( eventId$, aux:JSONObject=NULL ) _SubmitEvent( "quality", eventId, aux ) end function GA_Business:void( eventId$, aux:JSONObject=NULL ) _SubmitEvent( "business", eventId, aux ) end [/monkeycode] I hope it all self-explanatory and easy to follow .. :) NOTES: - 'gReg' wraps a StringMap<String> that gets written-to/read-from the state (via SaveState/LoadState) during OnSuspend/ OnCreate - I don't care about the POST responses which is why I just discard them - I use 5 mins for the SessionID expire because that's how long a stretch of inactivity the GameAnalytics RealTime Dashboard waits before it considers a session to have ended. |
| ||
Thanks David, great code, I also added a js/html5 version:// uuid.html5.js function Device_GetUUID() { var guid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); return v.toString(16); }); return guid; } (c) http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript |
| ||
' uuid.monkey #if TARGET="ios" or TARGET="android" or TARGET="html5" import "native/uuid.${TARGET}.${LANG}" EXTERN PRIVATE #if TARGET="ios" function Device_GetUUID$() #elseif TARGET="android" class Device method GetUUID$() end PRIVATE global _Device:= new Device #elseif TARGET="html5" function Device_GetUUID$() #end #end PUBLIC function deviceGetUUID$() #if TARGET="ios" return Device_GetUUID #elseif TARGET="android" return _Device.GetUUID #elseif TARGET="html5" return Device_GetUUID() #else Error "deviceGetUUID() Only Available On iOS/Android/HTML5 Targets!" #end end |
| ||
Didn't Apple forbid apps that uses UUID? There was even some trouble with Admob because of that... |
| ||
Yes, you are not allowed to get a unique device ID, such as the previous well known DeviceID or the MacAddress. However many still call the unique identifier for UUID. Sometimes this means connecting to a website, if the App has login use the email or you could just randomize a number and save it in a file - however that UUID will be different even for the same user on their Pad compared to their phone. Does anyone have a full updated working project for GameAnalytics? Looks like the above is missing a lot of code? GitHub/BitBucket link? |