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