@@ -131,6 +131,7 @@ internal class OneSignalImp : IOneSignal, IServiceProvider {
131131 private var _consentRequired : Boolean? = null
132132 private var _consentGiven : Boolean? = null
133133 private var _disableGMSMissingPrompt : Boolean? = null
134+ private val initLock: Any = Any ()
134135 private val loginLock: Any = Any ()
135136
136137 private val listOfModules =
@@ -171,130 +172,158 @@ internal class OneSignalImp : IOneSignal, IServiceProvider {
171172 ): Boolean {
172173 Logging .log(LogLevel .DEBUG , " initWithContext(context: $context , appId: $appId )" )
173174
174- // do not do this again if already initialized
175- if (isInitialized) {
176- return true
177- }
175+ synchronized(initLock) {
176+ // do not do this again if already initialized
177+ if (isInitialized) {
178+ Logging .log(LogLevel .DEBUG , " initWithContext: SDK already initialized" )
179+ return true
180+ }
178181
179- PreferenceStoreFix .ensureNoObfuscatedPrefStore(context )
182+ Logging .log( LogLevel . DEBUG , " initWithContext: SDK initializing " )
180183
181- // start the application service. This is called explicitly first because we want
182- // to make sure it has the context provided on input, for all other startable services
183- // to depend on if needed.
184- val applicationService = services.getService<IApplicationService >()
185- (applicationService as ApplicationService ).start(context)
184+ PreferenceStoreFix .ensureNoObfuscatedPrefStore(context)
186185
187- // Give the logging singleton access to the application service to support visual logging.
188- Logging .applicationService = applicationService
186+ // start the application service. This is called explicitly first because we want
187+ // to make sure it has the context provided on input, for all other startable services
188+ // to depend on if needed.
189+ val applicationService = services.getService<IApplicationService >()
190+ (applicationService as ApplicationService ).start(context)
189191
190- // get the current config model, if there is one
191- configModel = services.getService<ConfigModelStore >().model
192- sessionModel = services.getService<SessionModelStore >().model
192+ // Give the logging singleton access to the application service to support visual logging.
193+ Logging .applicationService = applicationService
193194
194- // initWithContext is called by our internal services/receivers/activites but they do not provide
195- // an appId (they don't know it). If the app has never called the external initWithContext
196- // prior to our services/receivers/activities we will blow up, as no appId has been established.
197- if (appId == null && ! configModel!! .hasProperty(ConfigModel ::appId.name)) {
198- Logging .warn(" initWithContext called without providing appId, and no appId has been established!" )
199- return false
200- }
195+ // get the current config model, if there is one
196+ configModel = services.getService<ConfigModelStore >().model
197+ sessionModel = services.getService<SessionModelStore >().model
201198
202- var forceCreateUser = false
203- // if the app id was specified as input, update the config model with it
204- if (appId != null ) {
205- if (! configModel!! .hasProperty(ConfigModel ::appId.name) || configModel!! .appId != appId) {
206- forceCreateUser = true
199+ // initWithContext is called by our internal services/receivers/activites but they do not provide
200+ // an appId (they don't know it). If the app has never called the external initWithContext
201+ // prior to our services/receivers/activities we will blow up, as no appId has been established.
202+ if (appId == null && ! configModel!! .hasProperty(ConfigModel ::appId.name)) {
203+ Logging .warn(" initWithContext called without providing appId, and no appId has been established!" )
204+ return false
207205 }
208- configModel!! .appId = appId
209- }
210206
211- // if requires privacy consent was set prior to init, set it in the model now
212- if (_consentRequired != null ) {
213- configModel!! .consentRequired = _consentRequired !!
214- }
207+ var forceCreateUser = false
208+ // if the app id was specified as input, update the config model with it
209+ if (appId != null ) {
210+ if (! configModel!! .hasProperty(ConfigModel ::appId.name) || configModel!! .appId != appId) {
211+ forceCreateUser = true
212+ }
213+ configModel!! .appId = appId
214+ }
215215
216- // if privacy consent was set prior to init, set it in the model now
217- if (_consentGiven != null ) {
218- configModel!! .consentGiven = _consentGiven !!
219- }
216+ // if requires privacy consent was set prior to init, set it in the model now
217+ if (_consentRequired != null ) {
218+ configModel!! .consentRequired = _consentRequired !!
219+ }
220220
221- if (_disableGMSMissingPrompt != null ) {
222- configModel!! .disableGMSMissingPrompt = _disableGMSMissingPrompt !!
223- }
221+ // if privacy consent was set prior to init, set it in the model now
222+ if (_consentGiven != null ) {
223+ configModel!! .consentGiven = _consentGiven !!
224+ }
224225
225- // "Inject" the services required by this main class
226- _location = services.getService()
227- _user = services.getService()
228- _session = services.getService()
229- iam = services.getService()
230- _notifications = services.getService()
231- operationRepo = services.getService()
232- propertiesModelStore = services.getService()
233- identityModelStore = services.getService()
234- subscriptionModelStore = services.getService()
235- preferencesService = services.getService()
236-
237- // Instantiate and call the IStartableServices
238- startupService = services.getService()
239- startupService!! .bootstrap()
240-
241- if (forceCreateUser || ! identityModelStore!! .model.hasProperty(IdentityConstants .ONESIGNAL_ID )) {
242- val legacyPlayerId = preferencesService!! .getString(PreferenceStores .ONESIGNAL , PreferenceOneSignalKeys .PREFS_LEGACY_PLAYER_ID )
243- if (legacyPlayerId == null ) {
244- Logging .debug(" initWithContext: creating new device-scoped user" )
245- createAndSwitchToNewUser()
246- operationRepo!! .enqueue(
247- LoginUserOperation (
248- configModel!! .appId,
249- identityModelStore!! .model.onesignalId,
250- identityModelStore!! .model.externalId,
251- ),
252- )
253- } else {
254- Logging .debug(" initWithContext: creating user linked to subscription $legacyPlayerId " )
226+ if (_disableGMSMissingPrompt != null ) {
227+ configModel!! .disableGMSMissingPrompt = _disableGMSMissingPrompt !!
228+ }
255229
256- // Converting a 4.x SDK to the 5.x SDK. We pull the legacy user sync values to create the subscription model, then enqueue
257- // a specialized `LoginUserFromSubscriptionOperation`, which will drive fetching/refreshing of the local user
258- // based on the subscription ID we do have.
259- val legacyUserSyncString =
230+ // "Inject" the services required by this main class
231+ _location = services.getService()
232+ _user = services.getService()
233+ _session = services.getService()
234+ iam = services.getService()
235+ _notifications = services.getService()
236+ operationRepo = services.getService()
237+ propertiesModelStore = services.getService()
238+ identityModelStore = services.getService()
239+ subscriptionModelStore = services.getService()
240+ preferencesService = services.getService()
241+
242+ // Instantiate and call the IStartableServices
243+ startupService = services.getService()
244+ startupService!! .bootstrap()
245+
246+ if (forceCreateUser || ! identityModelStore!! .model.hasProperty(IdentityConstants .ONESIGNAL_ID )) {
247+ val legacyPlayerId =
260248 preferencesService!! .getString(
261249 PreferenceStores .ONESIGNAL ,
262- PreferenceOneSignalKeys .PREFS_LEGACY_USER_SYNCVALUES ,
250+ PreferenceOneSignalKeys .PREFS_LEGACY_PLAYER_ID ,
251+ )
252+ if (legacyPlayerId == null ) {
253+ Logging .debug(" initWithContext: creating new device-scoped user" )
254+ createAndSwitchToNewUser()
255+ operationRepo!! .enqueue(
256+ LoginUserOperation (
257+ configModel!! .appId,
258+ identityModelStore!! .model.onesignalId,
259+ identityModelStore!! .model.externalId,
260+ ),
261+ )
262+ } else {
263+ Logging .debug(" initWithContext: creating user linked to subscription $legacyPlayerId " )
264+
265+ // Converting a 4.x SDK to the 5.x SDK. We pull the legacy user sync values to create the subscription model, then enqueue
266+ // a specialized `LoginUserFromSubscriptionOperation`, which will drive fetching/refreshing of the local user
267+ // based on the subscription ID we do have.
268+ val legacyUserSyncString =
269+ preferencesService!! .getString(
270+ PreferenceStores .ONESIGNAL ,
271+ PreferenceOneSignalKeys .PREFS_LEGACY_USER_SYNCVALUES ,
272+ )
273+ var suppressBackendOperation = false
274+
275+ if (legacyUserSyncString != null ) {
276+ val legacyUserSyncJSON = JSONObject (legacyUserSyncString)
277+ val notificationTypes = legacyUserSyncJSON.getInt(" notification_types" )
278+
279+ val pushSubscriptionModel = SubscriptionModel ()
280+ pushSubscriptionModel.id = legacyPlayerId
281+ pushSubscriptionModel.type = SubscriptionType .PUSH
282+ pushSubscriptionModel.optedIn =
283+ notificationTypes != SubscriptionStatus .NO_PERMISSION .value && notificationTypes != SubscriptionStatus .UNSUBSCRIBE .value
284+ pushSubscriptionModel.address =
285+ legacyUserSyncJSON.safeString(" identifier" ) ? : " "
286+ pushSubscriptionModel.status = SubscriptionStatus .fromInt(notificationTypes)
287+ ? : SubscriptionStatus .NO_PERMISSION
288+ configModel!! .pushSubscriptionId = legacyPlayerId
289+ subscriptionModelStore!! .add(
290+ pushSubscriptionModel,
291+ ModelChangeTags .NO_PROPOGATE ,
292+ )
293+ suppressBackendOperation = true
294+ }
295+
296+ createAndSwitchToNewUser(suppressBackendOperation = suppressBackendOperation)
297+
298+ operationRepo!! .enqueue(
299+ LoginUserFromSubscriptionOperation (
300+ configModel!! .appId,
301+ identityModelStore!! .model.onesignalId,
302+ legacyPlayerId,
303+ ),
304+ )
305+ preferencesService!! .saveString(
306+ PreferenceStores .ONESIGNAL ,
307+ PreferenceOneSignalKeys .PREFS_LEGACY_PLAYER_ID ,
308+ null ,
263309 )
264- var suppressBackendOperation = false
265-
266- if (legacyUserSyncString != null ) {
267- val legacyUserSyncJSON = JSONObject (legacyUserSyncString)
268- val notificationTypes = legacyUserSyncJSON.getInt(" notification_types" )
269-
270- val pushSubscriptionModel = SubscriptionModel ()
271- pushSubscriptionModel.id = legacyPlayerId
272- pushSubscriptionModel.type = SubscriptionType .PUSH
273- pushSubscriptionModel.optedIn = notificationTypes != SubscriptionStatus .NO_PERMISSION .value && notificationTypes != SubscriptionStatus .UNSUBSCRIBE .value
274- pushSubscriptionModel.address = legacyUserSyncJSON.safeString(" identifier" ) ? : " "
275- pushSubscriptionModel.status = SubscriptionStatus .fromInt(notificationTypes) ? : SubscriptionStatus .NO_PERMISSION
276- configModel!! .pushSubscriptionId = legacyPlayerId
277- subscriptionModelStore!! .add(pushSubscriptionModel, ModelChangeTags .NO_PROPOGATE )
278- suppressBackendOperation = true
279310 }
280-
281- createAndSwitchToNewUser(suppressBackendOperation = suppressBackendOperation)
282-
311+ } else {
312+ Logging .debug(" initWithContext: using cached user ${identityModelStore!! .model.onesignalId} " )
283313 operationRepo!! .enqueue(
284- LoginUserFromSubscriptionOperation (configModel!! .appId, identityModelStore!! .model.onesignalId, legacyPlayerId),
314+ RefreshUserOperation (
315+ configModel!! .appId,
316+ identityModelStore!! .model.onesignalId,
317+ ),
285318 )
286- preferencesService!! .saveString(PreferenceStores .ONESIGNAL , PreferenceOneSignalKeys .PREFS_LEGACY_PLAYER_ID , null )
287319 }
288- } else {
289- Logging .debug(" initWithContext: using cached user ${identityModelStore!! .model.onesignalId} " )
290- operationRepo!! .enqueue(RefreshUserOperation (configModel!! .appId, identityModelStore!! .model.onesignalId))
291- }
292320
293- startupService!! .start()
321+ startupService!! .start()
294322
295- isInitialized = true
323+ isInitialized = true
296324
297- return true
325+ return true
326+ }
298327 }
299328
300329 override fun login (
@@ -304,7 +333,7 @@ internal class OneSignalImp : IOneSignal, IServiceProvider {
304333 Logging .log(LogLevel .DEBUG , " login(externalId: $externalId , jwtBearerToken: $jwtBearerToken )" )
305334
306335 if (! isInitialized) {
307- Logging .log( LogLevel . ERROR , " Must call 'initWithContext' before using Login " )
336+ throw Exception ( " Must call 'initWithContext' before 'login' " )
308337 }
309338
310339 var currentIdentityExternalId: String? = null
@@ -378,8 +407,7 @@ internal class OneSignalImp : IOneSignal, IServiceProvider {
378407 Logging .log(LogLevel .DEBUG , " logout()" )
379408
380409 if (! isInitialized) {
381- Logging .log(LogLevel .ERROR , " Must call 'initWithContext' before using Login" )
382- return
410+ throw Exception (" Must call 'initWithContext' before 'logout'" )
383411 }
384412
385413 // only allow one login/logout at a time
0 commit comments