diff --git a/sdk_dev_guide/current.md b/sdk_dev_guide/current.md index 7e35b01b..fecf3dbe 100644 --- a/sdk_dev_guide/current.md +++ b/sdk_dev_guide/current.md @@ -890,126 +890,453 @@ end_sesson=1&session_duration=30
- Reporting views would allow you to analyze which views/screens/pages were visited by the app user as well as how long they spent on a specific view. If it is possible to automatically determine when a user visits a specific view in your platform, then you should provide an option to automatically track views. Also, it is important to provide a way to track views manually. + Reporting views enables you to analyze which screens or pages were visited by + users and how much time they spent on each one, providing valuable insights into + user engagement and navigation patterns.
-- View information is packaged into events. There are 2 kinds of events: + Config Methods
-CountlyConfig.enableAutomaticViewTracking()+
CountlyConfig.enableAutomaticViewShortNames()+
CountlyConfig.setAutomaticViewTrackingExclusions(exclusions: Array<String>)+
CountlyConfig.setGlobalViewSegmentation(segmentation: Map<String, Object>)
- All view-related events use the event key "[CLY]_view" and are dependent on the - consent key "views". + Instance Methods
-All view events are sent with a "count" of 1.
-- The duration field "dur" is used when reporting view duration. It should contain - the view duration in seconds. +
CountlyInstance.setGlobalViewSegmentation(segmentation: Map<String, Object>)+
CountlyInstance.updateGlobalViewSegmentation(segmentation: Map<String, Object>)+
String CountlyInstance.startAutoStoppedView(viewName: String)+
String CountlyInstance.startAutoStoppedView(viewName: String, segmentation: Map<String, Object>)+
String CountlyInstance.startView(viewName: String)+
String CountlyInstance.startView(viewName: String, segmentation: Map<String, Object>)+
CountlyInstance.stopViewWithName(viewName: String)+
CountlyInstance.stopViewWithName(viewName: String, segmentation: Map<String, Object>)+
CountlyInstance.stopViewWithID(viewID: String)+
CountlyInstance.stopViewWithID(viewID: String, segmentation: Map<String, Object>)+
CountlyInstance.pauseViewWithID(viewID: String)+
CountlyInstance.resumeViewWithID(viewID: String)+
CountlyInstance.stopAllViews(segmentation: Map<String, Object>)+
CountlyInstance.addSegmentationToViewWithID(viewID: String, segmentation: Map<String, Object>)+
CountlyInstance.addSegmentationToViewWithName(viewName: String, segmentation: Map<String, Object>)+
+ If it is possible to automatically determine when a user visits a specific view + in your platform, then you should provide an option to automatically track views. + Also, it is important to provide a way to track views manually. +
++ For all segmentation inputs, segmentation must be validated before processing, + constraints for a segmentation:
-There are 5 potential segmentation values:
- A sample event for reporting the first view would look like this: + View tracking can be configured through + SDK behavior settings, if it is disabled + in the Behavior Settings, all view calls must be omiited.
-events=[
{
"key": "[CLY]_view",
"count": 1,
"segmentation": {
"name": "view1",
"segment": "Android",
"visit": 1,
"start": 1,
"_idv": "f0e8f5db5e5d9e7b9a45d3916b93e43dd091153fdfb6c9a6f"
}
}
]
- Sample event for reporting this view's duration: + For config method enableAutomaticViewTracking
-events=[+
{
"key": "[CLY]_view",
"count": 1,
"dur": 30,
"segmentation": {
"name": "view1",
"segment": "Android",
"_idv": "f0e8f5db5e17ad5ce5cf53916b93e43dd091153fdfb6c9a6f"
}
}
]
CountlyConfig.enableAutomaticViewTracking() + +// Logic +Enables automatic tracking of views if the system supports it. +Registers system-specific lifecycle callbacks to track view appearances automatically. +- Like onViewStart, onViewStop, onViewPause, onViewResume +- Enabling automatic view tracking will disable calling all manual view calls. +
- Here is more information on view-tracking APIs. + For config method enableAutomaticViewShortNames
-CountlyConfig.enableAutomaticViewShortNames() + +// Logic +When enabled, view names will be shortened automatically by trimming package or path prefixes. +Helps in reducing verbose or repetitive view naming in analytics.
Only will get class of view name. +- If view name is something like ly.count.some.View name must be shortened to View
- The following section will describe a sample implementation of manual views. + For config method setAutomaticViewTrackingExclusions
+CountlyConfig.setAutomaticViewTrackingExclusions(exclusions: Array<String>) + +// Valid values +Only non-empty strings accepted. + +// Logic +Sets a list of view names to be excluded from automatic view tracking. +Useful to prevent tracking of internal, debug, or unwanted views. +- Simply omits the views if they exist in the exclusions list. +
- First, you will need to have 2 internal private properties as string lastView and int lastViewStartTime. Then, create an internal private method reportViewDuration, which checks if lastView is null, and if not, it should report the duration for lastView by calculating it based off the current timestamp and lastViewStartTime. + For config method setGlobalViewSegmentation
+CountlyConfig.setGlobalViewSegmentation(segmentation: Map<String, Object>) + +// Valid values +Only non-empty and non-null values accepted. And, for values only mentioned validated constraints above accepted. + +// Logic +Sets a global segmentation dictionary that will be attached to all views. +Allows adding common context or user attributes globally. +
- After those steps, provide a reportView method to set the view name as a string parameter inside this method call reportViewDuration to report the duration of the previous view (if there is one). Then set the provided view name as lastView and the current timestamp as lastViewStartTime. Report the view as an event with the visit property and segment as your platform name. Additionally, if this is the first view a user visits in this app session, then also report the start property as true. You will also need to call reportViewDuration with the app exit event. + For instance method setGlobalViewSegmentation
+CountlyInstance.setGlobalViewSegmentation(segmentation: Map<String, Object>) + +// Valid values +Only non-empty and non-null values accepted. And, for values only mentioned validated constraints above accepted. + +// Logic +Sets a global segmentation dictionary that will be attached to all views. +Useful to add common context or attributes to all views globally. +
- After manual view tracking has been implemented, you may also implement automatic view tracking (if it is available on your platform). To implement automatic view tracking, you will need to catch your platform's specific event when the view is changed and call your implemented reportView method with the view name. + For instance method updateGlobalViewSegmentation
+CountlyInstance.updateGlobalViewSegmentation(segmentation: Map<String, Object>) + +// Valid values +Only non-empty and non-null values accepted. And, for values only mentioned validated constraints above accepted. + +// Logic +Updates the existing global segmentation by merging the new keys and values. +Allows to add or overwrite global segmentation properties dynamically. +
- Additionally, you will need to implement enabling and disabling automatic view tracking, as well as status checking, despite whether automatic view tracking is currently enabled or not. + For instance method startAutoStoppedView
+String CountlyInstance.startAutoStoppedView(viewName: String) + +// Valid values +Only non-empty values accepted + +// Logic +Starts a view that will be stopped with another view. +Returns a unique view ID for further reference. +- If automatic view tracking enabled, this call will be omitted because manually calling this function end the automatically started views by the callbacks. +- If view tracking is not enabled in the SDK behavior settings, call need to be omitted. +- viewName is validated +- Previously started automatic views must end +- View segmentation will be created: + - If global view segmentation set, it is added + - If it is the first view in the session "start" added + - "visit", "segment", "name" parameters added which key length SDK internal limit is applied to the name. +- Records the view event with calculated segmentation +- Returns the view ID generated ++
+ For instance method startAutoStoppedView with segmentation +
+String CountlyInstance.startAutoStoppedView(viewName: String, segmentation: Map<String, Object>) + +// Valid values +Only non-empty values accepted, and segmentation is validated by the constraints mentioned above. +Segmentation can be nullable. + +// Logic +Same as startAutoStoppedView(viewName) but allows attaching segmentation data for that specific view start. +- While creating the view segmentation, before adding reserved keys given segmentation needs to be validated and all related SDK internal limits must be applied +- After it is validated, already validated global view segmentation need to be added and after addition segmentation values SDK internal limit must be applied +- At last, reserved segmentation keys are added. They must not affected from the segmentation values SDK internal limit. +
- The pseudo-code to implement view tracking could appear as follows: + For instance method startView
-class Countly {
- String lastView = null;
- int lastViewStartTime = 0;
- boolean autoViewTracking = false;
-
- private void reportViewDuration(){
- if(lastView != null){
- //create event with parameters and
- //calculating dur as getCurrentTimestamp()-lastViewStartTime
- }
- }
-
- void onAppExit(){
- reportViewDuration();
- }
-
- void onViewChanged(String view){
- if(autoViewTracking)
- reportView(view);
- }
-
- public void reportView(String name){
- //report previous view duration
- reportViewDuration();
- lastView = name;
- lastViewStartTime = getCurrentTimestamp();
- //create event with parameters without duration
- // duration will be calculated on next view start or app exit
- }
-
- public void setAutoViewTracking(boolean enable){
- autoViewTracking = enable;
- }
-
- public boolean getAutoViewTracking(){
- return autoViewTracking;
- }
+String CountlyInstance.startView(viewName: String)
+
+// Valid values
+Only non-empty values accepted.
+
+// Logic
+Same as startAutoStoppedView(viewName), except views started with this function will not be stopped automatically.
+Calling this function must end previously started automatic views too.
+
+
+ For instance method startView with segmentation
+
+String CountlyInstance.startView(viewName: String, segmentation: Map<String, Object>)
+
+// Valid values
+Only non-empty values accepted, and segmentation is validated by the constraints mentioned above.
+Segmentation can be nullable.
+
+// Logic
+Same as startAutoStoppedView(viewName, segmenatation), except views started with this function will not be stopped automatically.
+Calling this function must end previously started automatic views too.
+
+
+ For instance method stopViewWithName
+
+CountlyInstance.stopViewWithName(viewName: String)
+
+// Valid values
+Only non-empty values accepted.
+
+// Logic
+Stops tracking a view by its name.
+If multiple views with the same name exist, the most recent one or first accessed view from the view list is stopped.
+- Tries to find a view with the given name, if it cannot find a name function returns
+- Not started views cannot be stopped.
+- So stopping a view with an ID is most recommended way, becuase stopping with name can arise conflicts.
+- If view tracking is not enabled in the SDK behavior settings, call need to be omitted.
+- View duration calculated here by current timestamp - vew start timestamp in seconds.
+- View segmentation created here with:
+ - Global view segmentation
+ - "name" and "segment" reserved segmentation keys are added
+- Then, a view event recorded here with calculated duration and segmentation.
+
+
+ For instance method stopViewWithName with segmentation
+
+CountlyInstance.stopViewWithName(viewName: String, segmentation: Map<String, Object>)
+
+// Valid values
+Only non-empty values accepted, and segmentation is validated by the constraints mentioned above.
+Segmentation can be nullable.
+
+// Logic
+Same as stopViewWithName(viewName) but allows attaching segmentation data for that specific view end.
+- While creating the view segmentation, before adding reserved keys given segmentation needs to be validated and all related SDK internal limits must be applied
+- After it is validated, already validated global view segmentation need to be added and after addition segmentation values SDK internal limit must be applied
+- At last, reserved segmentation keys are added. They must not affected from the segmentation values SDK internal limit.
+
+ For instance method stopViewWithID
+
+CountlyInstance.stopViewWithID(viewID: String)
+
+// Valid values
+Only non-empty values accepted.
+
+// Logic
+Same as stopViewWithName(viewName) one difference because we have ID directly, we can directly access it via its ID.
+
+
+ For instance method stopViewWithID with segmentation
+
+CountlyInstance.stopViewWithID(viewID: String, segmentation: Map<String, Object>)
+
+// Valid values
+Only non-empty values accepted, and segmentation is validated by the constraints mentioned above.
+Segmentation can be nullable.
+
+// Logic
+Same as stopViewWithName(viewName, segmentation) one difference because we have ID directly, we can directly access it via its ID.
+
+
+ For instance method pauseViewWithID
+
+CountlyInstance.pauseViewWithID(viewID: String)
+
+// Valid values
+Only non-empty values accepted.
+
+// Logic
+Pauses the timing of the view identified by the given ID.
+Useful when the app goes into background or temporary interruptions occur.
+- If view tracking is not enabled in the SDK behavior settings, call need to be omitted.
+- This function will omit calls where the specified view ID is already paused.
+- An end view event will be recorded here to prevent data loss and data disperancies.
+- End view segmentation is same as stop calls without given segmentation.
+- Paused view will not be deleted from the view list, its start time will be reset.
+
+
+ For instance method resumeViewWithID
+
+CountlyInstance.resumeViewWithID(viewID: String)
+
+// Valid values
+Only non-empty values accepted.
+
+// Logic
+Resumes a paused view identified by the given ID.
+- If view tracking is not enabled in the SDK behavior settings, call need to be omitted.
+- Already running views cannot be resumed.
+- This function will not record any event, it will set start time of already paused views.
+
+
+ For instance method stopAllViews
+
+CountlyInstance.stopAllViews(segmentation: Map<String, Object>)
+
+// Valid values
+If not empty segmentation is validated by the constraints mentioned above. It can be nullable.
+
+// Logic
+Stops all views (auto/non-auto) with provided segmentation if any with adding global view segmentation.
+- It can loop through views and stop them one by one with their id.
+- It can use stopViewWithID(viewID, segmentation) function internally.
+
+
+ For instance method addSegmentationToViewWithID
+
+CountlyInstance.addSegmentationToViewWithID(viewID: String, segmentation: Map<String, Object>)
+
+// Valid values
+viewID cannot be empty. If not empty segmentation is validated by the constraints mentioned above. It can be nullable.
+
+// Logic
+Adds or updates segmentation data on an active view identified by the given ID.
+- SDK internal limits are applied to the segmentation and added to the view.
+- This segmentation will be recorded when a view ended or paused.
+
+
+ For instance method addSegmentationToViewWithName
+
+CountlyInstance.addSegmentationToViewWithName(viewName: String, segmentation: Map<String, Object>)
+
+// Valid values
+viewName cannot be empty. If not empty segmentation is validated by the constraints mentioned above. It can be nullable.
+
+// Logic
+Adds or updates segmentation data on active view matching the given name.
+- Same as addSegmentationToViewWithID(viewID, segmentation), function just tries to find view with given name.
+
+
+ If platform supports automatic view reporting, feature must register to some
+ callbacks or app lifecycle events if any.
+ If a callback that notifies new screen started or new page started exist, when
+ it called:
+
+- SDK tries to extract a name from given page or screen
+
+ - If using short names is used, SDK need to shorten by specific platform calls.
+ If names are always short, and cannot be null, SDK might not expose shortening
+ at all.
+
+
+ - If extracted name not in the exclusion list, we simply start a view with global
+ view segmentation.
+
+
+ - If this view is the first view, function should start all view that are flagged
+ as "willStartAgain"
+
+If a callback that notifies screen or place is closing:
+- stop the current running view
+
+ - if app is losing focus or going to background all running views will be stopped
+ and sent.
+
+
+ - And they are flagged as willStartAgain and will not be removed from the view
+ cache list. They are removed when they are stopped properly.
+
+
+ Additionally, if your platform supports actions on view, such as clicks, you may report them as well. Here is more information on reporting actions for views
+
+Networking and Params
+
+ Because views reported as events they are pretty much same. Except, views have
+ some internal segmentation keys.
+
+There are two types of view events:
+
+ - One to indicate the view was entered
+ - One to report view duration and mark it as exited
+
+
+ Both use the event key "[CLY]_view". Each event is sent with
+ "count": 1. Duration (in seconds) is reported via the
+ "dur" field.
+
+Each event includes up to four reserved segmentation keys:
+
+ -
+
name: view name, e.g. "View_1"
+
+ -
+
segment: SDK platform name, e.g. "Android"
+
+ -
+
visit: set to 1 when the view is entered
+
+ -
+
start: set to 1 if it's the first view of the session
+
+
+Example: first view entry
+{
+ "key": "[CLY]_view",
+ "count": 1,
+ "segmentation": {
+ "name": "view1",
+ "segment": "Android",
+ "visit": 1,
+ "start": 1
+ }
+}
+Example: reporting view duration
+{
+ "key": "[CLY]_view",
+ "count": 1,
+ "dur": 30,
+ "segmentation": {
+ "name": "view1",
+ "segment": "Android"
+ }
}
- Additionally, if your platform supports actions on view, such as clicks, you may report them as well. Here is more information on reporting actions for views.
+ For details, see the
+ Countly View Tracking API.
+
+Storage
+
+ Views are not stored specifically. Their start and end view events are stored
+ as events. Views are cache-stored to manage view states. A map data structure
+ is the supported approach to manage and access views by their IDs easily. Their
+ datas could be demonstrated by below class concept.
+
+class ViewData {
+
+ String viewID
+
+ String viewName
+
+ Long viewStartTime
+
+ Boolean autoView
+
+ Map<String, Object> viewSegmentation
+
+ Boolean willStartAgain
+}
+
+ ViewID is randomly generated unique URL-safe random string by combining 6 bytes
+ of secure randomness (Base64-encoded) with the current timestamp.
+
+Consent
+
+ The feature depends on "views" consent. If consent is not given, all calls must
+ be omitted.
+
+On consent revoke, all running views will be stopped.
+
+ On session end and "session" consent revoke, first view cache information int
+ the module is reset.
Device ID Management
@@ -1648,17 +1975,21 @@ end_sesson=1&session_duration=30
It should replace the internally used device ID with the new one, and use it for all new requests, persistently storing it for further sessions. The Countly SDK should follow these steps:
@@ -1719,9 +2054,13 @@ end_sesson=1&session_duration=30 The currently used ones are the following:
Product Information:
@@ -2301,15 +2644,19 @@ Countly.heatmap_whitelist = ["https://you.domain1.com", "https://you.domain2.com
After a user gives a rating, a reserved event will be recorded with [CLY]_star_ratingas the key and following as the segmentation dictionary:
If a user dismisses the star-rating dialog without giving a rating, an event will not be recorded. The star-rating dialog's message and dismiss button title may be customized using the properties on the initial configuration object. @@ -2375,27 +2722,31 @@ CountlyConfiguration.starRatingDismissButtonTitle = "Custom Dismiss Button Title "recordRatingWidgetWithID" should record an event with the internal key "[CLY]_star_rating". The event should have the following segmentation:
Basic filtering (type checks) on the provided values should be performed. Mandatory values must be provided. Invalid widget ID's (non string or empty values) should not be accepted. Rating value should be modified, if necessary, so that it lies within the acceptable range of [1,5]. @@ -2414,18 +2765,23 @@ CountlyConfiguration.starRatingDismissButtonTitle = "Custom Dismiss Button Title The Feedback Widgets API provides access to three types of widgets:
They are shown using a very similar server API and basically the same processing. @@ -2436,27 +2792,32 @@ CountlyConfiguration.starRatingDismissButtonTitle = "Custom Dismiss Button Title
Feedback widgets can be used through three methods:
- Automatic Server Rendered Widget: The server rendered - widget is inserted in the web page or the UI, using a WebView, by the - SDK. -
-- Manually Rendered and Reported Widget: The client app - builds a custom UI, and the results are reported to the SDK manually. - Used in cases where the developer wants to use a custom UI. -
-- Server Rendered Widget in a Custom WebView: The SDK - builds a required URL to be used in a WebView. This would then be used - in the WebView of the client app of choice. -
-+ Automatic Server Rendered Widget: The server + rendered widget is inserted in the web page or the UI, using + a WebView, by the SDK. +
++ Manually Rendered and Reported Widget: The client + app builds a custom UI, and the results are reported to the SDK + manually. Used in cases where the developer wants to use a custom + UI. +
++ Server Rendered Widget in a Custom WebView: The + SDK builds a required URL to be used in a WebView. This would + then be used in the WebView of the client app of choice. +
+@@ -2569,13 +2930,17 @@ CountlyConfiguration.starRatingDismissButtonTitle = "Custom Dismiss Button Title
Automatic Feedback Widget reporting has 3 steps:
-presentFeedbackWidget call.
- presentFeedbackWidget call.
+
As explained in the 'Retrieving the List of Eligible Widgets' section, the first
step uses the getAvailableFeedbackWidgets function to communicate
@@ -2593,40 +2958,49 @@ CountlyConfiguration.starRatingDismissButtonTitle = "Custom Dismiss Button Title
It should be possible to provide 2 optional callbacks to the
presentFeedbackWidget call:
widgetShown) that is called when
- the widget is successfully presented (currently that would mean that there
- were no issues/errors while trying to show the dialog with the WebView).
- Also, we aren't verifying if the WebView is showing a working widget. If
- there are any issues during the display of the widget, this callback will
- return an error message.
- widgetClosed) that is called when
- the widget/dialog is closed (for mobile SDKs and for the web SDK that would
- mean slightly different things, but the main point is to have the host app/site
- notified of when the "feedback process" is over). If there are any issues
- during the closing of the widget, this callback will return an error message.
- widgetShown) that is called
+ when the widget is successfully presented (currently that would mean
+ that there were no issues/errors while trying to show the dialog
+ with the WebView). Also, we aren't verifying if the WebView is showing
+ a working widget. If there are any issues during the display of the
+ widget, this callback will return an error message.
+ widgetClosed) that is
+ called when the widget/dialog is closed (for mobile SDKs and for
+ the web SDK that would mean slightly different things, but the main
+ point is to have the host app/site notified of when the "feedback
+ process" is over). If there are any issues during the closing of
+ the widget, this callback will return an error message.
+ Manual feedback widget reporting has 3 steps:
-
As mentioned before, the first step uses
getAvailableFeedbackWidgets function, which is also used for automatic
@@ -2696,15 +3070,19 @@ CountlyConfiguration.starRatingDismissButtonTitle = "Custom Dismiss Button Title
to the type of the reported widget. That event should have the following segmentation:
platform - SDK platform
- app_version - host app version
- widget_id - respective widget ID
- platform - SDK platform
+ app_version - host app version
+ widget_id - respective widget ID
+ In addition to this segmentation which identifies the widget, the contents of @@ -2714,9 +3092,13 @@ CountlyConfiguration.starRatingDismissButtonTitle = "Custom Dismiss Button Title value:
closed - with the value of "1"
- closed - with the value of "1"
+ After this event has been added to the event queue, the event queue should be @@ -2788,8 +3170,12 @@ string constructFeedbackWidgetUrl(CountlyFeedbackWidget chosenWidget);
Additionally, there could be custom key values added to the user details. In this case, you would need to provide a means to set them:You may find more information on what data may be set for a user by following this link. @@ -2811,17 +3197,21 @@ string constructFeedbackWidgetUrl(CountlyFeedbackWidget chosenWidget);
The standard methods that should be provided by the SDK are as follows (provided as pseudo-code, naming conventions may differ from platform to platform):Note: when reporting to the server, assure the push, pushUnique, and pull parameters can provide multiple values for the same property as an array. @@ -2856,9 +3246,13 @@ string constructFeedbackWidgetUrl(CountlyFeedbackWidget chosenWidget);
@@ -2918,14 +3312,18 @@ string constructFeedbackWidgetUrl(CountlyFeedbackWidget chosenWidget);
Consent management in the SDK is done in 2 steps
During SDK init there should be a flag (e.g. requiresConsent) to
@@ -2950,67 +3348,71 @@ string constructFeedbackWidgetUrl(CountlyFeedbackWidget chosenWidget);
sessions -
- tracking when, how often, and how long users use your app/website
- events -
- allow events to be sent to the server (doesn't apply to other features using event mechanisms)
- location - allows location information to be sent. If consent has not been given, the SDK should force send an empty location upon begin_sessionto prevent the server from determining location via IP addresses
- views -
- allow tracking of which views/pages a user visits
- scrolls -
- allow user scrolls for scroll heatmap to be tracked
- clicks -
- allow user clicks for heatmaps as well as link clicks to be tracked
- forms -
- allow user's form submissions to be tracked
- crashes -
- allow crashes, exceptions, and errors to be tracked
- attribution -
- allows the campaign from which a user came to be tracked
- users -
- allow collecting/providing user information, including custom properties
- push - allows push notifications
- star-rating -
- allows their rating and feedback to be sent
- accessory-devices -
- allow accessories or wearable devices, such as Apple Watches, etc. to be detected
- apm -
- allows usage of application performance monitoring features
- remote-config -
- allows downloading of remote configs from the server
- feedback- allows showing things like surveys and NPS
- sessions -
+ tracking when, how often, and how long users use your app/website
+ events -
+ allow events to be sent to the server (doesn't apply to other features using event mechanisms)
+ location - allows location information to be sent. If consent has not been given, the SDK should force send an empty location upon begin_sessionto prevent the server from determining location via IP addresses
+ views -
+ allow tracking of which views/pages a user visits
+ scrolls -
+ allow user scrolls for scroll heatmap to be tracked
+ clicks -
+ allow user clicks for heatmaps as well as link clicks to be tracked
+ forms -
+ allow user's form submissions to be tracked
+ crashes -
+ allow crashes, exceptions, and errors to be tracked
+ attribution -
+ allows the campaign from which a user came to be tracked
+ users -
+ allow collecting/providing user information, including custom properties
+ push - allows push notifications
+ star-rating -
+ allows their rating and feedback to be sent
+ accessory-devices -
+ allow accessories or wearable devices, such as Apple Watches, etc. to be detected
+ apm -
+ allows usage of application performance monitoring features
+ remote-config -
+ allows downloading of remote configs from the server
+ feedback- allows showing things like surveys and NPS
+ Note that the available features may change depending on the platform. @@ -3246,10 +3648,15 @@ string constructFeedbackWidgetUrl(CountlyFeedbackWidget chosenWidget);
&aid={"rndid":[SOME_OTHER_ID_VALUE]}The SDK should have the following limits:
-
Limits the maximum size of all string keys.
@@ -3262,10 +3669,15 @@ string constructFeedbackWidgetUrl(CountlyFeedbackWidget chosenWidget);
Limits the size of all values in our key-value pairs.
@@ -3278,11 +3690,15 @@ string constructFeedbackWidgetUrl(CountlyFeedbackWidget chosenWidget);
Max amount of custom (dev-provided) segmentation in: @@ -3305,28 +3721,41 @@ string constructFeedbackWidgetUrl(CountlyFeedbackWidget chosenWidget);
- Custom APM Metrics -Maximum amount of breadcrumbs that can be recorded before the oldest one is deleted
-limits how many stack trace lines would be recorded per thread
-limits how many characters are allowed per stack trace line. This also limits the crash message length. @@ -3449,42 +3878,52 @@ npm install markdownlint --save-dev be changed after the following triggers:
Here is a list of metrics that need to be tracked. They are identified by the JSON key that should be used when sending these health metrics:
-- el (Integer) - The amount of error-level SDK logs triggered -
-- wl (Integer) - The amount of warning-level SDK logs - triggered -
-- sc (Integer) - The status code of the last failed request -
-- em (String) - The first 1000 characters of the response - returned by the last failed request -
-+ el (Integer) - The amount of error-level SDK + logs triggered +
++ wl (Integer) - The amount of warning-level SDK + logs triggered +
++ sc (Integer) - The status code of the last failed + request +
++ em (String) - The first 1000 characters of the + response returned by the last failed request +
+The module should expose the following methods for tracking, saving, and creating