Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
adam1929 committed Mar 28, 2024
2 parents bf48aba + 970917f commit 59888a1
Show file tree
Hide file tree
Showing 45 changed files with 2,224 additions and 534 deletions.
2 changes: 1 addition & 1 deletion Documentation/APP_INBOX.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ override fun getAppInboxListFragment(context: Context): Fragment {
### Building App Inbox detail View

Method `getAppInboxDetailView(Context, String)` is used to build a `android.view.View` to show an App Inbox message detail. All data handling has to be done here (fetching, showing data, action listeners...).
Default implementation builds a simple View that shows data by multiple `android.widget.TextView`s and `com.exponea.sdk.view.SquareImageView`, whole layout wrapped by `android.widget.ScrollView`.
Default implementation builds a simple View that shows data by multiple `android.widget.TextView`s and `android.widget.ImageView`, whole layout wrapped by `android.widget.ScrollView`.
App Inbox message actions are shown and invoked by multiple `android.widget.Button`s.
To override this behavior you are able to write own method:

Expand Down
83 changes: 61 additions & 22 deletions Documentation/IN_APP_MESSAGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,46 +7,70 @@ No developer work is required for in-app messages; they work automatically after
As with everything that's supposed to work automatically, the biggest problem is what to do when it doesn't.

### Logging
The SDK logs a lot of useful information about presenting in-app messages on the default `INFO` level. To see why each message was/wasn't displayed, make sure your logger level is most `INFO`. You can set the logger level using `Exponea.loggerLevel = Logger.Level.DEBUG` before initializing the SDK.
The SDK logs a lot of useful information about presenting in-app messages on the default `INFO` level. To see why each message was/wasn't displayed, make sure your logger level is most `INFO`. You can set the logger level using `Exponea.loggerLevel = Logger.Level.INFO` before initializing the SDK.
If you are facing any unexpected behaviour and `INFO` logs are not sufficient enough, try to set log level do `VERBOSE` to got more detailed information.

> Note: All logs assigned to In-app handling process are prefixed with `[InApp]` shortcut to bring easier search-ability to you. Bear in mind that some supporting processes (such as Image caching) are logging without this prefix.
### Example logs

Let's look at an example of how the logs may look when displaying an in-app message.
1. ```
In-app message data preloaded, picking a message to display
Event {eventCategory}:{eventType} occurred, going to trigger In-app show process
```
In-app process has been triggered by SDK usage of identifyCustomer() or event tracking.
1. ```
Register request for in-app message to be shown for $eventType
```
In-app message definitions must be preloaded in order to display the message. If the preload is still in progress, we store the events until preload is complete and perform the message picking logic afterward.

Each non-null `eventType` registers a 'show request' to show an In-app message after whole process is done.
1. ```
[In-app message data preloaded. ]Picking a message to display
```
In-app show process starts successfully and messages are prepared to be selected and shown. Log message `In-app message data preloaded.` means that In-app message definitions preload has to be done here.
2. ```
Picking in-app message for eventType payment. 2 messages available: [App load in-app message, Payment in-app message].
Picking in-app message for eventType {eventType}. {X} messages available: [{message1 name}, {message2 name}, ...].
```
This log contains the list of **all** message names we received from the server. If you don't see your message here, double-check the setup on the Exponea web application. Make sure your targeting includes the current customer.

This log contains `eventType` for which the messages going to be searched. Then count of `X` messages and the names of **all** messages received from the server is listed in log.
3. ```
Message 'App load in-app message' failed event filter. Message filter: {"event_type":"session_start","filter":[]} Event type: payment properties: {price=2011.1, product_title=Item #1} timestamp: 1.59921557821E9
Message '{message name}' failed event filter. Message filter: {"event_type":"session_start","filter":[]} Event type: payment properties: {price=2011.1, product_title=Item #1} timestamp: 1.59921557821E9
```
We show reasons why some messages are not picked. In this example, message failed event filter - the type was set for `session_start`, but `payment` was tracked.
3. ```
{X} messages available after filtering. Going to pick the highest priority messages.
```
Log informs that `X` messages match all requirements given by own filter. Filter could be configured on Bloomreach engagement app for each message. See `Schedule`, `Show on` and `Display` in In-app message settings.
4. ```
1 messages available after filtering. Picking the highest priority message.
```
After applying all the filters, we have one message left. You can set priority on your messages. The highest priority message should be displayed.
5. ```
Got 1 messages with highest priority. [Payment in-app message]
```
There may be a tie between a few messages with the same priority. In that case, we pick one at random.
Got {X} messages with highest priority for eventType {eventType}. [{message1 name}, {message2 name}, ...]
```
There may be a tie between a few messages with the same priority. All messages with same highest priority are listed.
6. ```
Attempting to show in-app message 'Payment in-app message'
```
The message picked for displaying was `Payment in-app message`
Picking top message '{message name}' for eventType {eventType}
```
The single message is randomly picked from filtered messages with same highest priority for `eventType`
7. ```
Got {X} messages available to show. [{message1 name}, {message2 name}, ...].
```
All `X` messages has been collected for registered 'show requests'. Process continues with selecting of message with highest priority.
8. ```
Posting show to the main thread with delay 0ms.
```
Message display request is posted to the main thread, where it will be displayed in the last resumed Activity.
Picking top message '{message name}' to be shown.
```
The single message is randomly picked from all filtered messages. This message is going to be shown to user.
9. ```
Only logging in-app message for control group '${message.name}'
```
A/B testing In-app message or message without payload is not shown to user but 'show' event is tracked for your analysis.
6. ```
Attempting to show in-app message '{message name}'
```
In-app message that meant to be show to user (not A/B testing) is going to be shown
7. ```
Posting show to main thread with delay {X}ms.
```
Message display request is posted to the main thread with delay of `X` milliseconds. Delay is configured by `Display delay` in In-app message settings. Message will be displayed in the last resumed Activity.
8. ```
Attempting to present in-app message.
```
Called from the main thread, if a failure happens after this point, please check next section about `Displaying in-app messages`.
10. ```
9. ```
In-app message presented.
```
Everything went well, and you should see your message. It was presented in the current Activity. In case you don't see the message, it's possible that the view hierarchy has changed, and the message is no longer on screen.
Expand Down Expand Up @@ -80,6 +104,21 @@ It is common behaviour that if you change an In-app message data on platform the

> Note: Invoking of `Exponea.anonymize` does fetch In-apps immediately but `Exponea.identifyCustomer` needs to be sent to backend successfully. The reason is to register customer IDs on backend properly to correctly assign an In-app messages. If you have set other then `Exponea.flushMode = FlushMode.IMMEDIATE` you need to call `Exponea.flushData()` to finalize `identifyCustomer` process and trigger a In-app messages fetch.
### In-app messages tracking

In-app messages are tracked automatically by SDK. You may see these `action` values in customers tracked events:

- 'show' - event is tracked if message has been shown to user
- 'click' - event is tracked if user clicked on action button inside message. Event contains 'text' and 'link' properties that you might be interested in
- 'close' - event is tracked if user clicked on button with close action inside message or message has been dismissed automatically by defined 'Closing timeout'
- 'error' - event is tracked if showing of message has failed. Event contains 'error' property with meaningful description

The behaviour of In-app messages tracking may be affected by the tracking consent feature, which in enabled mode considers the requirement of explicit consent for tracking. Read more in [tracking consent documentation](./TRACKING_CONSENT.md).
Tracking of 'show' and 'error' event is done by SDK and behaviour cannot be overridden. These events are tracked only if:

* Tracking consent feature is disabled
* Tracking consent feature is enabled and 'hasTrackingConsent' has 'true' value

### Custom in-app message actions
If you want to override default SDK behavior, when in-app message action is performed (button is clicked, a message is closed), or you want to add your code to be performed along with code executed by the SDK, you can set up `inAppMessageActionCallback` on Exponea instance.

Expand Down
12 changes: 12 additions & 0 deletions Documentation/RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
## :arrow_double_up: [SDK version update guide](./../Guides/VERSION_UPDATE.md)

## Release Notes
## Release Notes for 3.12.0
#### March 28, 2024
* Features
* In-app message load refactoring (show on the first load etc.)
* In-app message documentation extended with tracking and consent information
* Bug Fixes
* Fixed: NotificationChannel is not registered after autobackup and app reinstall
* Fixed: Config for automaticPushNotification is not stored locally
* Fixed: Image for App Inbox "PUSH" message detail is not shown correctly
* Fixed: PUSH token tracking event is not consider allowDefaultCustomerProperties flag


## Release Notes for 3.11.2
#### January 11, 2024
* Bug Fixes
Expand Down
2 changes: 1 addition & 1 deletion Guides/INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
2. Add ExponeaSDK dependency and sync your project
```groovy
dependencies {
implementation 'com.exponea.sdk:sdk:3.11.2'
implementation 'com.exponea.sdk:sdk:3.12.0'
}
```
3. After synchronization is complete, you can start using the SDK.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Download via Gradle:

```groovy
dependencies {
implementation 'com.exponea.sdk:sdk:3.11.2'
implementation 'com.exponea.sdk:sdk:3.12.0'
}
```

Expand All @@ -32,7 +32,7 @@ Download via Maven:
<dependency>
<groupId>com.exponea.sdk</groupId>
<artifactId>sdk</artifactId>
<version>3.11.2</version>
<version>3.12.0</version>
</dependency>
```

Expand Down
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ android {
applicationId "com.exponea.example"
minSdkVersion 21
targetSdkVersion 33
versionCode 78
versionName "3.11.2"
versionCode 79
versionName "3.12.0"
vectorDrawables.useSupportLibrary = true
}
compileOptions {
Expand Down
4 changes: 2 additions & 2 deletions sdk/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ android {
defaultConfig {
minSdkVersion 17
targetSdkVersion 33
buildConfigField "String", "EXPONEA_VERSION_NAME", '"3.11.2"'
buildConfigField "int", "EXPONEA_VERSION_CODE", "73"
buildConfigField "String", "EXPONEA_VERSION_NAME", '"3.12.0"'
buildConfigField "int", "EXPONEA_VERSION_CODE", "74"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'proguard-rules.pro'
}
Expand Down
100 changes: 100 additions & 0 deletions sdk/schemas/com.exponea.sdk.database.ExponeaDatabase/2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
{
"formatVersion": 1,
"database": {
"version": 2,
"identityHash": "2497c79b4842963dfb14882f555b01a3",
"entities": [
{
"tableName": "exported_event",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `tries` INTEGER NOT NULL, `project_id` TEXT NOT NULL, `route` TEXT, `should_be_skipped` INTEGER NOT NULL, `exponea_project` TEXT, `event_type` TEXT, `timestamp` REAL, `age` REAL, `customer_ids` TEXT, `properties` TEXT, `sdk_event_type` TEXT, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "tries",
"columnName": "tries",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "projectId",
"columnName": "project_id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "route",
"columnName": "route",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "shouldBeSkipped",
"columnName": "should_be_skipped",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "exponeaProject",
"columnName": "exponea_project",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "type",
"columnName": "event_type",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "timestamp",
"columnName": "timestamp",
"affinity": "REAL",
"notNull": false
},
{
"fieldPath": "age",
"columnName": "age",
"affinity": "REAL",
"notNull": false
},
{
"fieldPath": "customerIds",
"columnName": "customer_ids",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "properties",
"columnName": "properties",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "sdkEventType",
"columnName": "sdk_event_type",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '2497c79b4842963dfb14882f555b01a3')"
]
}
}
9 changes: 5 additions & 4 deletions sdk/src/main/java/com/exponea/sdk/Exponea.kt
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ object Exponea {
}
set(value) = runCatching {
configuration.sessionTimeout = value
ExponeaConfigRepository.set(application, configuration)
}.logOnException()

/**
Expand All @@ -136,6 +137,7 @@ object Exponea {
}
set(value) = runCatching {
configuration.automaticSessionTracking = value
ExponeaConfigRepository.set(application, configuration)
startSessionTracking(value)
}.logOnException()

Expand All @@ -156,6 +158,7 @@ object Exponea {
}
set(value) = runCatching {
configuration.automaticPushNotification = value
ExponeaConfigRepository.set(application, configuration)
}.logOnException()

/**
Expand Down Expand Up @@ -220,6 +223,7 @@ object Exponea {
}
set(value) = runCatching {
configuration.campaignTTL = value
ExponeaConfigRepository.set(application, configuration)
}.logOnException()

/**
Expand All @@ -232,6 +236,7 @@ object Exponea {
}.returnOnException { hashMapOf() }
set(value) = runCatching {
configuration.defaultProperties = value
ExponeaConfigRepository.set(application, configuration)
}.logOnException()

/**
Expand Down Expand Up @@ -913,10 +918,6 @@ object Exponea {
return false
}
val campaignData = CampaignData(intent!!.data!!)
if (!campaignData.isValid()) {
Logger.w(this, "Intent doesn't contain a valid Campaign info in Uri: ${intent.data}")
return false
}
val campaingManager = getCampaingManager(appContext)
if (campaingManager != null) {
campaingManager.trackCampaignClick(campaignData)
Expand Down
11 changes: 5 additions & 6 deletions sdk/src/main/java/com/exponea/sdk/ExponeaComponent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,9 @@ internal class ExponeaComponent(
eventRepository,
exponeaService,
connectionManager,
// once customer is identified(and potentially merged with another), refresh the in-app messages
{ inAppMessageManager.preload() }
onEventUploaded = { uploadedEvent ->
inAppMessageManager.onEventUploaded(uploadedEvent)
}
)

internal val eventManager: EventManager = EventManagerImpl(
Expand Down Expand Up @@ -203,7 +204,6 @@ internal class ExponeaComponent(
)

internal val inAppMessageManager: InAppMessageManager = InAppMessageManagerImpl(
exponeaConfiguration,
customerIdsRepository,
inAppMessagesCache,
fetchManager,
Expand Down Expand Up @@ -248,8 +248,7 @@ internal class ExponeaComponent(
fcmManager.trackToken(" ", ExponeaConfiguration.TokenFrequency.EVERY_LAUNCH, TokenType.HMS)
deviceInitiatedRepository.set(false)
campaignRepository.clear()
inAppMessagesCache.clear()
inAppMessageDisplayStateRepository.clear()
inAppMessageManager.clear()
uniqueIdentifierRepository.clear()
customerIdsRepository.clear()
inAppContentBlockManager.clearAll()
Expand All @@ -270,7 +269,7 @@ internal class ExponeaComponent(
}
// Do not use TokenFrequency from the configuration, setup token from new customer immediately during anonymize
fcmManager.trackToken(token, ExponeaConfiguration.TokenFrequency.EVERY_LAUNCH, tokenType)
inAppMessageManager.preload()
inAppMessageManager.reload()
appInboxManager.reload()
inAppContentBlockManager.loadInAppContentBlockPlaceholders()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import com.exponea.sdk.models.ExportedEvent

@Database(entities = [ExportedEvent::class], version = 1)
@Database(entities = [ExportedEvent::class], version = 2)
@TypeConverters(Converters::class)
internal abstract class ExponeaDatabase : RoomDatabase() {

Expand Down
Loading

0 comments on commit 59888a1

Please sign in to comment.