Skip to content

Commit

Permalink
feat: add Kotlin android sample (#23)
Browse files Browse the repository at this point in the history
  • Loading branch information
qingzhuozhen authored Apr 5, 2022
1 parent 4cd2c69 commit 3b948c8
Show file tree
Hide file tree
Showing 28 changed files with 615 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,10 @@ class AndroidStorage(
}

override fun getEventCallback(insertId: String): EventCallBack? {
return eventCallbacksMap.getOrDefault(insertId, null)
if (eventCallbacksMap.contains(insertId)) {
return eventCallbacksMap.get(insertId)
}
return null
}

override fun removeEventCallback(insertId: String) {
Expand Down
121 changes: 101 additions & 20 deletions core/src/main/java/com/amplitude/core/Amplitude.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ import kotlinx.coroutines.launch
import org.json.JSONObject
import java.util.concurrent.Executors

/**
* <h1>Amplitude</h1>
* This is the SDK instance class that contains all of the SDK functionality.<br><br>
* Many of the SDK functions return the SDK instance back, allowing you to chain multiple methods calls together.
*/
open class Amplitude internal constructor(
val configuration: Configuration,
val store: State,
Expand All @@ -52,7 +57,7 @@ open class Amplitude internal constructor(
}

/**
* Public Constructor
* Public Constructor.
*/
constructor(configuration: Configuration) : this(configuration, State())

Expand All @@ -68,104 +73,174 @@ open class Amplitude internal constructor(
}

@Deprecated("Please use 'track' instead.", ReplaceWith("track"))
fun logEvent(event: BaseEvent) {
track(event)
fun logEvent(event: BaseEvent): Amplitude {
return track(event)
}

fun track(event: BaseEvent, callback: EventCallBack? = null) {
/**
* Track an event.
*
* @param event the event
* @param callback the optional event callback
* @return the Amplitude instance
*/
fun track(event: BaseEvent, callback: EventCallBack? = null): Amplitude {
callback ?. let {
event.callback = it
}
process(event)
return this
}

fun track(eventType: String, eventProperties: JSONObject? = null, options: EventOptions? = null) {
/**
* Log event with the specified event type, event properties, and optional event options.
*
* @param eventType the event type
* @param eventProperties the event properties
* @param options optional event options
* @return the Amplitude instance
*/
fun track(eventType: String, eventProperties: JSONObject? = null, options: EventOptions? = null): Amplitude {
val event = BaseEvent()
event.eventType = eventType
event.eventProperties = eventProperties
options ?. let {
event.mergeEventOptions(it)
}
process(event)
return this
}

/**
* Identify. Use this to send an Identify object containing user property operations to Amplitude server.
* Identify lets you to send an Identify object containing user property operations to Amplitude server.
* You can modify user properties by calling this api.
*
* @param identify identify object
* @param options optional event options
* @return the Amplitude instance
*/
fun identify(identify: Identify, options: EventOptions? = null) {
fun identify(identify: Identify, options: EventOptions? = null): Amplitude {
val event = IdentifyEvent()
event.userProperties = identify.properties
options ?. let {
event.mergeEventOptions(it)
}
process(event)
return this
}

fun identify(userId: String) {
/**
* Set the user id (can be null).
*
* @param userId custom user id
* @return the Amplitude instance
*/
fun setUserId(userId: String?): Amplitude {
this.idContainer.identityManager.editIdentity().setUserId(userId).commit()
return this
}

fun setDeviceId(deviceId: String) {
/**
* Sets a custom device id. <b>Note: only do this if you know what you are doing!</b>
*
* @param deviceId custom device id
* @return the Amplitude instance
*/
fun setDeviceId(deviceId: String): Amplitude {
this.idContainer.identityManager.editIdentity().setDeviceId(deviceId).commit()
return this
}

fun groupIdentify(groupType: String, groupName: String, identify: Identify, options: EventOptions? = null) {
/**
* Identify a group. You can modify group properties by calling this api.
*
* @param groupType the group type
* @param groupName the group name
* @param identify identify object
* @param options optional event options
* @return the Amplitude instance
*/
fun groupIdentify(groupType: String, groupName: String, identify: Identify, options: EventOptions? = null): Amplitude {
val event = GroupIdentifyEvent()
var group: JSONObject? = null
try {
group = JSONObject().put(groupType, groupName)
} catch (e: Exception) {
logger.error(e.toString())
logger.error("Error in groupIdentify: $e")
}
event.groups = group
event.groupProperties = identify.properties
options ?. let {
event.mergeEventOptions(it)
}
process(event)
return this
}

/**
* Sets the user's group.
* Set the user's group.
*
* @param groupType the group type
* @param groupName the group name
* @param options optional event options
* @return the Amplitude instance
*/
fun setGroup(groupType: String, groupName: String, options: EventOptions? = null) {
fun setGroup(groupType: String, groupName: String, options: EventOptions? = null): Amplitude {
val identify = Identify().set(groupType, groupName)
identify(identify, options)
return this
}

/**
* ets the user's groups.
* Sets the user's groups.
*
* @param groupType the group type
* @param groupName the group name
* @param options optional event options
* @return the Amplitude instance
*/
fun setGroup(groupType: String, groupName: Array<String>, options: EventOptions? = null) {
fun setGroup(groupType: String, groupName: Array<String>, options: EventOptions? = null): Amplitude {
val identify = Identify().set(groupType, groupName)
identify(identify, options)
return this
}

@Deprecated("Please use 'revenue' instead.", ReplaceWith("revenue"))
fun logRevenue(revenue: Revenue) {
fun logRevenue(revenue: Revenue): Amplitude {
revenue(revenue)
return this
}

/**
* Create a Revenue object to hold your revenue data and properties,
* and log it as a revenue event using this method.
*
* @param revenue revenue object
* @param options optional event options
* @return the Amplitude instance
*/
fun revenue(revenue: Revenue, options: EventOptions? = null) {
fun revenue(revenue: Revenue, options: EventOptions? = null): Amplitude {
if (!revenue.isValid()) {
return
logger.warn("Invalid revenue object, missing required fields")
return this
}
val event = revenue.toRevenueEvent()
options ?. let {
event.mergeEventOptions(it)
}
revenue(event)
return this
}

/**
* Log a Revenue Event
* Log a Revenue Event.
*
* @param event the revenue event
* @return the Amplitude instance
*/
fun revenue(event: RevenueEvent) {
fun revenue(event: RevenueEvent): Amplitude {
process(event)
return this
}

private fun process(event: BaseEvent) {
Expand All @@ -177,6 +252,12 @@ open class Amplitude internal constructor(
}
}

/**
* Add a plugin.
*
* @param plugin the plugin
* @return the Amplitude instance
*/
fun add(plugin: Plugin): Amplitude {
when (plugin) {
is ObservePlugin -> {
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/com/amplitude/core/events/Identify.kt
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,7 @@ class Identify() {
properties.getJSONObject(operation.operationType).put(property, value)
propertySet.add(property)
} catch (e: Exception) {
ConsoleLogger.logger.error(e.toString())
ConsoleLogger.logger.error("Error in set user property: $e")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class EventPipeline(
storage.writeEvent(message.event)
} catch (e: Exception) {
e.message?.let {
amplitude.logger.error(it)
amplitude.logger.error("Error when write event: $it")
}
}

Expand Down Expand Up @@ -117,7 +117,7 @@ class EventPipeline(
responseHandler?.handle(connection.response)
} catch (e: Exception) {
e.message?.let {
amplitude.logger.error(it)
amplitude.logger.error("Error when upload event: $it")
}
}
}
Expand Down
80 changes: 48 additions & 32 deletions core/src/main/java/com/amplitude/core/utilities/JSONUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ object JSONUtil {
eventJSON.addValue("insert_id", event.insertId)
eventJSON.addValue("library", event.library)
eventJSON.addValue("partner_id", event.partnerId)
eventJSON.addValue("android_app_set_id", event.appSetId)
event.plan?. let {
eventJSON.put("plan", it.toJSONObject())
}
Expand Down Expand Up @@ -157,50 +158,51 @@ internal fun JSONArray.toIntArray(): IntArray {
internal fun JSONObject.toBaseEvent(): BaseEvent {
val event = BaseEvent()
event.eventType = this.getString("event_type")
event.userId = this.optString("user_id", null)
event.deviceId = this.optString("device_id", null)
event.userId = this.optionalString("user_id", null)
event.deviceId = this.optionalString("device_id", null)
event.timestamp = if (this.has("time")) this.getLong("time") else null
event.eventProperties = this.optJSONObject("event_properties", null)
event.userProperties = this.optJSONObject("user_properties", null)
event.groups = this.optJSONObject("groups", null)
event.appVersion = this.optString("app_version", null)
event.platform = this.optString("platform", null)
event.osName = this.optString("os_name", null)
event.osVersion = this.optString("os_version", null)
event.deviceBrand = this.optString("device_brand", null)
event.deviceManufacturer = this.optString("device_manufacturer", null)
event.deviceModel = this.optString("device_model", null)
event.carrier = this.optString("carrier", null)
event.country = this.optString("country", null)
event.region = this.optString("region", null)
event.city = this.optString("city", null)
event.dma = this.optString("dma", null)
event.language = this.optString("language", null)
event.eventProperties = this.optionalJSONObject("event_properties", null)
event.userProperties = this.optionalJSONObject("user_properties", null)
event.groups = this.optionalJSONObject("groups", null)
event.appVersion = this.optionalString("app_version", null)
event.platform = this.optionalString("platform", null)
event.osName = this.optionalString("os_name", null)
event.osVersion = this.optionalString("os_version", null)
event.deviceBrand = this.optionalString("device_brand", null)
event.deviceManufacturer = this.optionalString("device_manufacturer", null)
event.deviceModel = this.optionalString("device_model", null)
event.carrier = this.optionalString("carrier", null)
event.country = this.optionalString("country", null)
event.region = this.optionalString("region", null)
event.city = this.optionalString("city", null)
event.dma = this.optionalString("dma", null)
event.language = this.optionalString("language", null)
event.price = if (this.has("price")) this.getDouble("price") else null
event.quantity = if (this.has("quantity")) this.getInt("quantity") else null
event.revenue = if (this.has("revenue")) this.getDouble("revenue") else null
event.productId = this.optString("productId", null)
event.revenueType = this.optString("revenueType", null)
event.productId = this.optionalString("productId", null)
event.revenueType = this.optionalString("revenueType", null)
event.locationLat = if (this.has("location_lat")) this.getDouble("location_lat") else null
event.locationLng = if (this.has("location_lng")) this.getDouble("location_lng") else null
event.ip = this.optString("ip", null)
event.idfa = this.optString("idfa", null)
event.idfv = this.optString("idfv", null)
event.adid = this.optString("adid", null)
event.androidId = this.optString("android_id", null)
event.ip = this.optionalString("ip", null)
event.idfa = this.optionalString("idfa", null)
event.idfv = this.optionalString("idfv", null)
event.adid = this.optionalString("adid", null)
event.androidId = this.optionalString("android_id", null)
event.appSetId = this.optString("android_app_set_id", null)
event.eventId = if (this.has("event_id")) this.getInt("event_id") else null
event.sessionId = this.getLong("session_id")
event.insertId = this.optString("insert_id", null)
event.insertId = this.optionalString("insert_id", null)
event.library = if (this.has("library")) this.getString("library") else null
event.partnerId = this.optString("partner_id", null)
event.partnerId = this.optionalString("partner_id", null)
event.plan = if (this.has("plan")) Plan.fromJSONObject(this.getJSONObject("plan")) else null
return event
}

internal fun JSONArray.toEvents(): List<BaseEvent> {
val events = mutableListOf<BaseEvent>()
this.forEach {
events.add((it as JSONObject).toBaseEvent())
(0 until this.length()).forEach {
events.add((this.getJSONObject(it)).toBaseEvent())
}
return events
}
Expand All @@ -209,11 +211,11 @@ internal fun JSONArray.split(): Pair<String, String> {
val mid = this.length() / 2
val firstHalf = JSONArray()
val secondHalf = JSONArray()
this.forEachIndexed { index, obj ->
(0 until this.length()).forEach { index, ->
if (index < mid) {
firstHalf.put(obj)
firstHalf.put(this.getJSONObject(index))
} else {
secondHalf.put(obj)
secondHalf.put(this.getJSONObject(index))
}
}
return Pair(firstHalf.toString(), secondHalf.toString())
Expand All @@ -224,3 +226,17 @@ internal fun JSONObject.addValue(key: String, value: Any?) {
this.put(key, value)
}
}

inline fun JSONObject.optionalJSONObject(key: String, defaultValue: JSONObject?): JSONObject? {
if (this.has(key)) {
return this.getJSONObject(key)
}
return defaultValue
}

inline fun JSONObject.optionalString(key: String, defaultValue: String?): String? {
if (this.has(key)) {
return this.getString(key)
}
return defaultValue
}
Loading

0 comments on commit 3b948c8

Please sign in to comment.