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

Add tracking to the WebKitViewController #17591

Merged
merged 30 commits into from
Nov 30, 2021
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
a9c0290
Add web view tracking items
Nov 29, 2021
fba764e
Update webkit reload and share tracking names
Nov 29, 2021
8b91a6f
Add an analyticsSource property to the WebKit Config and Controller
Nov 29, 2021
eee6206
Add event tracking to the WebKitViewController using the analytics so…
Nov 29, 2021
258b9a8
Add analytics source to the content coordinator
Nov 29, 2021
70f3781
Add source property to the PreviewWebKitViewController
Nov 29, 2021
f79d434
Add source property to the tests
Nov 29, 2021
d3417a9
Add analytics source to the User Profile Sheet
Nov 29, 2021
6764309
Add analytics source to the theme browser
Nov 29, 2021
8b82d2f
Add analytics source to the story example preview
Nov 29, 2021
c900581
Add analytics source to the stats views
Nov 29, 2021
93b7115
Add analytics source to the reader views
Nov 29, 2021
d9771f7
Add analytics source to the post/pages list and edit posts views
Nov 29, 2021
a8de77b
Add analytics source to the plugins view
Nov 29, 2021
7dfcf39
Add analytics source to the site settings views
Nov 29, 2021
22ea8f9
Add analytics source to the activity detail views
Nov 29, 2021
d1b6e3f
Add analytics source to the my site preview action
Nov 29, 2021
0bb79bc
Add analytics source to the comments views
Nov 29, 2021
24f820b
Add analytics source to the preview action
Nov 29, 2021
9295a15
Add analytics source to the Jetpack views
Nov 29, 2021
dbcdcd0
Add analytics source to the registration view
Nov 29, 2021
3be8962
Add analytics source to the about screens
Nov 29, 2021
084666d
Add analytics source to the Privacy Settings view
Nov 29, 2021
5345eb1
Add analytics source to the notifications view
Nov 29, 2021
fd058ff
Add analytics source to the media item view
Nov 29, 2021
5094e9c
Add analytics source to the invite person Learn more about roles button
Nov 29, 2021
6288b8f
Add PreviewWebKitView device change tracking
Nov 29, 2021
137a352
Add Jetpack App tracking items
Nov 29, 2021
86a06d4
Replace analytics source for about_screen and about_view to about
Nov 29, 2021
3cc23e5
Move the WebKitView dismissed tracking to viewWillDisappear
Nov 30, 2021
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
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class JetpackWebViewControllerFactory {
guard let url = URL(string: "https://wordpress.com/settings/jetpack/\(siteID)") else {
return nil
}
return WebViewControllerFactory.controller(url: url)
return WebViewControllerFactory.controller(url: url, source: "jetpack_web_settings")
}

}
34 changes: 34 additions & 0 deletions WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -264,10 +264,23 @@ import Foundation
// People
case peopleFilterChanged
case peopleUserInvited

// Login: Epilogue
case loginEpilogueChooseSiteTapped
case loginEpilogueCreateNewSiteTapped

// WebKitView
case webKitViewDisplayed
case webKitViewDismissed
case webKitViewOpenInSafariTapped
case webKitViewReloadTapped
case webKitViewShareTapped
case webKitViewNavigatedBack
case webKitViewNavigatedForward

// Preview WebKitView
case previewWebKitViewDeviceChanged

