Skip to content

Commit

Permalink
feat: Changed setAttribute to send map instead of key-value pair
Browse files Browse the repository at this point in the history
  • Loading branch information
Swapnil Chaudhari committed Feb 14, 2025
1 parent db371ec commit 6183c50
Show file tree
Hide file tree
Showing 9 changed files with 88 additions and 96 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,17 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

[1.3.0] - 2024-02-07
[1.3.0] - 2025-02-14

### Added

- Added support for FME-MI sdk linking
- added support to use salt for bucketing if provided in the rule.

### Changed

- Changed setAttribute to send map instead of key-value pair

## [1.2.0] - 2025-01-30

### Added
Expand Down
9 changes: 6 additions & 3 deletions app/src/main/java/com/vwo/fme/JavaMainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,12 @@ private void track() {

private void sendAttribute() {
if (vwo != null) {
vwo.setAttribute("userType", "paid", userContext);
vwo.setAttribute("attribute-name-float", 1.01, userContext);
vwo.setAttribute("attribute-name-boolean", true, userContext);
HashMap<String, Object> map = new HashMap<>();
map.put("userType", "paid");
map.put("price", 99);
map.put("isEnterpriseCustomer", true);

vwo.setAttribute(map, userContext);
}
}
}
13 changes: 8 additions & 5 deletions app/src/main/java/com/vwo/fme/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ class MainActivity : AppCompatActivity() {
binding.btnInitSdk.setOnClickListener {
// Initialize VWO SDK
val vwoInitOptions = VWOInitOptions()
vwoInitOptions.batchMinSize = 10
vwoInitOptions.batchUploadTimeInterval = 5 * 60 * 1000
/*vwoInitOptions.batchMinSize = 10
vwoInitOptions.batchUploadTimeInterval = 5 * 60 * 1000*/
val integrations = object : IntegrationCallback {
override fun execute(properties: Map<String, Any>) {
// your function definition
Expand Down Expand Up @@ -215,9 +215,12 @@ class MainActivity : AppCompatActivity() {
private fun sendAttribute() {
if (!::userContext.isInitialized) return

vwo?.setAttribute(server.attributeName, "attribute-value1", userContext)
vwo?.setAttribute("attribute-name-float", 1.01, userContext)
vwo?.setAttribute("attribute-name-boolean", true, userContext)
val attributes = mapOf(
server.attributeName to "paid",
"price" to 99,
"isEnterpriseCustomer" to false
)
vwo?.setAttribute(attributes, userContext)
}
}

Expand Down
4 changes: 3 additions & 1 deletion fme-android/src/main/assets/warn-messages.json
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
{}
{
"ATTRIBUTES_NOT_FOUND": "{key} passed to the {apiName} API is empty. Please provide {expectedFormat}."
}
7 changes: 3 additions & 4 deletions fme-android/src/main/java/com/vwo/VWO.kt
Original file line number Diff line number Diff line change
Expand Up @@ -158,12 +158,11 @@ object VWO {
/**
* Sets an attribute for a user in the context provided.
* This method validates the types of the inputs before proceeding with the API call.
* @param attributeKey - The key of the attribute to set.
* @param attributeValue - The value of the attribute to set.
* @param attributes - Map of attribute key and value to be set
* @param context User context
*/
fun setAttribute(attributeKey: String, attributeValue: Any, context: VWOContext) {
vwoClient?.setAttribute(attributeKey, attributeValue, context)
fun setAttribute(attributes: Map<String, Any>, context: VWOContext) {
vwoClient?.setAttribute(attributes, context)
}
}

103 changes: 47 additions & 56 deletions fme-android/src/main/java/com/vwo/VWOClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ import android.content.Context
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.ObjectMapper
import com.vwo.api.GetFlagAPI
import com.vwo.api.SetAttributeAPI
import com.vwo.api.SetAttributeAPI.setAttribute
import com.vwo.api.TrackEventAPI
import com.vwo.interfaces.IVwoListener
import com.vwo.models.Settings
import com.vwo.models.schemas.SettingsSchema
import com.vwo.models.user.GetFlag
Expand All @@ -31,7 +30,7 @@ import com.vwo.packages.logger.enums.LogLevelEnum
import com.vwo.services.HooksManager
import com.vwo.services.LoggerService
import com.vwo.services.UrlService
import com.vwo.utils.DataTypeUtil
import com.vwo.utils.DataTypeUtil.getType
import com.vwo.utils.DataTypeUtil.isBoolean
import com.vwo.utils.DataTypeUtil.isNumber
import com.vwo.utils.DataTypeUtil.isString
Expand Down Expand Up @@ -173,7 +172,7 @@ class VWOClient(settings: String?, options: VWOInitOptions?) {
init {
put("apiName", apiName)
put("key", "eventName")
put("type", DataTypeUtil.getType(eventName))
put("type", getType(eventName))
put("correctType", "String")
}
})
Expand Down Expand Up @@ -248,73 +247,65 @@ class VWOClient(settings: String?, options: VWOInitOptions?) {
/**
* Sets an attribute for a user in the context provided.
* This method validates the types of the inputs before proceeding with the API call.
* @param attributeKey - The key of the attribute to set.
* @param attributeValue - The value of the attribute to set.
* @param attributes - Map of attribute key and value to be set
* @param context User context
*/
fun setAttribute(attributeKey: String, attributeValue: Any, context: VWOContext?) {
fun setAttribute(immutableAttributes: Map<String, Any>, context: VWOContext) {
val apiName = "setAttribute"
try {
LoggerService.log(
LogLevelEnum.DEBUG,
"API_CALLED",
object : HashMap<String?, String?>() {
init {
put("apiName", apiName)
}
})
if (!isString(attributeKey)) {
LoggerService.log(
LogLevelEnum.ERROR,
"API_INVALID_PARAM",
object : HashMap<String?, String?>() {
init {
put("apiName", apiName)
put("key", "eventName")
put("type", DataTypeUtil.getType(attributeKey))
put("correctType", "String")
}
})
throw IllegalArgumentException("TypeError: attributeKey should be a string")
}
LoggerService.log(LogLevelEnum.DEBUG, "API_CALLED", mapOf("apiName" to apiName))

val attributes = immutableAttributes.toMutableMap()

if (!isString(attributeValue) && !isNumber(attributeValue) && !isBoolean(attributeValue)) {
if (attributes.isEmpty()) {
LoggerService.log(
LogLevelEnum.ERROR,
"API_INVALID_PARAM",
object : HashMap<String?, String?>() {
init {
put("apiName", apiName)
put("key", "eventName")
put("type", DataTypeUtil.getType(attributeValue))
put("correctType", "String, Number, Boolean")
}
})
throw IllegalArgumentException("TypeError: attributeValue should be a String, Number or Boolean")
LogLevelEnum.WARN, "ATTRIBUTES_NOT_FOUND", mapOf(
"apiName" to apiName,
"key" to "attributes",
"expectedFormat" to "a Map with String keys and String, Number or Boolean value types"
)
)
throw java.lang.IllegalArgumentException("TypeError: attributeMap should be a non empty map")
}
removedUnsupportedValues(attributes, apiName)

require(!(context?.id == null || context.id?.isEmpty()==true)) { "User ID is required" }
require(!(context.id == null || context.id?.isEmpty() == true)) { "User ID is required" }

if (this.processedSettings == null || !SettingsSchema().isSettingsValid(this.processedSettings)) {
LoggerService.log(LogLevelEnum.ERROR, "SETTINGS_SCHEMA_INVALID", null)
return
}
SetAttributeAPI.setAttribute(
this.processedSettings!!,
attributeKey,
attributeValue,
context!!
)

setAttribute(processedSettings!!, attributes, context)
} catch (exception: Exception) {
LoggerService.log(
LogLevelEnum.ERROR,
"API_THROW_ERROR",
object : HashMap<String?, String?>() {
init {
put("apiName", apiName)
put("err", exception.toString())
}
})
LogLevelEnum.ERROR, "API_THROW_ERROR", mapOf(
"apiName" to apiName,
"err" to exception.toString()
)
)
}
}

private fun removedUnsupportedValues(
attributes: MutableMap<String, Any>,
apiName: String
) {
attributes.entries.forEach { entry ->

if (!isString(entry.value) && !isNumber(entry.value) && !isBoolean(entry.value)) {
LoggerService.log(
LogLevelEnum.ERROR,
"API_INVALID_PARAM",
mapOf(
"apiName" to apiName,
"key" to "attribute value",
"type" to getType(entry.value),
"correctType" to "String, Number, Boolean"
)
)
throw java.lang.IllegalArgumentException("TypeError: attributeMap should values of type String, Number, Boolean")
}
}
}

Expand Down
22 changes: 6 additions & 16 deletions fme-android/src/main/java/com/vwo/api/SetAttributeAPI.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,11 @@ object SetAttributeAPI {
/**
* This method is used to set an attribute for the user.
* @param settings The settings model containing configuration.
* @param attributeKey The key of the attribute to set.
* @param attributeValue The value of the attribute to set.
* @param attributeMap - Map of attribute key and value to be set
* @param context The user context model containing user-specific data.
*/
@JvmStatic
fun setAttribute(
settings: Settings,
attributeKey: String,
attributeValue: Any,
context: VWOContext
) {
createAndSendImpressionForSetAttribute(settings, attributeKey, attributeValue, context)
fun setAttribute(settings: Settings, attributeMap: Map<String, Any>, context: VWOContext) {
createAndSendImpressionForSetAttribute(settings, attributeMap, context)
}

/**
Expand All @@ -45,14 +38,12 @@ object SetAttributeAPI {
* and uses the NetworkUtil to send a POST API request.
*
* @param settings The settings model containing configuration.
* @param attributeKey The key of the attribute to set.
* @param attributeValue The value of the attribute to set.
* @param attributeMap - Map of attribute key and value to be set
* @param context The user context model containing user-specific data.
*/
private fun createAndSendImpressionForSetAttribute(
settings: Settings,
attributeKey: String,
attributeValue: Any,
attributeMap: Map<String, Any>,
context: VWOContext
) {
// Get base properties for the event
Expand All @@ -69,8 +60,7 @@ object SetAttributeAPI {
context,
context.id,
EventEnum.VWO_SYNC_VISITOR_PROP.value,
attributeKey,
attributeValue
attributeMap
)

// Send the constructed properties and payload as a POST request
Expand Down
10 changes: 4 additions & 6 deletions fme-android/src/main/java/com/vwo/utils/NetworkUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -293,21 +293,19 @@ class NetworkUtil {
* @param settings The settings model containing configuration.
* @param userId The ID of the user.
* @param eventName The name of the event.
* @param attributeKey The key of the attribute.
* @param attributeValue The value of the attribute.
* @param attributeMap - Map of attribute key and value to be set
* @return
*/
fun getAttributePayloadData(
settings: Settings,
context: VWOContext,
userId: String?,
eventName: String,
attributeKey: String,
attributeValue: Any
): Map<String, Any?> {
attributeMap: Map<String, Any>
): Map<String, Any> {
val properties = getEventBasePayload(settings, context, userId, eventName, null, null)
properties.d?.event?.props?.setIsCustomEvent(true)
properties.d?.visitor?.props?.set(attributeKey, attributeValue)
properties.d?.visitor?.props?.putAll(attributeMap)
log(
LogLevelEnum.DEBUG,
"IMPRESSION_FOR_SYNC_VISITOR_PROP",
Expand Down
8 changes: 4 additions & 4 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ android.nonTransitiveRClass=true

POM_NAME=VWO FME Android SDK
POM_ARTIFACT_ID=vwo-fme-android-sdk
VERSION_NAME=1.2.0
VERSION_CODE=7
VERSION_NAME=1.3.0
VERSION_CODE=8
GROUP=com.vwo.sdk

#POM details
Expand All @@ -37,11 +37,11 @@ POM_SCM_DEV_CONNECTION=scm:git:[email protected]:wingify/vwo-fme-android-sdk.git
POM_LICENCE_NAME=scm:[email protected]:wingify/vwo-mobile-insights-android-sdk.git
POM_LICENCE_URL=https://www.apache.org/licenses/LICENSE-2.0
#POM_LICENCE_DIST=https://www.apache.org/licenses/LICENSE-2.0
POM_DEVELOPER_ID=
POM_DEVELOPER_NAME=
android.enableJetifier=true

POM_PACKAGING=aar
POM_DEVELOPER_EMAIL=[email protected]
POM_DEVELOPER_ID=
POM_DEVELOPER_NAME=
NEXUS_USERNAME=
NEXUS_PASSWORD=

0 comments on commit 6183c50

Please sign in to comment.