Usage
public class Usage
Client Usage in Common
Flexibly collect, store, and upload client usage events.
ClientUsage
allows you to collect data for different targets. A target is logical group of collected events and information, collected for a specific purpose, and sent to a given analytics server. Different servers can be used for different targets using different communication protocols and data structures.
Elements:
Reporters: All events reported using a reporter assigned to a target. The reporter’s only task is to generate
UsageRecord
which is stored in an instance ofUsageStoring
.Uploaders: Transforms the collected data of a target to a required format, uploads to a given server, and removes the successfully uploaded data. You can write a custom ‘Uploader’ which uses a custom server and custom data format. Use
UsageStoring
andUsageSnapsotting
to help with this task. By default theSAPcpmsUsageUploader
is implemented in SAPFoundation to upload logs to SAP Mobile Services.UsageStoring: A protocol that manages record storing, retrieval, and deletion, and can be used by
Uploaders
to retrieve records and clear them after a successful upload. It can also be used to obtain an instance ofUsageSnapshotting
for a given target. By default theUsageStore
is implemented in SAPFoundation.
See Usage Reporting for additional information.
SAP Mobile Services configuration
To use this component you must enable the server to accept records for an application. See Defining Usage Report Policy
After successful client data upload, you can find your reports on the server. See Viewing Client Data Report
Configuration
The main component of Usage
is separated from the default store and uploader implementation. You must configure the component before you can use it. For example, by instantiating a default store object and passing it to the Usage’s configure method as follows:
do {
let store = try UsageStore()
Usage.shared.configure(with: store)
} catch {
// handle error
}
The UsageStore
class is located in SAPFoundation.
*Notes: *
- This is not an optional step – In order to generate usage records via reporters, the usage instance must be configured. Reporters created (by subclassing and registering, or by obtaining via reporter(for:) method) prior configuration are invalid instances which can not be used for reporting.
- Configure the instance once only – Multiple calls to the configure method have no effect and the first configured store remains in use.
- A custom store can be created by implementing the
UsageStoring
protocol – Custom classes implementing theUsageStoring
protocol can be passed to the configure method.
Usage
Event reporting
You can report events using either:
Event reporting using SAPcpms compatible reporter
The SAP Mobile Services server supports a specific format of Usage data. Since the schema of the data is not flexible the fields are mandatory.
Reporting using SAPcpmsUsage
to the default target:
// Only the applicationID and applicationVersion fields are used from the settingsParameter.
SAPcpmsUsage.sessionStart(applicationIdentifier: <#application identifier#>, applicationVersion: <#application version#>)
// ...
SAPcpmsUsage.event(type: "testType", key: "testKey")
SAPcpmsUsage.sessionEnd()
The SAPcpmsRecord
class provides convenience methods to create a record using the proper fields. Reporting using SAPcpmsRecord
to any target:
reporter = Usage.shared.reporter(for: "myTarget")
reporter.report(SAPcpmsRecord.sessionStart(applicationIdentifier: <#application identifier#>, applicationVersion: <#application version#>))
// ...
reporter.report(SAPcpmsRecord.event(type: "testType", key: "testKey"))
Note: Additional convenience method is available by importing the SAPFoundation. See Additional convenience method on SAPcpmsUsage for more information.
Event reporting using flexible reporter
Create a report using custom events and include an info dictionary as a parameter:
// get the default reporter
let reporter = Usage.shared.reporter()
// report session start event
reporter.report(.sessionStart)
// ...
// report custom event
reporter.report(.event("SomeCustomEvent"))
// ...
// report custom event with additional info
reporter.report(.event("SomeCustomEvent"), info: ["MyCustomKey": "MyCustomData"])
In this case you must upload reports using a custom uploader.
Reporting app usage
App usage events may be logged using the SAPcpmsUsage.logBehaviorEvent(behaviorEvent:viewIdentifier:)
method in SAPCommon. This method is a wrapper around the SAPcpmsUsage.event()
API and provides a structured schema for server-side generated analytics reports about usage behaviors and application analytics.
Logging when views display
Utilize a view controller’s viewDidAppear()
method to log when a view is presented to the user. The value for behaviorEvent
should be viewDisplayed
from the SAPcpmsUsage.BehaviorEvent
enumeration to identify this event on the server-side as a screen being displayed in your app. The viewIdentifier
should always be the name of the screen; this could either be a string representation of the class name or a “business-friendly” name that may be more readable to an analyst reviewing the reports generated from this data. For example:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.makeSelection()
SAPcpmsUsage.logBehaviorEvent(behaviorEvent: .viewDisplayed, viewIdentifier: "Products Listing Screen")
}
Logging user interactions within your app
Use SAPcpmsUsage.logBehaviorEvent(behaviorEvent:viewIdentifier:)
with its optional parameters to log when users interact with controls and other on-screen elements within your app:
- The value for
behaviorEvent
isuserInteraction
from theSAPcpmsUsage.BehaviorEvent
enumeration and identifies this event on the server-side as an action performed by the user. viewIdentifier
is always the name of the screen (as a best practice, follow the same convention you use when loggingviewDisplayed
events).
Use the optional parameters to add details about the nature of the user’s interaction which are utilized when generating analytics reports, for example:
elementIdentifier
is the name of the control that interacts with and follows a similar naming convention toviewIdentifier
action
is a description of the action the user performs on the control (if applicable)value
contains any value deemed relevant to the interaction (if applicable).
Here are some examples:
Logging when the user presses your app’s refresh button:
private func refresh() {
SAPcpmsUsage.logBehaviorEvent(behaviorEvent: .userInteraction, viewIdentifier: "Products Listing Screen", elementIdentifier: "Refresh Button")
// Note: The only action that can be performed in this example is the button being pressed, so the action parameter is not used.
// ...
}
Logging when the user selects a row in a table of products:
override func prepare(for segue: UIStoryboardSegue, sender _: Any?) {
SAPcpmsUsage.logBehaviorEvent(behaviorEvent: .userInteraction, viewIdentifier: "Products Listing Screen", elementIdentifier: "Products Table", action:"Row Selected", value: selectedEntity.productName)
// Note: In this example, selectedEntity.productName is a variable with the product name of the item selected, e.g., "iPad Pro".
// ...
}
The parameters for logBehaviorEvent()
can be flexibly applied to a variety of controls and possible interactions, but you should decide on an appropriate convention to follow for logging interactions within your app.
Report uploading
You can upload reports using either:
- SAPcpms compatible uploader - found in SAPFoundation
- Custom uploader
Uploading reports using a custom uploader
Uploads a snapshot of the data to an endpoint using data format and protocol for communication. The steps to upload the data are:
- Retrieve the snapshot for a given target using:
Usage.store.snapshot(for:)
. - Read all records from the snapshot and create the proper data format. Use
UsageSnapshot.records()
to enumerate the records. - Upload the generated data to the server.
- If the upload is successful, delete the original records calling
UsageSnapshot.removeRecords()
.
You can use Streaming to merge the second and third steps.
Usage component Logger ID
This component uses the following name prefix for logging: ‘SAP.Common.Usage’
Usage
-
The default target identifier
Declaration
Swift
public static let defaultTargetID: String
-
StorageID name used for shared data.
Declaration
Swift
public static let unattributedStorageID: String
-
UserID used for shared/anonymous data.
Declaration
Swift
public static let unattributedUserID: String
-
Returns a shared singleton usage object.
Declaration
Swift
public class var shared: Usage { get }
-
Returns the store object associated with the usage object. The UsageStore used by the Usage component to save the data until it is uploaded to a server. It is used also by uploader components to access the data. If the store is not initialized, an attempt is made to initialize it with default parameters.
Declaration
Swift
public var store: UsageStoring? { get }
-
Read-only access to representation of SAPcpmsUsagePolicy server-side setting.
Declaration
Swift
private(set) public var dataCollectionEnabled: Bool { get }
-
Read-only access to current consent value.
Declaration
Swift
private(set) public var userConsent: Bool { get }
-
Unique identifier created during onboarding process.
Declaration
Swift
private(set) public var userID: String? { get }
-
Configures the usage instance with the given UsageStoring. Sets userID and userConsent values used to control Usage message output on a per-user basis.
Declaration
Swift
public func configure(with store: UsageStoring, retainLastUnattributedSession: Bool = false, addSessionData applicationIdentifier: String? = nil)
Parameters
store
the UsageStoring used to store the UsageRecords
retainLastUnattributedSession
if true, temporarily save last unattributed session in memory to inject into attributed store, else leave unattributed data in place.
applicationIdentifier
optionally add session data when outputEnabled state transition is detected.
-
Returns a UsageReporter instance for the given target identifier. If the reporter doesn’t exist a new one will be created automatically. All other calls will return the same reporter instance. Uses
Usage.defaultTargetID
by default.Declaration
Swift
public func reporter(for targetID: String = defaultTargetID, injectUnattributed: Bool = true) -> UsageReporter
Parameters
targetID
the target identifier where to reporter will report to
injectUnattributed
controls if saved unattributed data is injected
Return Value
UsageReporter associated with the given target identifier
-
Registers a custom created UsageReporter instance. Custom UsageReporters can be created by subclassing the UsageReporter class. UsageReporters created this way must be registered to Usage through this register method, otherwise they can not report to the usage store. If there was a reporter with this ID that will be replaced with the new instance.
Declaration
Swift
public func register(reporter: UsageReporter, for targetID: String = defaultTargetID, injectUnattributed: Bool = true)
Parameters
reporter
custom created UsageReporter
targetID
the target identifier which will be associated with the reporter
injectUnattributed
controls if saved unattributed data is injected
-
Unregisters and invalidates a previously registered or created reporter and removes it from Usage. After unregistering a reporter it can no longer report to the usage store and must be re-registered to use again.
Declaration
Swift
public func unregisterReporter(from targetID: String)
Parameters
targetID
the target identifier which identifies the reporter
-
Retrieves the used target identifiers. This method retrieves all the distinct target identifiers used by the reporter both in the usage store and in-memory.
Declaration
Swift
public func targetIdentifiers() -> [String]
Return Value
array of used target identifiers
-
Set dataCollectionEnabled true and optionally emit session data.
Declaration
Swift
public func enableDataCollection(addSessionData applicationIdentifier: String? = nil)
Parameters
applicationIdentifier
optionally add session data when outputEnabled state transition is detected.
-
Set dataCollectionEnabled false and optionally emit session data.
Declaration
Swift
public func disableDataCollection(addSessionData emitData: Bool = false)
Parameters
emitData
optionally add session data when outputEnabled state transition is detected.
-
Record consent value for specfied user.
Declaration
Swift
public func consentForUser(_ userID: UUID, given consent: Bool = false, addSessionData applicationIdentifier: String? = nil)
Parameters
userID
specified user.
consent
value to record.
applicationIdentifier
optionally add session data when outputEnabled state transition is detected.
-
Obtain consent value for specified user.
Declaration
Swift
public func hasConsentForUser(_ userID: UUID) -> Bool
Parameters
userID
whom to query consent for.
Return Value
associated consent value.
-
Determine if Usage data may be output.
Declaration
Swift
public func outputEnabled() -> Bool
Return Value
boolean indicating state.