From cc708aa8f1783fac34a46cd2ee0ba7ceed4c53ef Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Tue, 26 Mar 2024 20:38:27 -0400 Subject: [PATCH 1/2] only fetch IAMs if app is in the foreground We want to prevent wasted resources polling for IAMs durning times where it is unlikely they will be seen. Two changes are being made; 1. ensure we only poll when the isInForeground is true. 2. poll the first time the app is foregrounded, incase it is not when the SDK is initialized. --- .../internal/InAppMessagesManager.kt | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessagesManager.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessagesManager.kt index 2f1f46d88d..978fb6ab2a 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessagesManager.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessagesManager.kt @@ -9,6 +9,7 @@ import com.onesignal.common.exceptions.BackendException import com.onesignal.common.modeling.ISingletonModelStoreChangeHandler import com.onesignal.common.modeling.ModelChangedArgs import com.onesignal.common.threading.suspendifyOnThread +import com.onesignal.core.internal.application.IApplicationLifecycleHandler import com.onesignal.core.internal.application.IApplicationService import com.onesignal.core.internal.config.ConfigModel import com.onesignal.core.internal.config.ConfigModelStore @@ -71,7 +72,8 @@ internal class InAppMessagesManager( ISingletonModelStoreChangeHandler, IInAppLifecycleEventHandler, ITriggerHandler, - ISessionLifecycleHandler { + ISessionLifecycleHandler, + IApplicationLifecycleHandler { private val lifecycleCallback = EventProducer() private val messageClickCallback = EventProducer() @@ -133,6 +135,7 @@ internal class InAppMessagesManager( _lifecycle.subscribe(this) _triggerController.subscribe(this) _sessionService.subscribe(this) + _applicationService.addApplicationLifecycleHandler(this) suspendifyOnThread { _repository.cleanCachedInAppMessages() @@ -225,6 +228,14 @@ internal class InAppMessagesManager( // called when a new push subscription is added, or the app id is updated, or a new session starts private suspend fun fetchMessages() { + // We only want to fetch IAMs if we know the app is in the + // foreground, as we don't want to do this for background + // events (such as push received), wasting resources for + // IAMs that are never shown. + if (!_applicationService.isInForeground) { + return + } + val appId = _configModelStore.model.appId val subscriptionId = _subscriptionManager.subscriptions.push.id @@ -869,4 +880,16 @@ internal class InAppMessagesManager( .setPositiveButton(android.R.string.ok) { _, _ -> suspendifyOnThread { showMultiplePrompts(inAppMessage, prompts) } } .show() } + + private var onFocusCalled: Boolean = false + + override fun onFocus() { + if (onFocusCalled) return + onFocusCalled = true + suspendifyOnThread { + fetchMessages() + } + } + + override fun onUnfocused() { } } From 3b852963d000696b8ffbc07421fa5d11496fc2f9 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Tue, 26 Mar 2024 21:32:18 -0400 Subject: [PATCH 2/2] only refresh User when app is foregrounded Ensure cache for the user is refreshed once per cold start when app is in the foreground. This saves resources as there are a number of events (such as push received or non-OneSignal events) that start the app in the background but will never read/write any user properties. --- .../com/onesignal/internal/OneSignalImp.kt | 6 --- .../java/com/onesignal/user/UserModule.kt | 4 ++ .../internal/service/UserRefreshService.kt | 49 +++++++++++++++++++ 3 files changed, 53 insertions(+), 6 deletions(-) create mode 100644 OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/service/UserRefreshService.kt diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/internal/OneSignalImp.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/internal/OneSignalImp.kt index 53877bf80b..15fa601abb 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/internal/OneSignalImp.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/internal/OneSignalImp.kt @@ -323,12 +323,6 @@ internal class OneSignalImp : IOneSignal, IServiceProvider { } } else { Logging.debug("initWithContext: using cached user ${identityModelStore!!.model.onesignalId}") - operationRepo!!.enqueue( - RefreshUserOperation( - configModel!!.appId, - identityModelStore!!.model.onesignalId, - ), - ) } startupService!!.start() diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/UserModule.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/UserModule.kt index 996b37178f..f371e6d391 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/UserModule.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/UserModule.kt @@ -4,6 +4,7 @@ import com.onesignal.common.modules.IModule import com.onesignal.common.services.ServiceBuilder import com.onesignal.core.internal.operations.IOperationExecutor import com.onesignal.core.internal.startup.IBootstrapService +import com.onesignal.core.internal.startup.IStartableService import com.onesignal.user.internal.UserManager import com.onesignal.user.internal.backend.IIdentityBackendService import com.onesignal.user.internal.backend.ISubscriptionBackendService @@ -24,6 +25,7 @@ import com.onesignal.user.internal.operations.impl.listeners.IdentityModelStoreL import com.onesignal.user.internal.operations.impl.listeners.PropertiesModelStoreListener import com.onesignal.user.internal.operations.impl.listeners.SubscriptionModelStoreListener import com.onesignal.user.internal.properties.PropertiesModelStore +import com.onesignal.user.internal.service.UserRefreshService import com.onesignal.user.internal.subscriptions.ISubscriptionManager import com.onesignal.user.internal.subscriptions.SubscriptionModelStore import com.onesignal.user.internal.subscriptions.impl.SubscriptionManager @@ -61,5 +63,7 @@ internal class UserModule : IModule { builder.register().provides() builder.register().provides() builder.register().provides() + + builder.register().provides() } } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/service/UserRefreshService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/service/UserRefreshService.kt new file mode 100644 index 0000000000..b2371d3214 --- /dev/null +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/service/UserRefreshService.kt @@ -0,0 +1,49 @@ +package com.onesignal.user.internal.service + +import com.onesignal.core.internal.application.IApplicationLifecycleHandler +import com.onesignal.core.internal.application.IApplicationService +import com.onesignal.core.internal.config.ConfigModelStore +import com.onesignal.core.internal.operations.IOperationRepo +import com.onesignal.core.internal.startup.IStartableService +import com.onesignal.user.internal.identity.IdentityModelStore +import com.onesignal.user.internal.operations.RefreshUserOperation + +// Ensure cache for the user is refreshed once per cold start when app +// is in the foreground. This saves resources as there are a number of +// events (such as push received or non-OneSignal events) that start +// the app in the background but will never read/write any user +// properties. +class UserRefreshService( + private val _applicationService: IApplicationService, + private val _operationRepo: IOperationRepo, + private val _configModelStore: ConfigModelStore, + private val _identityModelStore: IdentityModelStore, +) : IStartableService, + IApplicationLifecycleHandler { + private fun refreshUser() { + _operationRepo.enqueue( + RefreshUserOperation( + _configModelStore.model.appId, + _identityModelStore.model.onesignalId, + ), + ) + } + + override fun start() { + if (_applicationService.isInForeground) { + refreshUser() + } else { + _applicationService.addApplicationLifecycleHandler(this) + } + } + + private var onFocusCalled: Boolean = false + + override fun onFocus() { + if (onFocusCalled) return + onFocusCalled = true + refreshUser() + } + + override fun onUnfocused() { } +}