@@ -13,6 +13,19 @@ import UUID from './uuid';
1313import { version } from '../package.json' ;
1414import DEFAULT_OPTIONS from './options' ;
1515
16+ let asyncStorage ;
17+ let Platform ;
18+ let DeviceInfo ;
19+ if ( BUILD_COMPAT_REACT_NATIVE ) {
20+ const reactNative = require ( 'react-native' ) ;
21+ Platform = reactNative . Platform ;
22+ asyncStorage = reactNative . AsyncStorage ;
23+ try {
24+ DeviceInfo = require ( 'react-native-device-info' ) ;
25+ } catch ( e ) {
26+ }
27+ }
28+
1629/**
1730 * AmplitudeClient SDK API - instance constructor.
1831 * The Amplitude class handles creation of client instances, all you need to do is call amplitude.getInstance()
@@ -86,74 +99,105 @@ AmplitudeClient.prototype.init = function init(apiKey, opt_userId, opt_config, o
8699 this . options . domain = this . cookieStorage . options ( ) . domain ;
87100
88101 _loadCookieData ( this ) ;
102+ this . _pendingReadStorage = true ;
103+
104+ const initFromStorage = ( ) => {
105+ // load deviceId and userId from input, or try to fetch existing value from cookie
106+ this . options . deviceId = ( type ( opt_config ) === 'object' && type ( opt_config . deviceId ) === 'string' &&
107+ ! utils . isEmptyString ( opt_config . deviceId ) && opt_config . deviceId ) ||
108+ ( this . options . deviceIdFromUrlParam && this . _getDeviceIdFromUrlParam ( this . _getUrlParams ( ) ) ) ||
109+ this . options . deviceId || UUID ( ) + 'R' ;
110+ this . options . userId =
111+ ( type ( opt_userId ) === 'string' && ! utils . isEmptyString ( opt_userId ) && opt_userId ) ||
112+ ( type ( opt_userId ) === 'number' && opt_userId . toString ( ) ) ||
113+ this . options . userId || null ;
114+
115+ var now = new Date ( ) . getTime ( ) ;
116+ if ( ! this . _sessionId || ! this . _lastEventTime || now - this . _lastEventTime > this . options . sessionTimeout ) {
117+ if ( this . options . unsetParamsReferrerOnNewSession ) {
118+ this . _unsetUTMParams ( ) ;
119+ }
120+ this . _newSession = true ;
121+ this . _sessionId = now ;
89122
90- // load deviceId and userId from input, or try to fetch existing value from cookie
91- this . options . deviceId = ( type ( opt_config ) === 'object' && type ( opt_config . deviceId ) === 'string' &&
92- ! utils . isEmptyString ( opt_config . deviceId ) && opt_config . deviceId ) ||
93- ( this . options . deviceIdFromUrlParam && this . _getDeviceIdFromUrlParam ( this . _getUrlParams ( ) ) ) ||
94- this . options . deviceId || UUID ( ) + 'R' ;
95- this . options . userId =
96- ( type ( opt_userId ) === 'string' && ! utils . isEmptyString ( opt_userId ) && opt_userId ) ||
97- ( type ( opt_userId ) === 'number' && opt_userId . toString ( ) ) ||
98- this . options . userId || null ;
99-
100- // load unsent events and identifies before any attempt to log new ones
101- if ( this . options . saveEvents ) {
102- this . _unsentEvents = this . _loadSavedUnsentEvents ( this . options . unsentKey ) ;
103- this . _unsentIdentifys = this . _loadSavedUnsentEvents ( this . options . unsentIdentifyKey ) ;
104-
105- // validate event properties for unsent events
106- for ( var i = 0 ; i < this . _unsentEvents . length ; i ++ ) {
107- var eventProperties = this . _unsentEvents [ i ] . event_properties ;
108- var groups = this . _unsentEvents [ i ] . groups ;
109- this . _unsentEvents [ i ] . event_properties = utils . validateProperties ( eventProperties ) ;
110- this . _unsentEvents [ i ] . groups = utils . validateGroups ( groups ) ;
123+ // only capture UTM params and referrer if new session
124+ if ( this . options . saveParamsReferrerOncePerSession ) {
125+ this . _trackParamsAndReferrer ( ) ;
126+ }
111127 }
112128
113- // validate user properties for unsent identifys
114- for ( var j = 0 ; j < this . _unsentIdentifys . length ; j ++ ) {
115- var userProperties = this . _unsentIdentifys [ j ] . user_properties ;
116- var identifyGroups = this . _unsentIdentifys [ j ] . groups ;
117- this . _unsentIdentifys [ j ] . user_properties = utils . validateProperties ( userProperties ) ;
118- this . _unsentIdentifys [ j ] . groups = utils . validateGroups ( identifyGroups ) ;
129+ if ( ! this . options . saveParamsReferrerOncePerSession ) {
130+ this . _trackParamsAndReferrer ( ) ;
119131 }
120- }
121132
122- var now = new Date ( ) . getTime ( ) ;
123- if ( ! this . _sessionId || ! this . _lastEventTime || now - this . _lastEventTime > this . options . sessionTimeout ) {
124- if ( this . options . unsetParamsReferrerOnNewSession ) {
125- this . _unsetUTMParams ( ) ;
133+ // load unsent events and identifies before any attempt to log new ones
134+ if ( this . options . saveEvents ) {
135+ this . _unsentEvents = this . _loadSavedUnsentEvents ( this . options . unsentKey ) . concat ( this . _unsentEvents ) ;
136+ this . _unsentIdentifys = this . _loadSavedUnsentEvents ( this . options . unsentIdentifyKey ) . concat ( this . _unsentIdentifys ) ;
137+
138+ // validate event properties for unsent events
139+ for ( let i = 0 ; i < this . _unsentEvents . length ; i ++ ) {
140+ var eventProperties = this . _unsentEvents [ i ] . event_properties ;
141+ var groups = this . _unsentEvents [ i ] . groups ;
142+ this . _unsentEvents [ i ] . event_properties = utils . validateProperties ( eventProperties ) ;
143+ this . _unsentEvents [ i ] . groups = utils . validateGroups ( groups ) ;
144+ }
145+
146+ // validate user properties for unsent identifys
147+ for ( let j = 0 ; j < this . _unsentIdentifys . length ; j ++ ) {
148+ var userProperties = this . _unsentIdentifys [ j ] . user_properties ;
149+ var identifyGroups = this . _unsentIdentifys [ j ] . groups ;
150+ this . _unsentIdentifys [ j ] . user_properties = utils . validateProperties ( userProperties ) ;
151+ this . _unsentIdentifys [ j ] . groups = utils . validateGroups ( identifyGroups ) ;
152+ }
126153 }
127- this . _newSession = true ;
128- this . _sessionId = now ;
129154
130- // only capture UTM params and referrer if new session
131- if ( this . options . saveParamsReferrerOncePerSession ) {
132- this . _trackParamsAndReferrer ( ) ;
155+ this . _lastEventTime = now ;
156+ _saveCookieData ( this ) ;
157+
158+ this . _pendingReadStorage = false ;
159+
160+ this . _sendEventsIfReady ( ) ; // try sending unsent events
161+
162+ for ( let i = 0 ; i < this . _onInit . length ; i ++ ) {
163+ this . _onInit [ i ] ( ) ;
133164 }
134- }
165+ this . _onInit = [ ] ;
166+ this . _isInitialized = true ;
167+ } ;
135168
136- if ( ! this . options . saveParamsReferrerOncePerSession ) {
137- this . _trackParamsAndReferrer ( ) ;
169+ if ( asyncStorage ) {
170+ asyncStorage . getItem ( this . _storageSuffix ) . then ( ( json ) => {
171+ const cookieData = JSON . parse ( json ) ;
172+ if ( cookieData ) {
173+ _loadCookieDataProps ( this , cookieData ) ;
174+ }
175+ if ( DeviceInfo ) {
176+ Promise . all ( [ DeviceInfo . getCarrier ( ) , DeviceInfo . getModel ( ) , DeviceInfo . getManufacturer ( ) ] ) . then ( values => {
177+ this . deviceInfo = {
178+ carrier : values [ 0 ] ,
179+ model : values [ 1 ] ,
180+ manufacturer : values [ 2 ]
181+ } ;
182+ initFromStorage ( ) ;
183+ this . runQueuedFunctions ( ) ;
184+ } ) ;
185+ } else {
186+ initFromStorage ( ) ;
187+ this . runQueuedFunctions ( ) ;
188+ }
189+ } ) ;
190+ } else {
191+ initFromStorage ( ) ;
138192 }
139193
140- this . _lastEventTime = now ;
141- _saveCookieData ( this ) ;
142-
143- this . _sendEventsIfReady ( ) ; // try sending unsent events
144194 } catch ( e ) {
145195 utils . log . error ( e ) ;
146196 } finally {
147197 if ( type ( opt_callback ) === 'function' ) {
148198 opt_callback ( this ) ;
149199 }
150200 }
151-
152- for ( let i = 0 ; i < this . _onInit . length ; i ++ ) {
153- this . _onInit [ i ] ( ) ;
154- }
155- this . _onInit = [ ] ;
156- this . _isInitialized = true ;
157201} ;
158202
159203/**
@@ -436,7 +480,7 @@ var _loadCookieDataProps = function _loadCookieDataProps(scope, cookieData) {
436480 * @private
437481 */
438482var _saveCookieData = function _saveCookieData ( scope ) {
439- scope . cookieStorage . set ( scope . options . cookieName + scope . _storageSuffix , {
483+ const cookieData = {
440484 deviceId : scope . options . deviceId ,
441485 userId : scope . options . userId ,
442486 optOut : scope . options . optOut ,
@@ -445,7 +489,11 @@ var _saveCookieData = function _saveCookieData(scope) {
445489 eventId : scope . _eventId ,
446490 identifyId : scope . _identifyId ,
447491 sequenceNumber : scope . _sequenceNumber
448- } ) ;
492+ } ;
493+ if ( asyncStorage ) {
494+ asyncStorage . setItem ( scope . _storageSuffix , JSON . stringify ( cookieData ) ) ;
495+ }
496+ scope . cookieStorage . set ( scope . options . cookieName + scope . _storageSuffix , cookieData ) ;
449497} ;
450498
451499/**
@@ -721,6 +769,9 @@ AmplitudeClient.prototype.setDeviceId = function setDeviceId(deviceId) {
721769 * @example amplitudeClient.setUserProperties({'gender': 'female', 'sign_up_complete': true})
722770 */
723771AmplitudeClient . prototype . setUserProperties = function setUserProperties ( userProperties ) {
772+ if ( this . _pendingReadStorage ) {
773+ return this . _q . push ( [ 'identify' , userProperties ] ) ;
774+ }
724775 if ( ! this . _apiKeySet ( 'setUserProperties()' ) || ! utils . validateInput ( userProperties , 'userProperties' , 'object' ) ) {
725776 return ;
726777 }
@@ -782,6 +833,9 @@ var _convertProxyObjectToRealObject = function _convertProxyObjectToRealObject(i
782833 * amplitude.identify(identify);
783834 */
784835AmplitudeClient . prototype . identify = function ( identify_obj , opt_callback ) {
836+ if ( this . _pendingReadStorage ) {
837+ return this . _q . push ( [ 'identify' , identify_obj , opt_callback ] ) ;
838+ }
785839 if ( ! this . _apiKeySet ( 'identify()' ) ) {
786840 if ( type ( opt_callback ) === 'function' ) {
787841 opt_callback ( 0 , 'No request sent' , { reason : 'API key is not set' } ) ;
@@ -814,6 +868,9 @@ AmplitudeClient.prototype.identify = function(identify_obj, opt_callback) {
814868} ;
815869
816870AmplitudeClient . prototype . groupIdentify = function ( group_type , group_name , identify_obj , opt_callback ) {
871+ if ( this . _pendingReadStorage ) {
872+ return this . _q . push ( [ 'groupIdentify' , group_type , group_name , identify_obj , opt_callback ] ) ;
873+ }
817874 if ( ! this . _apiKeySet ( 'groupIdentify()' ) ) {
818875 if ( type ( opt_callback ) === 'function' ) {
819876 opt_callback ( 0 , 'No request sent' , { reason : 'API key is not set' } ) ;
@@ -907,6 +964,21 @@ AmplitudeClient.prototype._logEvent = function _logEvent(eventType, eventPropert
907964 this . _lastEventTime = eventTime ;
908965 _saveCookieData ( this ) ;
909966
967+ let osName = this . _ua . browser . name ;
968+ let osVersion = this . _ua . browser . major ;
969+ let deviceModel = this . _ua . os . name ;
970+ let deviceManufacturer ;
971+ let carrier ;
972+ if ( BUILD_COMPAT_REACT_NATIVE ) {
973+ osName = Platform . OS ;
974+ osVersion = Platform . Version ;
975+ if ( this . deviceInfo ) {
976+ carrier = this . deviceInfo . carrier ;
977+ deviceManufacturer = this . deviceInfo . manufacturer ;
978+ deviceModel = this . deviceInfo . model ;
979+ }
980+ }
981+
910982 userProperties = userProperties || { } ;
911983 var trackingOptions = { ...this . _apiPropertiesTrackingOptions } ;
912984 apiProperties = { ...( apiProperties || { } ) , ...trackingOptions } ;
@@ -922,10 +994,12 @@ AmplitudeClient.prototype._logEvent = function _logEvent(eventType, eventPropert
922994 event_type : eventType ,
923995 version_name : _shouldTrackField ( this , 'version_name' ) ? ( this . options . versionName || null ) : null ,
924996 platform : _shouldTrackField ( this , 'platform' ) ? this . options . platform : null ,
925- os_name : _shouldTrackField ( this , 'os_name' ) ? ( this . _ua . browser . name || null ) : null ,
926- os_version : _shouldTrackField ( this , 'os_version' ) ? ( this . _ua . browser . major || null ) : null ,
927- device_model : _shouldTrackField ( this , 'device_model' ) ? ( this . _ua . os . name || null ) : null ,
997+ os_name : _shouldTrackField ( this , 'os_name' ) ? ( osName || null ) : null ,
998+ os_version : _shouldTrackField ( this , 'os_version' ) ? ( osVersion || null ) : null ,
999+ device_model : _shouldTrackField ( this , 'device_model' ) ? ( deviceModel || null ) : null ,
1000+ device_manufacturer : _shouldTrackField ( this , 'device_manufacturer' ) ? ( deviceManufacturer || null ) : null ,
9281001 language : _shouldTrackField ( this , 'language' ) ? this . options . language : null ,
1002+ carrier : _shouldTrackField ( this , 'carrier' ) ? ( carrier || null ) : null ,
9291003 api_properties : apiProperties ,
9301004 event_properties : utils . truncate ( utils . validateProperties ( eventProperties ) ) ,
9311005 user_properties : utils . truncate ( utils . validateProperties ( userProperties ) ) ,
@@ -1007,6 +1081,9 @@ AmplitudeClient.prototype._limitEventsQueued = function _limitEventsQueued(queue
10071081 * @example amplitudeClient.logEvent('Clicked Homepage Button', {'finished_flow': false, 'clicks': 15});
10081082 */
10091083AmplitudeClient . prototype . logEvent = function logEvent ( eventType , eventProperties , opt_callback ) {
1084+ if ( this . _pendingReadStorage ) {
1085+ return this . _q . push ( [ 'logEvent' , eventType , eventProperties , opt_callback ] ) ;
1086+ }
10101087 return this . logEventWithTimestamp ( eventType , eventProperties , null , opt_callback ) ;
10111088} ;
10121089
@@ -1021,6 +1098,9 @@ AmplitudeClient.prototype.logEvent = function logEvent(eventType, eventPropertie
10211098 * @example amplitudeClient.logEvent('Clicked Homepage Button', {'finished_flow': false, 'clicks': 15});
10221099 */
10231100AmplitudeClient . prototype . logEventWithTimestamp = function logEvent ( eventType , eventProperties , timestamp , opt_callback ) {
1101+ if ( this . _pendingReadStorage ) {
1102+ return this . _q . push ( [ 'logEventWithTimestamp' , eventType , eventProperties , timestamp , opt_callback ] ) ;
1103+ }
10241104 if ( ! this . _apiKeySet ( 'logEvent()' ) ) {
10251105 if ( type ( opt_callback ) === 'function' ) {
10261106 opt_callback ( 0 , 'No request sent' , { reason : 'API key not set' } ) ;
@@ -1058,6 +1138,9 @@ AmplitudeClient.prototype.logEventWithTimestamp = function logEvent(eventType, e
10581138 * @example amplitudeClient.logEventWithGroups('Clicked Button', null, {'orgId': 24});
10591139 */
10601140AmplitudeClient . prototype . logEventWithGroups = function ( eventType , eventProperties , groups , opt_callback ) {
1141+ if ( this . _pendingReadStorage ) {
1142+ return this . _q . push ( [ 'logEventWithGroups' , eventType , eventProperties , groups , opt_callback ] ) ;
1143+ }
10611144 if ( ! this . _apiKeySet ( 'logEventWithGroups()' ) ) {
10621145 if ( type ( opt_callback ) === 'function' ) {
10631146 opt_callback ( 0 , 'No request sent' , { reason : 'API key not set' } ) ;
@@ -1193,7 +1276,7 @@ AmplitudeClient.prototype.sendEvents = function sendEvents(callback) {
11931276 }
11941277 if ( this . _sending ) {
11951278 if ( type ( callback ) === 'function' ) {
1196- callback ( 0 , 'No request sent' , { reason : 'Request already in progress' } ) ;
1279+ callback ( 0 , 'No request sent' , { reason : 'Request already in progress. Events will be sent once this request is complete ' } ) ;
11971280 }
11981281 return ;
11991282 }
0 commit comments