Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions OneSignalSDK/detekt/detekt-baseline-core.xml
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@
<ID>PrintStackTrace:TrackGooglePurchase.kt$TrackGooglePurchase.&lt;no name provided>$t</ID>
<ID>RethrowCaughtException:OSDatabase.kt$OSDatabase$throw e</ID>
<ID>ReturnCount:AppIdResolution.kt$fun resolveAppId( inputAppId: String?, configModel: ConfigModel, preferencesService: IPreferencesService, ): AppIdResolution</ID>
<ID>ReturnCount:AppIdResolutionV2.kt$internal fun resolveAppIdV2( inputAppId: String?, configModel: ConfigModel, preferencesService: IPreferencesService, ): AppIdResolution</ID>
<ID>ReturnCount:BackgroundManager.kt$BackgroundManager$override fun cancelRunBackgroundServices(): Boolean</ID>
<ID>ReturnCount:ConfigModel.kt$ConfigModel$override fun createModelForProperty( property: String, jsonObject: JSONObject, ): Model?</ID>
<ID>ReturnCount:ExecutorsIvExtensions.kt$internal fun resolveIvBackendParams( op: Operation, onesignalId: String, jwtTokenStore: JwtTokenStore, ivBehaviorActive: Boolean, ): IvBackendParams</ID>
Expand All @@ -327,6 +328,8 @@
<ID>ReturnCount:Model.kt$Model$protected fun getOptIntProperty( name: String, create: (() -> Int?)? = null, ): Int?</ID>
<ID>ReturnCount:Model.kt$Model$protected fun getOptLongProperty( name: String, create: (() -> Long?)? = null, ): Long?</ID>
<ID>ReturnCount:Model.kt$Model$protected inline fun &lt;reified T : Enum&lt;T>> getOptEnumProperty(name: String): T?</ID>
<ID>ReturnCount:OneSignalImp.kt$OneSignalImp$override suspend fun initWithContextSuspend( context: Context?, appId: String?, ): Boolean</ID>
<ID>ReturnCount:OneSignalImpV2.kt$OneSignalImpV2$override suspend fun initWithContextSuspend( context: Context?, appId: String?, ): Boolean</ID>
<ID>ReturnCount:OperationModelStore.kt$OperationModelStore$override fun create(jsonObject: JSONObject?): Operation?</ID>
<ID>ReturnCount:OperationModelStore.kt$OperationModelStore$private fun isValidOperation(jsonObject: JSONObject): Boolean</ID>
<ID>ReturnCount:OperationRepo.kt$OperationRepo$private fun shouldSuppressAnonymousOp(op: Operation): Boolean</ID>
Expand Down Expand Up @@ -640,7 +643,5 @@
<ID>UnusedPrivateMember:OperationRepo.kt$OperationRepo$private val _time: ITime</ID>
<ID>UseCheckOrError:OneSignalImp.kt$OneSignalImp$throw IllegalStateException("'initWithContext failed' before 'updateUserJwt'")</ID>
<ID>UseCheckOrError:OneSignalImp.kt$OneSignalImp$throw initFailureException ?: IllegalStateException("Initialization failed. Cannot proceed.")</ID>
<ID>UseCheckOrError:OneSignalImpV2.kt$OneSignalImpV2$throw IllegalStateException("'initWithContext failed' before 'updateUserJwt'")</ID>
<ID>UseCheckOrError:OneSignalImpV2.kt$OneSignalImpV2$throw initFailureException ?: IllegalStateException("Initialization failed. Cannot proceed.")</ID>
</CurrentIssues>
</SmellBaseline>
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ interface IOneSignal {
val isInitialized: Boolean

/**
* The user manager for accessing user-scoped
* management.
* The user manager. Waits while init is running. Before init succeeds this is a stand-in:
* observers are attached once init succeeds, other calls are logged and ignored.
*/
val user: IUserManager

Expand Down Expand Up @@ -78,14 +78,16 @@ interface IOneSignal {
/**
* Initialize the OneSignal SDK. This should be called during startup of the application.
*
* @param context The Android context the SDK should use.
* @param appId The application ID the OneSignal SDK is bound to.
* @param context The Android context the SDK should use. Required: a null context is logged and init does not start.
* @param appId Your OneSignal app ID. Always pass it: a null or invalid value falls back to the app ID
* cached by an earlier launch, and with none cached init fails and logs.
*
* @return true if the SDK could be successfully initialized, false otherwise.
* @return true once initialization has started (or is already running or done), false for a
* null [context] or an immediate startup failure. Check [isInitialized] for the outcome.
*/
fun initWithContext(
context: Context,
appId: String,
context: Context?,
appId: String?,
): Boolean

/**
Expand All @@ -111,7 +113,7 @@ interface IOneSignal {
* subscriptions from the current user (if there is one) to the newly logged in user. This is
* because both Push and IAM are owned by the device.
*
* @param externalId The external ID of the user that is to be logged in.
* @param externalId The external ID of the user to log in. Must be non-empty: an empty value is ignored and logged.
* @param jwtBearerToken The optional JWT bearer token generated by your backend to establish
* trust for the login operation. Required when identity verification has been enabled. See
* [Identity Verification | OneSignal](https://documentation.onesignal.com/docs/identity-verification)
Expand All @@ -137,8 +139,8 @@ interface IOneSignal {
* [IUserJwtInvalidatedListener.onUserJwtInvalidated] callback). Stores the JWT and
* wakes the operation queue so any deferred ops can dispatch with the fresh token.
*
* @param externalId The external ID the JWT belongs to.
* @param token The new JWT bearer token issued by your backend.
* @param externalId The external ID the JWT belongs to. Must be non-empty.
* @param token The new JWT bearer token issued by your backend. Must be non-empty; empty values are ignored and logged.
*/
fun updateUserJwt(
externalId: String,
Expand All @@ -164,43 +166,44 @@ interface IOneSignal {
/**
* Initialize the OneSignal SDK, suspend until initialization is completed
*
* @param context The Android context the SDK should use.
* @param appId The application ID the OneSignal SDK is bound to.
* @param context The Android context the SDK should use. Required: a null context is logged and init does not start.
* @param appId Your OneSignal app ID. Always pass it: a null or invalid value falls back to the app ID
* cached by an earlier launch, and with none cached init fails and logs.
*
* @return true if the SDK could be successfully initialized, false otherwise.
*/
suspend fun initWithContextSuspend(
context: Context,
context: Context?,
appId: String? = null,
): Boolean

/**
* Get the session manager without blocking the calling thread.
* Suspends until the SDK is initialized.
* Suspends while initialization is in progress; if the SDK is not initialized, returns a stand-in (see [user]).
*/
suspend fun getSession(): ISessionManager

/**
* Get the notifications manager without blocking the calling thread.
* Suspends until the SDK is initialized.
* Suspends while initialization is in progress; if the SDK is not initialized, returns a stand-in (see [user]).
*/
suspend fun getNotifications(): INotificationsManager

/**
* Get the location manager without blocking the calling thread.
* Suspends until the SDK is initialized.
* Suspends while initialization is in progress; if the SDK is not initialized, returns a stand-in (see [user]).
*/
suspend fun getLocation(): ILocationManager

/**
* Get the in-app messages manager without blocking the calling thread.
* Suspends until the SDK is initialized.
* Suspends while initialization is in progress; if the SDK is not initialized, returns a stand-in (see [user]).
*/
suspend fun getInAppMessages(): IInAppMessagesManager

/**
* Get the user manager without blocking the calling thread.
* Suspends until the SDK is initialized.
* Suspends while initialization is in progress; if the SDK is not initialized, returns a stand-in (see [user]).
*/
suspend fun getUser(): IUserManager

Expand Down Expand Up @@ -240,7 +243,7 @@ interface IOneSignal {
* Login a user with external ID and optional JWT token (suspend version).
* Handles initialization automatically.
*
* @param externalId The external ID of the user that is to be logged in.
* @param externalId The external ID of the user to log in. Must be non-empty: an empty value is ignored and logged.
* @param jwtBearerToken The optional JWT bearer token generated by your backend to establish
* trust for the login operation. Required when identity verification has been enabled.
* See [Identity Verification | OneSignal](https://documentation.onesignal.com/docs/identity-verification)
Expand All @@ -253,6 +256,7 @@ interface IOneSignal {
/**
* Login with [externalId] plus [profile] as one Create User upsert (anonymous is not merged). Email/SMS create or transfer; a foreign alias fails it.
* Same id is a no-op once a backend ID exists. Backend failure leaves this identity local; INVALID_ARGUMENT and NOT_INITIALIZED change nothing.
* @param externalId Required: null or empty returns INVALID_ARGUMENT and changes nothing.
*/
suspend fun login(
externalId: String?,
Expand All @@ -266,11 +270,11 @@ interface IOneSignal {
suspend fun logoutSuspend()

/**
* Update the JWT bearer token associated with [externalId] (suspend version). Suspends
* until SDK initialization is complete, then stores the JWT and wakes the operation queue.
* Update the JWT bearer token associated with [externalId] (suspend version). Suspends while
* initialization is in progress, then stores the JWT; if the SDK is not initialized it logs instead.
*
* @param externalId The external ID the JWT belongs to.
* @param token The new JWT bearer token issued by your backend.
* @param externalId The external ID the JWT belongs to. Must be non-empty.
* @param token The new JWT bearer token issued by your backend. Must be non-empty; empty values are ignored and logged.
*/
suspend fun updateUserJwtSuspend(
externalId: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,41 +37,40 @@ object OneSignal {
get() = oneSignal.sdkVersion

/**
* The user manager for accessing user-scoped management. Initialized only after [initWithContext]
* has been called, and initialized with a device-scoped user until (or if) [login] has been
* called.
* The user manager, with a device-scoped user until (or if) [login] is called. Waits while init is running.
* Before [initWithContext] succeeds this is a stand-in: observers are attached once init succeeds, other calls are logged and ignored.
*/
@JvmStatic
val User: IUserManager
get() = oneSignal.user

/**
* The session manager for accessing session-scoped management. Initialized only after [initWithContext]
* has been called.
* The session manager for accessing session-scoped management.
* Before [initWithContext] succeeds this is a stand-in: outcome calls are logged and ignored.
*/
@JvmStatic
val Session: ISessionManager
get() = oneSignal.session

/**
* The notification manager for accessing device-scoped notification management. Initialized
* only after [initWithContext] has been called.
* The notification manager. Waits while init is running. Before [initWithContext] succeeds this is a stand-in:
* listeners and permission observers are attached once init succeeds, other calls are logged and ignored.
*/
@JvmStatic
val Notifications: INotificationsManager
get() = oneSignal.notifications

/**
* The location manager for accessing device-scoped location management. Initialized
* only after [initWithContext] has been called.
* The location manager. Waits while init is running. Before [initWithContext] succeeds this is a stand-in:
* a value set on `isShared` is applied once init succeeds, other calls are logged and ignored.
*/
@JvmStatic
val Location: ILocationManager
get() = oneSignal.location

/**
* The In App Messaging manager for accessing device-scoped IAP management. Initialized
* only after [initWithContext] has been called.
* The In App Messaging manager. Waits while init is running. Before [initWithContext] succeeds this is a stand-in:
* listeners and `paused` are applied once init succeeds, other calls are logged and ignored.
*/
@JvmStatic
val InAppMessages: IInAppMessagesManager
Expand Down Expand Up @@ -124,13 +123,14 @@ object OneSignal {
/**
* Initialize the OneSignal SDK. This should be called during startup of the application.
*
* @param context The Android context the SDK should use.
* @param appId The application ID the OneSignal SDK is bound to.
* @param context The Android context the SDK should use. Required: a null context is logged and init does not start.
* @param appId Your OneSignal app ID. Always pass it: a null or invalid value falls back to the app ID
* cached by an earlier launch, and with none cached init fails and logs. Check [isInitialized] for the outcome.
*/
@JvmStatic
fun initWithContext(
context: Context,
appId: String,
context: Context?,
appId: String?,
) {
oneSignal.initWithContext(context, appId)
}
Expand All @@ -140,13 +140,14 @@ object OneSignal {
* This method provides a suspended version that returns a boolean indicating success.
* Uses Dispatchers.IO internally to prevent ANRs and optimize for I/O operations.
*
* @param context Application context is recommended for SDK operations
* @param appId The application ID the OneSignal SDK is bound to.
* @param context Application context is recommended for SDK operations. Required: a null context is logged and init does not start.
* @param appId Your OneSignal app ID. Always pass it: a null or invalid value falls back to the app ID
* cached by an earlier launch, and with none cached init fails and logs.
* @return Boolean indicating if initialization was successful.
*/
@JvmStatic
suspend fun initWithContextSuspend(
context: Context,
context: Context?,
appId: String? = null,
): Boolean {
return oneSignal.initWithContextSuspend(context, appId)
Expand Down Expand Up @@ -302,7 +303,7 @@ object OneSignal {
* subscriptions from the current user (if there is one) to the newly logged in user. This is
* because both Push and IAM are owned by the device.
*
* @param externalId The external ID of the user that is to be logged in.
* @param externalId The external ID of the user to log in. Must be non-empty: an empty value is ignored and logged.
*/
@JvmStatic
fun login(externalId: String) = oneSignal.login(externalId)
Expand All @@ -323,7 +324,7 @@ object OneSignal {
* subscriptions from the current user (if there is one) to the newly logged in user. This is
* because both Push and IAM are owned by the device.
*
* @param externalId The external ID of the user that is to be logged in.
* @param externalId The external ID of the user to log in. Must be non-empty: an empty value is ignored and logged.
* @param jwtBearerToken The optional JWT bearer token generated by your backend to establish
* trust for the login operation. Required when identity verification has been enabled. See
* [Identity Verification | OneSignal](https://documentation.onesignal.com/docs/identity-verification)
Expand All @@ -349,8 +350,8 @@ object OneSignal {
* [IUserJwtInvalidatedListener.onUserJwtInvalidated] callback). Stores the JWT and
* wakes the operation queue so any deferred ops can dispatch with the fresh token.
*
* @param externalId The external ID the JWT belongs to.
* @param token The new JWT bearer token issued by your backend.
* @param externalId The external ID the JWT belongs to. Must be non-empty.
* @param token The new JWT bearer token issued by your backend. Must be non-empty; empty values are ignored and logged.
*/
@JvmStatic
fun updateUserJwt(
Expand Down Expand Up @@ -412,7 +413,7 @@ object OneSignal {
* subscriptions from the current user (if there is one) to the newly logged in user. This is
* because both Push and IAM are owned by the device.
*
* @param externalId The external ID of the user that is to be logged in.
* @param externalId The external ID of the user to log in. Must be non-empty: an empty value is ignored and logged.
* @param jwtBearerToken The optional JWT bearer token generated by your backend to establish
* trust for the login operation. Required when identity verification has been enabled. See
* [Identity Verification | OneSignal](https://documentation.onesignal.com/docs/identity-verification)
Expand All @@ -428,6 +429,7 @@ object OneSignal {
/**
* Login with [externalId] plus [profile] as one Create User upsert (anonymous is not merged). Email/SMS create or transfer; a foreign alias fails it.
* Same id is a no-op once a backend ID exists. Backend failure leaves this identity local; INVALID_ARGUMENT and NOT_INITIALIZED change nothing.
* @param externalId Required: null or empty returns INVALID_ARGUMENT and changes nothing.
*/
@JvmStatic
@JvmOverloads
Expand Down Expand Up @@ -455,8 +457,8 @@ object OneSignal {
* Update the JWT bearer token associated with [externalId] without blocking the calling
* thread. Suspend-safe version of [updateUserJwt].
*
* @param externalId The external ID the JWT belongs to.
* @param token The new JWT bearer token issued by your backend.
* @param externalId The external ID the JWT belongs to. Must be non-empty.
* @param token The new JWT bearer token issued by your backend. Must be non-empty; empty values are ignored and logged.
*/
@JvmStatic
suspend fun updateUserJwtSuspend(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,16 @@ import com.onesignal.debug.internal.logging.Logging
internal class StartupService(
private val services: ServiceProvider,
) {
private val bootstrapped = mutableSetOf<IBootstrapService>()

// Retryable after a failure: services that already bootstrapped are skipped, so none subscribes twice.
fun bootstrap() {
services.getAllServices<IBootstrapService>().forEach { it.bootstrap() }
services.getAllServices<IBootstrapService>().forEach {
if (it !in bootstrapped) {
it.bootstrap()
bootstrapped += it
}
}
}

// schedule to start all startable services using OneSignal dispatcher
Expand Down
Loading
Loading