Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release/5.4.0 #806

Merged
merged 4 commits into from
Jul 12, 2023
Merged
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
6 changes: 6 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
Version 5.4.0 (2023-07-12)
--------------------------
Add Snowplow ecommerce events and entities (#800)
Increase interval for updating platform context properties from 0.1s to 1s (#798)
Expose property for retrieving payload in ConsentDocument that was removed in v5 (#804)

Version 5.3.1 (2023-07-06)
--------------------------
Fix incorrect date deserialization when reading the install timestamp from 1.7 version of the tracker (#801)
Expand Down
2 changes: 1 addition & 1 deletion SnowplowTracker.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "SnowplowTracker"
s.version = "5.3.1"
s.version = "5.4.0"
s.summary = "Snowplow event tracker for iOS, macOS, tvOS, watchOS for apps and games."
s.description = <<-DESC
Snowplow is a mobile and event analytics platform with a difference: rather than tell our users how they should analyze their data, we deliver their event-level data in their own data warehouse, on their own Amazon Redshift or Postgres database, so they can analyze it any way they choose. Snowplow mobile is used by data-savvy games companies and app developers to better understand their users and how they engage with their games and applications. Snowplow is open source using the business-friendly Apache License, Version 2.0 and scales horizontally to many billions of events.
Expand Down
4 changes: 2 additions & 2 deletions Sources/Core/Subject/PlatformContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import UIKit
/// Manages a dictionary (Payload) with platform context. Some properties for mobile platforms are updated on fetch in set intervals.
class PlatformContext {
private var platformDict: Payload = Payload()
private var mobileDictUpdateFrequency: TimeInterval = 0.1
private var mobileDictUpdateFrequency: TimeInterval = 1.0
private var networkDictUpdateFrequency: TimeInterval = 10.0
private var lastUpdatedEphemeralMobileDict: TimeInterval = 0.0
private var lastUpdatedEphemeralNetworkDict: TimeInterval = 0.0
Expand All @@ -37,7 +37,7 @@ class PlatformContext {
/// - deviceInfoMonitor: Device monitor for fetching platform information
/// - Returns: a PlatformContext object
init(platformContextProperties: [PlatformContextProperty]? = nil,
mobileDictUpdateFrequency: TimeInterval = 0.1,
mobileDictUpdateFrequency: TimeInterval = 1.0,
networkDictUpdateFrequency: TimeInterval = 10.0,
deviceInfoMonitor: DeviceInfoMonitor = DeviceInfoMonitor()) {
self.platformContextProperties = platformContextProperties
Expand Down
37 changes: 37 additions & 0 deletions Sources/Core/Tracker/EcommerceControllerImpl.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright (c) 2013-2023 Snowplow Analytics Ltd. All rights reserved.
//
// This program is licensed to you under the Apache License Version 2.0,
// and you may not use this file except in compliance with the Apache License
// Version 2.0. You may obtain a copy of the Apache License Version 2.0 at
// http://www.apache.org/licenses/LICENSE-2.0.
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the Apache License Version 2.0 is distributed on
// an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the Apache License Version 2.0 for the specific
// language governing permissions and limitations there under.

import Foundation

class EcommerceControllerImpl: Controller, EcommerceController {

func setEcommerceScreen(_ screen: EcommerceScreenEntity) {
let plugin = PluginConfiguration(identifier: "ecommercePageTypePluginInternal")
_ = plugin.entities { _ in [screen.entity] }
serviceProvider.addPlugin(plugin: plugin)
}

func setEcommerceUser(_ user: EcommerceUserEntity) {
let plugin = PluginConfiguration(identifier: "ecommerceUserPluginInternal")
_ = plugin.entities { _ in [user.entity] }
serviceProvider.addPlugin(plugin: plugin)
}

func removeEcommerceScreen() {
serviceProvider.removePlugin(identifier: "ecommercePageTypePluginInternal")
}

func removeEcommerceUser() {
serviceProvider.removePlugin(identifier: "ecommerceUserPluginInternal")
}
}
9 changes: 8 additions & 1 deletion Sources/Core/Tracker/ServiceProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,14 @@ class ServiceProvider: NSObject, ServiceProviderProtocol {
return mediaController
}

// Configurations
private var _ecommerceController: EcommerceController?
var ecommerceController: EcommerceController {
if let controller = _ecommerceController { return controller }
let ecommerceController = EcommerceControllerImpl(serviceProvider: self)
_ecommerceController = ecommerceController
return ecommerceController
}

private(set) var networkConfiguration = NetworkConfiguration()
private(set) var trackerConfiguration = TrackerConfiguration()
private(set) var emitterConfiguration = EmitterConfiguration()
Expand Down
1 change: 1 addition & 0 deletions Sources/Core/Tracker/ServiceProviderProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ protocol ServiceProviderProtocol: AnyObject {
var subjectConfiguration: SubjectConfiguration { get }
var sessionConfiguration: SessionConfiguration { get }
var gdprConfiguration: GDPRConfiguration { get }
var ecommerceController: EcommerceController { get }
var pluginConfigurations: [PluginIdentifiable] { get }
func addPlugin(plugin: PluginIdentifiable)
func removePlugin(identifier: String)
Expand Down
5 changes: 3 additions & 2 deletions Sources/Core/Tracker/Tracker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -471,11 +471,12 @@ class Tracker: NSObject {
setApplicationInstallEventTimestamp(event)
addBasicProperties(to: payload, event: event)
addStateMachinePayloadValues(event: event)
event.wrapProperties(to: payload, base64Encoded: base64Encoded)


// Context entities
addBasicContexts(event: event)
addStateMachineEntities(event: event)

event.wrapProperties(to: payload, base64Encoded: base64Encoded)
event.wrapContexts(to: payload, base64Encoded: base64Encoded)

// Decide whether to track the event or not
Expand Down
4 changes: 4 additions & 0 deletions Sources/Core/Tracker/TrackerControllerImpl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ class TrackerControllerImpl: Controller, TrackerController {
var media: MediaController {
return serviceProvider.mediaController
}

var ecommerce: EcommerceController {
return serviceProvider.ecommerceController
}

// MARK: - Control methods

Expand Down
12 changes: 11 additions & 1 deletion Sources/Core/TrackerConstants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import Foundation

// --- Version
let kSPRawVersion = "5.3.1"
let kSPRawVersion = "5.4.0"
#if os(iOS)
let kSPVersion = "ios-\(kSPRawVersion)"
#elseif os(tvOS)
Expand Down Expand Up @@ -60,6 +60,16 @@ let kSPErrorSchema = "iglu:com.snowplowanalytics.snowplow/application_error/json
let kSPApplicationInstallSchema = "iglu:com.snowplowanalytics.mobile/application_install/jsonschema/1-0-0"
let kSPGdprContextSchema = "iglu:com.snowplowanalytics.snowplow/gdpr/jsonschema/1-0-0"
let kSPDiagnosticErrorSchema = "iglu:com.snowplowanalytics.snowplow/diagnostic_error/jsonschema/1-0-0"
let ecommerceActionSchema = "iglu:com.snowplowanalytics.snowplow.ecommerce/snowplow_ecommerce_action/jsonschema/1-0-2"
let ecommerceProductSchema = "iglu:com.snowplowanalytics.snowplow.ecommerce/product/jsonschema/1-0-0"
let ecommerceCartSchema = "iglu:com.snowplowanalytics.snowplow.ecommerce/cart/jsonschema/1-0-0"
let ecommerceTransactionSchema = "iglu:com.snowplowanalytics.snowplow.ecommerce/transaction/jsonschema/1-0-0"
let ecommerceTransactionErrorSchema = "iglu:com.snowplowanalytics.snowplow.ecommerce/transaction_error/jsonschema/1-0-0"
let ecommerceCheckoutStepSchema = "iglu:com.snowplowanalytics.snowplow.ecommerce/checkout_step/jsonschema/1-0-0"
let ecommercePromotionSchema = "iglu:com.snowplowanalytics.snowplow.ecommerce/promotion/jsonschema/1-0-0"
let ecommerceRefundSchema = "iglu:com.snowplowanalytics.snowplow.ecommerce/refund/jsonschema/1-0-0"
let ecommerceUserSchema = "iglu:com.snowplowanalytics.snowplow.ecommerce/user/jsonschema/1-0-0"
let ecommercePageSchema = "iglu:com.snowplowanalytics.snowplow.ecommerce/page/jsonschema/1-0-0"

// --- Event Keys
let kSPEventPageView = "pv"
Expand Down
3 changes: 3 additions & 0 deletions Sources/Snowplow/Controllers/TrackerController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ public protocol TrackerController: TrackerConfigurationProtocol {
/// Media controller for managing media tracking instances and tracking media events.
@objc
var media: MediaController { get }
/// Ecommerce controller for managing ecommerce entity addition.
@objc
var ecommerce: EcommerceController { get }
/// Track the event.
/// The tracker will take care to process and send the event assigning `event_id` and `device_timestamp`.
/// - Parameter event: The event to track.
Expand Down
39 changes: 39 additions & 0 deletions Sources/Snowplow/Ecommerce/EcommerceController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright (c) 2013-2023 Snowplow Analytics Ltd. All rights reserved.
//
// This program is licensed to you under the Apache License Version 2.0,
// and you may not use this file except in compliance with the Apache License
// Version 2.0. You may obtain a copy of the Apache License Version 2.0 at
// http://www.apache.org/licenses/LICENSE-2.0.
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the Apache License Version 2.0 is distributed on
// an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the Apache License Version 2.0 for the specific
// language governing permissions and limitations there under.

import Foundation

/**
Controller for managing Ecommerce entities.
*/
@objc(SPEcommController)
public protocol EcommerceController {

/// Add an ecommerce Screen/Page entity to all subsequent events.
/// - Parameter screen: A EcommScreenEntity.
@objc
func setEcommerceScreen(_ screen: EcommerceScreenEntity)

/// Add an ecommerce User entity to all subsequent events.
/// - Parameter user: A EcommUserEntity.
@objc
func setEcommerceUser(_ user: EcommerceUserEntity)

/// Stop adding a Screen/Page entity to events.
@objc
func removeEcommerceScreen()

/// Stop adding a User entity to events.
@objc
func removeEcommerceUser()
}
56 changes: 56 additions & 0 deletions Sources/Snowplow/Ecommerce/Entities/CartEntity.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (c) 2013-2023 Snowplow Analytics Ltd. All rights reserved.
//
// This program is licensed to you under the Apache License Version 2.0,
// and you may not use this file except in compliance with the Apache License
// Version 2.0. You may obtain a copy of the Apache License Version 2.0 at
// http://www.apache.org/licenses/LICENSE-2.0.
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the Apache License Version 2.0 is distributed on
// an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the Apache License Version 2.0 for the specific
// language governing permissions and limitations there under.

import Foundation

/**
Provided to certain Ecommerce events. The Cart properties will be sent with the event as a Cart entity.
Entity schema: `iglu:com.snowplowanalytics.snowplow.ecommerce/cart/jsonschema/1-0-0`
*/
@objc(SPCartEntity)
public class CartEntity: NSObject {
/// The total value of the cart after this interaction.
@objc
public var totalValue: Decimal

/// The currency used for this cart (ISO 4217).
@objc
public var currency: String

/// The unique ID representing this cart.
@objc
public var cartId: String?

internal var entity: SelfDescribingJson {
var data: [String : Any] = [
"total_value": totalValue,
"currency": currency
]
if let cartId = cartId { data["cart_id"] = cartId }

return SelfDescribingJson(schema: ecommerceCartSchema, andData: data)
}

/// - Parameter totalValue: The total value of the cart after this interaction.
/// - Parameter currency: The currency used for this cart (ISO 4217).
/// - Parameter cartId: The unique ID representing this cart.
@objc
public init(
totalValue: Decimal,
currency: String,
cartId: String? = nil) {
self.totalValue = totalValue
self.currency = currency
self.cartId = cartId
}
}
56 changes: 56 additions & 0 deletions Sources/Snowplow/Ecommerce/Entities/EcommerceScreenEntity.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (c) 2013-2023 Snowplow Analytics Ltd. All rights reserved.
//
// This program is licensed to you under the Apache License Version 2.0,
// and you may not use this file except in compliance with the Apache License
// Version 2.0. You may obtain a copy of the Apache License Version 2.0 at
// http://www.apache.org/licenses/LICENSE-2.0.
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the Apache License Version 2.0 is distributed on
// an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the Apache License Version 2.0 for the specific
// language governing permissions and limitations there under.

import Foundation

/**
Attach Ecommerce Screen (Page) details to events. It is designed to help with grouping insights by
screen/page type, e.g. Product description, Product list, Home.
Entity schema: `iglu:com.snowplowanalytics.snowplow.ecommerce/page/jsonschema/1-0-0`
*/
@objc(SPEcommerceScreenEntity)
public class EcommerceScreenEntity: NSObject {
/// The type of screen that was visited, e.g. homepage, product details, cart, checkout, etc.
@objc
public var type: String

/// The language that the screen is based in.
@objc
public var language: String?

/// The locale version of the app that is running.
@objc
public var locale: String?

internal var entity: SelfDescribingJson {
var data: [String : Any] = ["type": type]
if let language = language { data["language"] = language }
if let locale = locale { data["locale"] = locale }

return SelfDescribingJson(schema: ecommercePageSchema, andData: data)
}

/// - Parameter type: The type of screen that was visited, e.g. homepage, product details, cart, checkout, etc.
/// - Parameter language: The language that the screen is based in.
/// - Parameter locale: The locale version of the app that is running.
@objc
public init(
type: String,
language: String? = nil,
locale: String? = nil
) {
self.type = type
self.language = language
self.locale = locale
}
}
71 changes: 71 additions & 0 deletions Sources/Snowplow/Ecommerce/Entities/EcommerceUserEntity.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright (c) 2013-2023 Snowplow Analytics Ltd. All rights reserved.
//
// This program is licensed to you under the Apache License Version 2.0,
// and you may not use this file except in compliance with the Apache License
// Version 2.0. You may obtain a copy of the Apache License Version 2.0 at
// http://www.apache.org/licenses/LICENSE-2.0.
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the Apache License Version 2.0 is distributed on
// an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the Apache License Version 2.0 for the specific
// language governing permissions and limitations there under.

import Foundation

/**
Attach Ecommerce User details to events. It is designed to help in modeling guest/non-guest account activity.
Entity schema: `iglu:com.snowplowanalytics.snowplow.ecommerce/user/jsonschema/1-0-0`
*/
@objc(SPEcommerceUserEntity)
public class EcommerceUserEntity: NSObject {
/// The user ID.
@objc
public var id: String

/// Whether or not the user is a guest.
public var isGuest: Bool?

/// The user's email address.
@objc
public var email: String?

internal var entity: SelfDescribingJson {
var data: [String : Any] = ["id": id]
if let isGuest = isGuest { data["is_guest"] = isGuest }
if let email = email { data["email"] = email }

return SelfDescribingJson(schema: ecommerceUserSchema, andData: data)
}

/// - Parameter id: The user ID.
/// - Parameter isGuest: Whether or not the user is a guest.
/// - Parameter email: The user's email address.
public init(
id: String,
isGuest: Bool? = nil,
email: String? = nil
) {
self.id = id
self.isGuest = isGuest
self.email = email
}

/// - Parameter id: The user ID.
/// - Parameter email: The user's email address.
@objc
public init(
id: String,
email: String? = nil
) {
self.id = id
self.email = email
}

/// Whether or not the user is a guest.
@objc
public func isGuest(_ isGuest: Bool) -> Self {
self.isGuest = isGuest
return self
}
}
Loading
Loading