Skip to content

Commit 2f114f2

Browse files
jinliu9508AR Abdul Azeez
andcommitted
Improvement: failure message shows that appID is missing (#2506)
Co-authored-by: AR Abdul Azeez <[email protected]>
1 parent 5a806e6 commit 2f114f2

File tree

2 files changed

+35
-27
lines changed

2 files changed

+35
-27
lines changed

OneSignalSDK/onesignal/core/src/main/java/com/onesignal/internal/OneSignalImp.kt

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ internal class OneSignalImp(
5252
@Volatile
5353
private var initState: InitState = InitState.NOT_STARTED
5454

55+
// Save the exception pointing to the caller that triggered init, not the async worker thread.
56+
private var initFailureException: Exception? = null
57+
5558
override val sdkVersion: String = OneSignalUtils.sdkVersion
5659

5760
override val isInitialized: Boolean
@@ -279,7 +282,11 @@ internal class OneSignalImp(
279282
val startupService = bootstrapServices()
280283
val result = resolveAppId(appId, configModel, preferencesService)
281284
if (result.failed) {
282-
Logging.warn("suspendInitInternal: no appId provided or found in legacy config.")
285+
val message = "suspendInitInternal: no appId provided or found in local storage. Please pass a valid appId to initWithContext()."
286+
val exception = IllegalStateException(message)
287+
// attach the real crash cause to the init failure exception that will be throw shortly after
288+
initFailureException?.addSuppressed(exception)
289+
Logging.warn(message)
283290
initState = InitState.FAILED
284291
notifyInitComplete()
285292
return false
@@ -395,12 +402,12 @@ internal class OneSignalImp(
395402

396403
// Re-check state after waiting - init might have failed during the wait
397404
if (initState == InitState.FAILED) {
398-
throw IllegalStateException("Initialization failed. Cannot proceed.")
405+
throw initFailureException ?: IllegalStateException("Initialization failed. Cannot proceed.")
399406
}
400407
// initState is guaranteed to be SUCCESS here - consistent state
401408
}
402409
InitState.FAILED -> {
403-
throw IllegalStateException("Initialization failed. Cannot proceed.")
410+
throw initFailureException ?: IllegalStateException("Initialization failed. Cannot proceed.")
404411
}
405412
else -> {
406413
// SUCCESS - already initialized, no need to wait
@@ -506,6 +513,9 @@ internal class OneSignalImp(
506513
): Boolean {
507514
Logging.log(LogLevel.DEBUG, "initWithContext(context: $context, appId: $appId)")
508515

516+
// This ensures the stack trace points to the caller that triggered init, not the async worker thread.
517+
initFailureException = IllegalStateException("OneSignal initWithContext failed.")
518+
509519
// Use IO dispatcher for initialization to prevent ANRs and optimize for I/O operations
510520
return withContext(ioDispatcher) {
511521
// do not do this again if already initialized or init is in progress

OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/application/SDKInitTests.kt

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -37,20 +37,6 @@ class SDKInitTests : FunSpec({
3737

3838
beforeAny {
3939
Logging.logLevel = LogLevel.NONE
40-
41-
// Aggressive pre-test cleanup to avoid state leakage across tests
42-
val context = getApplicationContext<Context>()
43-
val prefs = context.getSharedPreferences("OneSignal", Context.MODE_PRIVATE)
44-
prefs.edit()
45-
.clear()
46-
.commit()
47-
48-
val otherPrefs = context.getSharedPreferences("com.onesignal", Context.MODE_PRIVATE)
49-
otherPrefs.edit()
50-
.clear()
51-
.commit()
52-
53-
Thread.sleep(100)
5440
}
5541

5642
afterAny {
@@ -65,19 +51,31 @@ class SDKInitTests : FunSpec({
6551
otherPrefs.edit()
6652
.clear()
6753
.commit()
54+
}
6855

69-
// Wait longer to ensure cleanup is complete
70-
Thread.sleep(100)
56+
test("accessor instances after initWithContext without appID shows the failure reason") {
57+
// Given
58+
val context = getApplicationContext<Context>()
59+
val os = OneSignalImp()
7160

72-
// Clear any in-memory state by initializing and logging out a fresh instance
73-
try {
74-
val os = OneSignalImp()
75-
os.initWithContext(context, "appId")
76-
os.logout()
77-
Thread.sleep(100)
78-
} catch (ignored: Exception) {
79-
// ignore cleanup exceptions
61+
// When
62+
os.initWithContext(context)
63+
64+
// Then
65+
val ex = shouldThrow<IllegalStateException> {
66+
os.user.onesignalId // Should trigger waitUntilInitInternal → throw failure message
8067
}
68+
// The main exception preserves the caller's stack trace
69+
ex.message shouldBe "OneSignal initWithContext failed."
70+
// The detailed failure reason is in the suppressed exception
71+
ex.suppressed.size shouldBe 1
72+
ex.suppressed[0].message shouldBe "suspendInitInternal: no appId provided or found in local storage. Please pass a valid appId to initWithContext()."
73+
74+
// Calling initWithContext with an appID after the failure should not throw anymore
75+
val result = os.initWithContext(context, "appID")
76+
waitForInitialization(os)
77+
result shouldBe true
78+
os.isInitialized shouldBe true
8179
}
8280

8381
test("OneSignal accessors throw before calling initWithContext") {

0 commit comments

Comments
 (0)