/// A String that represents the event
var value: String {
switch self {
Expand Down Expand Up @@ -716,11 +729,32 @@ import Foundation
return "people_management_filter_changed"
case .peopleUserInvited:
return "people_management_user_invited"

// Login: Epilogue
case .loginEpilogueChooseSiteTapped:
return "login_epilogue_choose_site_tapped"
case .loginEpilogueCreateNewSiteTapped:
return "login_epilogue_create_new_site_tapped"

// WebKitView
case .webKitViewDisplayed:
return "webkitview_displayed"
case .webKitViewDismissed:
return "webkitview_dismissed"
case .webKitViewOpenInSafariTapped:
return "webkitview_open_in_safari_tapped"
case .webKitViewReloadTapped:
return "webkitview_reload_tapped"
case .webKitViewShareTapped:
return "webkitview_share_tapped"
case .webKitViewNavigatedBack:
return "webkitview_navigated_back"
case .webKitViewNavigatedForward:
return "webkitview_navigated_forward"

case .previewWebKitViewDeviceChanged:
return "preview_webkitview_device_changed"

} // END OF SWITCH
}

Expand Down
6 changes: 3 additions & 3 deletions WordPress/Classes/Utility/ContentCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ protocol ContentCoordinator {
func displayStatsWithSiteID(_ siteID: NSNumber?, url: URL?) throws
func displayFollowersWithSiteID(_ siteID: NSNumber?, expirationTime: TimeInterval) throws
func displayStreamWithSiteID(_ siteID: NSNumber?) throws
func displayWebViewWithURL(_ url: URL)
func displayWebViewWithURL(_ url: URL, source: String)
func displayFullscreenImage(_ image: UIImage)
func displayPlugin(withSlug pluginSlug: String, on siteSlug: String) throws
func displayBackupWithSiteID(_ siteID: NSNumber?) throws
Expand Down Expand Up @@ -132,13 +132,13 @@ struct DefaultContentCoordinator: ContentCoordinator {
controller?.navigationController?.pushViewController(browseViewController, animated: true)
}

func displayWebViewWithURL(_ url: URL) {
func displayWebViewWithURL(_ url: URL, source: String) {
if UniversalLinkRouter(routes: UniversalLinkRouter.readerRoutes).canHandle(url: url) {
UniversalLinkRouter(routes: UniversalLinkRouter.readerRoutes).handle(url: url, source: .inApp(presenter: controller))
return
}

let webViewController = WebViewControllerFactory.controllerAuthenticatedWithDefaultAccount(url: url)
let webViewController = WebViewControllerFactory.controllerAuthenticatedWithDefaultAccount(url: url, source: source)
let navController = UINavigationController(rootViewController: webViewController)
controller?.present(navController, animated: true)
}
Expand Down
2 changes: 1 addition & 1 deletion WordPress/Classes/Utility/Spotlight/SearchManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ fileprivate extension SearchManager {
WPTabBarController.sharedInstance().showMySitesTab()
closePreviewIfNeeded(for: apost)

let controller = PreviewWebKitViewController(post: apost)
let controller = PreviewWebKitViewController(post: apost, source: "spotlight_preview_post")
controller.trackOpenEvent()
let navWrapper = LightNavigationController(rootViewController: controller)
if WPTabBarController.sharedInstance()?.traitCollection.userInterfaceIdiom == .pad {
Expand Down
26 changes: 23 additions & 3 deletions WordPress/Classes/Utility/WebKitViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Foundation
import Gridicons
import UIKit
import WebKit
import WordPressShared

protocol WebKitAuthenticatable {
var authenticator: RequestAuthenticator? { get }
Expand All @@ -27,6 +28,7 @@ class WebKitViewController: UIViewController, WebKitAuthenticatable {
@objc let webView: WKWebView
@objc let progressView = WebProgressView()
@objc let titleView = NavigationTitleView()
let analyticsSource: String?

@objc lazy var backButton: UIBarButtonItem = {
let button = UIBarButtonItem(image: UIImage.gridicon(.chevronLeft).imageFlippedForRightToLeftLayoutDirection(),
Expand Down Expand Up @@ -120,12 +122,14 @@ class WebKitViewController: UIViewController, WebKitAuthenticatable {
linkBehavior = configuration.linkBehavior
opensNewInSafari = configuration.opensNewInSafari
onClose = configuration.onClose
analyticsSource = configuration.analyticsSource

super.init(nibName: nil, bundle: nil)
hidesBottomBarWhenPushed = true
startObservingWebView()
}

fileprivate init(url: URL, parent: WebKitViewController, configuration: WKWebViewConfiguration) {
fileprivate init(url: URL, parent: WebKitViewController, configuration: WKWebViewConfiguration, source: String? = nil) {
webView = WKWebView(frame: .zero, configuration: configuration)
self.url = url
customOptionsButton = parent.customOptionsButton
Expand All @@ -136,6 +140,7 @@ class WebKitViewController: UIViewController, WebKitAuthenticatable {
navigationDelegate = parent.navigationDelegate
linkBehavior = parent.linkBehavior
opensNewInSafari = parent.opensNewInSafari
analyticsSource = source
super.init(nibName: nil, bundle: nil)
hidesBottomBarWhenPushed = true
startObservingWebView()
Expand Down Expand Up @@ -197,6 +202,8 @@ class WebKitViewController: UIViewController, WebKitAuthenticatable {
webView.uiDelegate = self

loadWebViewRequest()

track(.webKitViewDisplayed)
}

override func viewWillDisappear(_ animated: Bool) {
Expand Down Expand Up @@ -390,6 +397,7 @@ class WebKitViewController: UIViewController, WebKitAuthenticatable {

@objc func close() {
dismiss(animated: true, completion: onClose)
track(.webKitViewDismissed)
}

@objc func share() {
Expand All @@ -407,26 +415,30 @@ class WebKitViewController: UIViewController, WebKitAuthenticatable {
}
}
present(activityViewController, animated: true)

track(.webKitViewShareTapped)
}

@objc func refresh() {
webView.reload()
track(.webKitViewReloadTapped)
}

@objc func goBack() {
webView.goBack()
track(.webKitViewNavigatedBack)
}

@objc func goForward() {
webView.goForward()
track(.webKitViewNavigatedForward)
}

@objc func openInSafari() {
guard let url = webView.url else {
return
}
UIApplication.shared.open(url)
track(.webKitViewOpenInSafariTapped)
}

///location is used to present a document menu in tap location on iOS 13
Expand Down Expand Up @@ -472,6 +484,14 @@ class WebKitViewController: UIViewController, WebKitAuthenticatable {
navigationItem.titleView?.accessibilityValue = titleView.titleLabel.text
navigationItem.titleView?.accessibilityTraits = .updatesFrequently
}

private func track(_ event: WPAnalyticsEvent) {
let properties: [AnyHashable: Any] = [
"source": analyticsSource ?? "unknown"
]

WPAnalytics.track(event, properties: properties)
}
}

extension WebKitViewController: WKNavigationDelegate {
Expand Down Expand Up @@ -537,7 +557,7 @@ extension WebKitViewController: WKUIDelegate {
if opensNewInSafari {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
} else {
let controller = WebKitViewController(url: url, parent: self, configuration: configuration)
let controller = WebKitViewController(url: url, parent: self, configuration: configuration, source: analyticsSource)
let navController = UINavigationController(rootViewController: controller)
present(navController, animated: true)
return controller.webView
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class WebViewControllerConfiguration: NSObject {
@objc var optionsButton: UIBarButtonItem?
@objc var secureInteraction = false
@objc var addsWPComReferrer = false
@objc var analyticsSource: String?

/// Opens any new pages in Safari. Otherwise, a new web view will be opened
var opensNewInSafari = false
Expand Down
29 changes: 16 additions & 13 deletions WordPress/Classes/Utility/WebViewControllerFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,45 +6,48 @@ class WebViewControllerFactory: NSObject {
override init() {
}

@objc static func controller(configuration: WebViewControllerConfiguration) -> WebKitViewController {
@objc static func controller(configuration: WebViewControllerConfiguration, source: String) -> WebKitViewController {
configuration.analyticsSource = source

let controller = WebKitViewController(configuration: configuration)
return controller
}

@objc static func controller(url: URL) -> UIViewController {
@objc static func controller(url: URL, source: String) -> UIViewController {
let configuration = WebViewControllerConfiguration(url: url)
return controller(configuration: configuration)
return controller(configuration: configuration, source: source)
}

@objc static func controller(url: URL, title: String) -> UIViewController {
@objc static func controller(url: URL, title: String, source: String) -> UIViewController {
let configuration = WebViewControllerConfiguration(url: url)
configuration.customTitle = title
return controller(configuration: configuration)
return controller(configuration: configuration, source: source)
}

@objc static func controller(url: URL, blog: Blog, withDeviceModes: Bool = false) -> UIViewController {
@objc static func controller(url: URL, blog: Blog, source: String, withDeviceModes: Bool = false) -> UIViewController {
let configuration = WebViewControllerConfiguration(url: url)
configuration.analyticsSource = source
configuration.authenticate(blog: blog)
return withDeviceModes ? PreviewWebKitViewController(configuration: configuration) : controller(configuration: configuration)
return withDeviceModes ? PreviewWebKitViewController(configuration: configuration) : controller(configuration: configuration, source: source)
}

@objc static func controller(url: URL, account: WPAccount) -> UIViewController {
@objc static func controller(url: URL, account: WPAccount, source: String) -> UIViewController {
let configuration = WebViewControllerConfiguration(url: url)
configuration.authenticate(account: account)
return controller(configuration: configuration)
return controller(configuration: configuration, source: source)
}

@objc static func controllerAuthenticatedWithDefaultAccount(url: URL) -> UIViewController {
@objc static func controllerAuthenticatedWithDefaultAccount(url: URL, source: String) -> UIViewController {
let configuration = WebViewControllerConfiguration(url: url)
configuration.authenticateWithDefaultAccount()
return controller(configuration: configuration)
return controller(configuration: configuration, source: source)
}

static func controllerWithDefaultAccountAndSecureInteraction(url: URL) -> WebKitViewController {
static func controllerWithDefaultAccountAndSecureInteraction(url: URL, source: String) -> WebKitViewController {
let configuration = WebViewControllerConfiguration(url: url)
configuration.authenticateWithDefaultAccount()
configuration.secureInteraction = true

return controller(configuration: configuration)
return controller(configuration: configuration, source: source)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class ActivityDetailViewController: UIViewController, StoryboardLoadable {
return
}

let navController = UINavigationController(rootViewController: WebViewControllerFactory.controller(url: url))
let navController = UINavigationController(rootViewController: WebViewControllerFactory.controller(url: url, source: "activity_detail_warning"))

present(navController, animated: true)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ struct ActivityContentRouter: ContentRouter {
let pluginSlug = pluginRange.pluginSlug
try? coordinator.displayPlugin(withSlug: pluginSlug, on: siteSlug)
default:
coordinator.displayWebViewWithURL(url)
coordinator.displayWebViewWithURL(url, source: "activity_detail_route")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1865,7 +1865,7 @@ - (void)showViewSiteFromSource:(BlogDetailsNavigationSource)source

NSURL *targetURL = [NSURL URLWithString:self.blog.homeURL];

UIViewController *webViewController = [WebViewControllerFactory controllerWithUrl:targetURL blog:self.blog withDeviceModes:true];
UIViewController *webViewController = [WebViewControllerFactory controllerWithUrl:targetURL blog:self.blog source:@"my_site_view_site" withDeviceModes:true];
LightNavigationController *navController = [[LightNavigationController alloc] initWithRootViewController:webViewController];
if (self.traitCollection.userInterfaceIdiom == UIUserInterfaceIdiomPad) {
navController.modalPresentationStyle = UIModalPresentationFullScreen;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public extension SiteSettingsViewController {
let configuration = WebViewControllerConfiguration(url: url)
configuration.secureInteraction = true
configuration.authenticate(blog: blog)
let controller = WebViewControllerFactory.controller(configuration: configuration)
let controller = WebViewControllerFactory.controller(configuration: configuration, source: "site_settings_show_purchases")
controller.loadViewIfNeeded()
controller.navigationItem.titleView = nil
controller.title = NSLocalizedString("Purchases", comment: "Title of screen showing site purchases")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ open class DateAndTimeFormatSettingsViewController: UITableViewController {
guard let url = URL(string: DateAndTimeFormatSettingsViewController.learnMoreUrl) else {
return
}
let webViewController = WebViewControllerFactory.controller(url: url)
let webViewController = WebViewControllerFactory.controller(url: url, source: "site_settings_date_time_format_learn_more")

if presentingViewController != nil {
navigationController?.pushViewController(webViewController, animated: true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ extension SiteSettingsViewController {
guard let url = URL(string: self.ampSupportURL) else {
return
}
let webViewController = WebViewControllerFactory.controller(url: url)
let webViewController = WebViewControllerFactory.controller(url: url, source: "site_settings_amp_footer")

if presentingViewController != nil {
navigationController?.pushViewController(webViewController, animated: true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -919,7 +919,8 @@ - (void)showStartOverForBlog:(Blog *)blog
[self.navigationController pushViewController:viewController animated:YES];
} else {
NSURL *targetURL = [NSURL URLWithString:EmptySiteSupportURL];
UIViewController *webViewController = [WebViewControllerFactory controllerWithUrl:targetURL];

UIViewController *webViewController = [WebViewControllerFactory controllerWithUrl:targetURL source:@"site_settings_start_over"];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:webViewController];
[self presentViewController:navController animated:YES completion:nil];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ private extension CommentDetailViewController {
return
}

let viewController = WebViewControllerFactory.controllerAuthenticatedWithDefaultAccount(url: url)
let viewController = WebViewControllerFactory.controllerAuthenticatedWithDefaultAccount(url: url, source: "comment_detail")
let navigationControllerToPresent = UINavigationController(rootViewController: viewController)

present(navigationControllerToPresent, animated: true, completion: nil)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ - (void)openWebViewWithURL:(NSURL *)url
return;
}

UIViewController *webViewController = [WebViewControllerFactory controllerAuthenticatedWithDefaultAccountWithUrl:url];
UIViewController *webViewController = [WebViewControllerFactory controllerAuthenticatedWithDefaultAccountWithUrl:url source:@"comments"];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:webViewController];
[self presentViewController:navController animated:YES completion:nil];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ extension RegisterDomainSuggestionsViewController: NUXButtonViewControllerDelega
return
}

let webViewController = WebViewControllerFactory.controllerWithDefaultAccountAndSecureInteraction(url: url)
let webViewController = WebViewControllerFactory.controllerWithDefaultAccountAndSecureInteraction(url: url, source: "domains_register")
let navController = LightNavigationController(rootViewController: webViewController)

// WORKAROUND: The reason why we have to use this mechanism to detect success and failure conditions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class JetpackRestoreCompleteViewController: BaseRestoreCompleteViewController {
return
}

let webVC = WebViewControllerFactory.controller(url: homeURL)
let webVC = WebViewControllerFactory.controller(url: homeURL, source: "jetpack_restore_complete")
let navigationVC = LightNavigationController(rootViewController: webVC)

self.present(navigationVC, animated: true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ open class JetpackSettingsViewController: UITableViewController {
guard let url = URL(string: JetpackSettingsViewController.learnMoreUrl) else {
return
}
let webViewController = WebViewControllerFactory.controller(url: url)
let webViewController = WebViewControllerFactory.controller(url: url, source: "jetpack_settings_learn_more")

if presentingViewController != nil {
navigationController?.pushViewController(webViewController, animated: true)
Expand Down
Loading