Skip to content

Commit

Permalink
Merge pull request #17591 from wordpress-mobile/issue/17503-add-webvi…
Browse files Browse the repository at this point in the history
…ew-tracking

Add tracking to the WebKitViewController
  • Loading branch information
Emily Laguna authored Nov 30, 2021
2 parents 55b2ae3 + 3cc23e5 commit a1e0738
Show file tree
Hide file tree
Showing 49 changed files with 138 additions and 71 deletions.
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 @@ -272,10 +272,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 @@ -739,11 +752,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
28 changes: 24 additions & 4 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,12 +202,16 @@ class WebKitViewController: UIViewController, WebKitAuthenticatable {
webView.uiDelegate = self

loadWebViewRequest()

track(.webKitViewDisplayed)
}

override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
stopWaitingForConnectionRestored()
ReachabilityUtils.dismissNoInternetConnectionNotice()

track(.webKitViewDismissed)
}

@objc func loadWebViewRequest() {
Expand Down Expand Up @@ -387,7 +396,6 @@ class WebKitViewController: UIViewController, WebKitAuthenticatable {
}

// MARK: User Actions

@objc func close() {
dismiss(animated: true, completion: onClose)
}
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

0 comments on commit a1e0738

Please sign in to comment.