From 828be0e63c09e38e4ee6c32e75b0206bc85b0bad Mon Sep 17 00:00:00 2001 From: Nikita Korobeinikov Date: Tue, 2 Apr 2024 14:50:23 +0400 Subject: [PATCH 1/5] added delegate to listen analytics events --- Example/KinescopeExample/AppDelegate.swift | 9 ++++++++ .../Manager+KinescopeConfigurable.swift | 9 +++++++- .../Protocols/KinescopeConfigurable.swift | 5 +++- .../Service/Analytic/AnalyticsDelegate.swift | 17 ++++++++++++++ .../Analytic/AnalyticsLoggingService.swift | 18 +++++++++++++++ .../AnalyticsNetworkService.swift} | 9 +++----- .../Analytic/AnalyticsProxyService.swift | 23 +++++++++++++++++++ .../Service/Analytic/AnalyticsService.swift | 12 ++++++++++ Sources/KinescopeSDK/Shared/Kinescope.swift | 2 ++ 9 files changed, 96 insertions(+), 8 deletions(-) create mode 100644 Sources/KinescopeSDK/Service/Analytic/AnalyticsDelegate.swift create mode 100644 Sources/KinescopeSDK/Service/Analytic/AnalyticsLoggingService.swift rename Sources/KinescopeSDK/Service/{AnalyticsService.swift => Analytic/AnalyticsNetworkService.swift} (89%) create mode 100644 Sources/KinescopeSDK/Service/Analytic/AnalyticsProxyService.swift create mode 100644 Sources/KinescopeSDK/Service/Analytic/AnalyticsService.swift diff --git a/Example/KinescopeExample/AppDelegate.swift b/Example/KinescopeExample/AppDelegate.swift index e6b937e5..fdd383a4 100644 --- a/Example/KinescopeExample/AppDelegate.swift +++ b/Example/KinescopeExample/AppDelegate.swift @@ -30,6 +30,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { private func setupSDK() { Kinescope.shared.setConfig(.init()) + Kinescope.shared.setAnalytics(delegate: self) Kinescope.shared.set(logger: KinescopeDefaultLogger(), levels: KinescopeLoggerLevel.allCases) } @@ -50,3 +51,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } } + +extension AppDelegate: KinescopeAnalyticsDelegate { + + func didSendAnalytics(event: String, with data: String) { + debugPrint("Catched analytic event: \(event) with data \(data)") + } + +} diff --git a/Sources/KinescopeSDK/Manager/Manager+KinescopeConfigurable.swift b/Sources/KinescopeSDK/Manager/Manager+KinescopeConfigurable.swift index c34dad29..44c62181 100644 --- a/Sources/KinescopeSDK/Manager/Manager+KinescopeConfigurable.swift +++ b/Sources/KinescopeSDK/Manager/Manager+KinescopeConfigurable.swift @@ -22,9 +22,16 @@ extension Manager: KinescopeConfigurable { assetService: AssetNetworkService()) self.inspector = Inspector(videosService: VideosNetworkService(transport: Transport(), config: config)) - self.analyticFactory = AnalyticHandler(service: AnalyticsNetworkService(transport: Transport(), config: config)) + self.analyticFactory = AnalyticHandler(service: AnalyticsProxyService(wrappedServices: [ + AnalyticsNetworkService(transport: Transport(), config: config), + AnalyticsLoggingService() + ])) } + + func setAnalytics(delegate: any KinescopeAnalyticsDelegate) { + Kinescope.analyticDelegate = delegate + } func set(logger: KinescopeLogging, levels: [KinescopeLoggingLevel]) { self.logger = KinescopeLogger(logger: logger, levels: levels) diff --git a/Sources/KinescopeSDK/Protocols/KinescopeConfigurable.swift b/Sources/KinescopeSDK/Protocols/KinescopeConfigurable.swift index 303e562d..9ba114f1 100644 --- a/Sources/KinescopeSDK/Protocols/KinescopeConfigurable.swift +++ b/Sources/KinescopeSDK/Protocols/KinescopeConfigurable.swift @@ -10,9 +10,12 @@ public protocol KinescopeConfigurable { /// - parameter config: Configuration parameters required to connection func setConfig(_ config: KinescopeConfig) + + /// - parameter delegate: Delegate to listen for analytics sended from ``KinescopeVideoPlayer`` + func setAnalytics(delegate: KinescopeAnalyticsDelegate) /// - parameter logger: opportunity to set custom logger /// - parameter levels: levels of logging func set(logger: KinescopeLogging, levels: [KinescopeLoggingLevel]) - + } diff --git a/Sources/KinescopeSDK/Service/Analytic/AnalyticsDelegate.swift b/Sources/KinescopeSDK/Service/Analytic/AnalyticsDelegate.swift new file mode 100644 index 00000000..8113fee8 --- /dev/null +++ b/Sources/KinescopeSDK/Service/Analytic/AnalyticsDelegate.swift @@ -0,0 +1,17 @@ +// +// KinescopeAnalyticsDelegate.swift +// KinescopeSDK +// +// Created by Nikita Korobeinikov on 02.04.2024. +// + +import Foundation + +/// Delegate to listen for analytics sended from ``KinescopeVideoPlayer`` +public protocol KinescopeAnalyticsDelegate { + /// Fired when ``KinescopeVideoPlayer`` is sending any analytics `event` + /// - Parameters: + /// - event: name of the event + /// - data: serialized data in `String` format + func didSendAnalytics(event: String, with data: String) +} diff --git a/Sources/KinescopeSDK/Service/Analytic/AnalyticsLoggingService.swift b/Sources/KinescopeSDK/Service/Analytic/AnalyticsLoggingService.swift new file mode 100644 index 00000000..74cf9c63 --- /dev/null +++ b/Sources/KinescopeSDK/Service/Analytic/AnalyticsLoggingService.swift @@ -0,0 +1,18 @@ +// +// AnalyticsLoggingService.swift +// KinescopeSDK +// +// Created by Nikita Korobeinikov on 02.04.2024. +// + +import Foundation + +/// Implementation of ``AnalyticsService`` which can delegate sending to client code +final class AnalyticsLoggingService: AnalyticsService { + + func send(event: Analytics_Native) { + Kinescope.analyticDelegate?.didSendAnalytics(event: event.event, + with: event.textFormatString()) + } + +} diff --git a/Sources/KinescopeSDK/Service/AnalyticsService.swift b/Sources/KinescopeSDK/Service/Analytic/AnalyticsNetworkService.swift similarity index 89% rename from Sources/KinescopeSDK/Service/AnalyticsService.swift rename to Sources/KinescopeSDK/Service/Analytic/AnalyticsNetworkService.swift index 7cc9ca73..b39eba09 100644 --- a/Sources/KinescopeSDK/Service/AnalyticsService.swift +++ b/Sources/KinescopeSDK/Service/Analytic/AnalyticsNetworkService.swift @@ -1,16 +1,13 @@ // -// AnalyticsService.swift +// AnalyticsNetworkService.swift // KinescopeSDK // -// Created by Artemii Shabanov on 27.04.2021. +// Created by Nikita Korobeinikov on 02.04.2024. // import Foundation -protocol AnalyticsService { - func send(event: Analytics_Native) -} - +/// Implementation of ``AnalyticsService`` which will send analytic via network to kinescope dashboard final class AnalyticsNetworkService: AnalyticsService { // MARK: - Private Properties diff --git a/Sources/KinescopeSDK/Service/Analytic/AnalyticsProxyService.swift b/Sources/KinescopeSDK/Service/Analytic/AnalyticsProxyService.swift new file mode 100644 index 00000000..c2433214 --- /dev/null +++ b/Sources/KinescopeSDK/Service/Analytic/AnalyticsProxyService.swift @@ -0,0 +1,23 @@ +// +// AnalyticsProxyService.swift +// KinescopeSDK +// +// Created by Nikita Korobeinikov on 02.04.2024. +// + +import Foundation + +/// Implementation of ``AnalyticsService`` which can delegate sending to other services +final class AnalyticsProxyService: AnalyticsService { + + private let wrappedServices: [AnalyticsService] + + init(wrappedServices: [AnalyticsService]) { + self.wrappedServices = wrappedServices + } + + func send(event: Analytics_Native) { + wrappedServices.forEach { $0.send(event: event) } + } + +} diff --git a/Sources/KinescopeSDK/Service/Analytic/AnalyticsService.swift b/Sources/KinescopeSDK/Service/Analytic/AnalyticsService.swift new file mode 100644 index 00000000..f612a062 --- /dev/null +++ b/Sources/KinescopeSDK/Service/Analytic/AnalyticsService.swift @@ -0,0 +1,12 @@ +// +// AnalyticsService.swift +// KinescopeSDK +// +// Created by Artemii Shabanov on 27.04.2021. +// + +import Foundation + +protocol AnalyticsService { + func send(event: Analytics_Native) +} diff --git a/Sources/KinescopeSDK/Shared/Kinescope.swift b/Sources/KinescopeSDK/Shared/Kinescope.swift index 3704eb69..04381c1f 100644 --- a/Sources/KinescopeSDK/Shared/Kinescope.swift +++ b/Sources/KinescopeSDK/Shared/Kinescope.swift @@ -19,4 +19,6 @@ public enum Kinescope { static var analytic: KinescopeAnalyticHandlerFactory? { return (shared as? Manager)?.analyticFactory } + + static var analyticDelegate: KinescopeAnalyticsDelegate? = nil } From 504aada06f747a7c532067958e6163f60b15b797 Mon Sep 17 00:00:00 2001 From: Nikita Korobeinikov Date: Tue, 2 Apr 2024 15:11:31 +0400 Subject: [PATCH 2/5] fix missed eventTime --- Sources/KinescopeSDK/Events/InnerEventsProtoHandler.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/KinescopeSDK/Events/InnerEventsProtoHandler.swift b/Sources/KinescopeSDK/Events/InnerEventsProtoHandler.swift index 36ca90ef..58024d03 100644 --- a/Sources/KinescopeSDK/Events/InnerEventsProtoHandler.swift +++ b/Sources/KinescopeSDK/Events/InnerEventsProtoHandler.swift @@ -73,7 +73,7 @@ private extension InnerEventsProtoHandler { $0.device = dataStorage.device.provide() ?? .init() $0.session = dataStorage.session.provide() ?? .init() $0.playback = dataStorage.playback.provide() ?? .init() - $0.eventTime = .init() + $0.eventTime = .init(date: Date()) return } } From d65b7fd5d034fe1dc8e81ad90b0f7d6ed2f08ebc Mon Sep 17 00:00:00 2001 From: Nikita Korobeinikov Date: Tue, 2 Apr 2024 15:23:40 +0400 Subject: [PATCH 3/5] fix missing playback analytic data --- Sources/KinescopeSDK/Player/KinescopeVideoPlayer.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Sources/KinescopeSDK/Player/KinescopeVideoPlayer.swift b/Sources/KinescopeSDK/Player/KinescopeVideoPlayer.swift index 7f49d347..e1ed310e 100644 --- a/Sources/KinescopeSDK/Player/KinescopeVideoPlayer.swift +++ b/Sources/KinescopeSDK/Player/KinescopeVideoPlayer.swift @@ -139,6 +139,7 @@ public class KinescopeVideoPlayer: KinescopePlayer, KinescopePlayerBody, Fullscr public required convenience init(config: KinescopePlayerConfig) { self.init(config: config, dependencies: KinescopeVideoPlayerDependencies()) + self.configureAnalytic() } public func play() { From ab9ac437a33cffb5f589cf0e35cddc5ea1c50b10 Mon Sep 17 00:00:00 2001 From: Nikita Korobeinikov Date: Tue, 2 Apr 2024 15:23:48 +0400 Subject: [PATCH 4/5] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 425bb11e..d9cae09e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,3 +17,4 @@ - collecting of analytic events with playback data for Kinescope dashboard - textField in example project to allow user to input videoId - ability to manage options menu on player view +- ability to listen analytic events in `KinescopeAnalyticsDelegate` From a81e1722d8a585cd0a13e8b8f89eb11aa1a81e3d Mon Sep 17 00:00:00 2001 From: Nikita Korobeinikov Date: Tue, 2 Apr 2024 15:32:28 +0400 Subject: [PATCH 5/5] add some documentation --- DOCUMENTATION.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md index e5a7e5ed..d98a4921 100644 --- a/DOCUMENTATION.md +++ b/DOCUMENTATION.md @@ -191,3 +191,19 @@ To add new localization to strings from SDK, add in your project file "Kinescope # Error Handling KinescopePlayerView has inbox error handling logic and retry-mechanism. If video is not available or some error occured player will try to retry failed operation 10 times with 5 seconds delay between each attempt. If all attempts failed player will show error overlay with refresh button. + +# Analytics + +KinescopePlayer automaticaly send analytic events to Kinescope dashboard. You can get access to this events by implementing `KinescopeAnalyticsDelegate` protocol and set it like below + +```swift +Kinescope.shared.setAnalytics(delegate: yourDelegate) +``` + +In delegate you can check all playback data which we sending to Kinescope dashboard. + +If you want to log only events without playback data, you can intercept them using `logger`. + +```swift +Kinescope.shared.set(logger: KinescopeDefaultLogger(), levels: [KinescopeLoggerLevel.analytics]) +```