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

RUM-4313 feat: Add WebViewTracking for Obj-c #1854

Merged
merged 6 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Unreleased

- [FEATURE] `DatadogTrace` now supports OpenTelemetry. See [#1828][]
- [FEATURE] `DatadogWebViewTracking` is now available for Obj-C. See [#1854][]

# 2.11.0 / 08-05-2024

Expand Down Expand Up @@ -662,6 +663,7 @@ Release `2.0` introduces breaking changes. Follow the [Migration Guide](MIGRATIO
[#1721]: https://github.com/DataDog/dd-sdk-ios/pull/1721
[#1803]: https://github.com/DataDog/dd-sdk-ios/pull/1803
[#1807]: https://github.com/DataDog/dd-sdk-ios/pull/1807
[#1854]: https://github.com/DataDog/dd-sdk-ios/pull/1854
[#1828]: https://github.com/DataDog/dd-sdk-ios/pull/1828
[@00fa9a]: https://github.com/00FA9A
[@britton-earnin]: https://github.com/Britton-Earnin
Expand Down
16 changes: 16 additions & 0 deletions Datadog/Datadog.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,8 @@
6172472725D673D7007085B3 /* CrashContextTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6172472625D673D7007085B3 /* CrashContextTests.swift */; };
617247AF25DA9BEA007085B3 /* CrashReportingObjcHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 617247AE25DA9BEA007085B3 /* CrashReportingObjcHelpers.m */; };
617247B825DAB0E2007085B3 /* DDCrashReportBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 617247B725DAB0E2007085B3 /* DDCrashReportBuilder.swift */; };
6174D6042BFB9AB600EC7469 /* WebViewTracking+objc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6174D6032BFB9AB600EC7469 /* WebViewTracking+objc.swift */; };
6174D6062BFB9D6400EC7469 /* DDWebViewTracking+apiTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6174D6052BFB9D5500EC7469 /* DDWebViewTracking+apiTests.m */; };
6175922B2A6FA8EE0073F431 /* DatadogSessionReplay.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6133D1F52A6ED9E100384BEF /* DatadogSessionReplay.framework */; };
6175922D2A6FADDD0073F431 /* DatadogSessionReplay.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6133D1F52A6ED9E100384BEF /* DatadogSessionReplay.framework */; };
6175C3512BCE66DB006FAAB0 /* TraceContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6175C3502BCE66DB006FAAB0 /* TraceContext.swift */; };
Expand Down Expand Up @@ -2386,6 +2388,8 @@
617247AD25DA9BEA007085B3 /* CrashReportingObjcHelpers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CrashReportingObjcHelpers.h; sourceTree = "<group>"; };
617247AE25DA9BEA007085B3 /* CrashReportingObjcHelpers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CrashReportingObjcHelpers.m; sourceTree = "<group>"; };
617247B725DAB0E2007085B3 /* DDCrashReportBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DDCrashReportBuilder.swift; sourceTree = "<group>"; };
6174D6032BFB9AB600EC7469 /* WebViewTracking+objc.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WebViewTracking+objc.swift"; sourceTree = "<group>"; };
6174D6052BFB9D5500EC7469 /* DDWebViewTracking+apiTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "DDWebViewTracking+apiTests.m"; sourceTree = "<group>"; };
6175C3502BCE66DB006FAAB0 /* TraceContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TraceContext.swift; sourceTree = "<group>"; };
617699172A860D9D0030022B /* HTTPClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPClient.swift; sourceTree = "<group>"; };
6176991A2A86121B0030022B /* HTTPClientMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPClientMock.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3335,6 +3339,7 @@
3CE11A3B29F7BEE700202522 /* DatadogWebViewTracking */ = {
isa = PBXGroup;
children = (
6174D6072BFCCDA400EC7469 /* ObjC */,
3C85D41429F7C59C00AFF894 /* WebViewTracking.swift */,
D29732462A5C108700827599 /* DDScriptMessageHandler.swift */,
D29732472A5C108700827599 /* MessageEmitter.swift */,
Expand Down Expand Up @@ -4742,6 +4747,14 @@
path = ../DatadogCrashReporting/Tests;
sourceTree = "<group>";
};
6174D6072BFCCDA400EC7469 /* ObjC */ = {
isa = PBXGroup;
children = (
6174D6032BFB9AB600EC7469 /* WebViewTracking+objc.swift */,
);
path = ObjC;
sourceTree = "<group>";
};
617699162A8608C20030022B /* Context */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -4993,6 +5006,7 @@
A728ADAD2934EB0300397996 /* DDW3CHTTPHeadersWriter+apiTests.m */,
3C1890132ABDE99200CE9E73 /* DDURLSessionInstrumentationTests+apiTests.m */,
A795069D2B974CAA00AC4814 /* DDSessionReplay+apiTests.m */,
6174D6052BFB9D5500EC7469 /* DDWebViewTracking+apiTests.m */,
);
path = ObjcAPITests;
sourceTree = "<group>";
Expand Down Expand Up @@ -7755,6 +7769,7 @@
files = (
3C85D42129F7C5C900AFF894 /* WebViewTracking.swift in Sources */,
D297324B2A5C108700827599 /* MessageEmitter.swift in Sources */,
6174D6042BFB9AB600EC7469 /* WebViewTracking+objc.swift in Sources */,
D29732492A5C108700827599 /* DDScriptMessageHandler.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -7848,6 +7863,7 @@
D29A9FDA29DDC6D0005C54A4 /* RUMEventFileOutputTests.swift in Sources */,
D28F836829C9E71D00EF8EA2 /* DDSpanTests.swift in Sources */,
61B8BA91281812F60068AFF4 /* KronosInternetAddressTests.swift in Sources */,
6174D6062BFB9D6400EC7469 /* DDWebViewTracking+apiTests.m in Sources */,
614798962A459AA80095CB02 /* DDTraceTests.swift in Sources */,
D25085102976E30000E931C3 /* DatadogRemoteFeatureMock.swift in Sources */,
6167E6DD2B811A8300C3CA2D /* AppHangsMonitoringTests.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,5 +134,4 @@ - (void)testDDRUMConfigurationAPI {

#pragma clang diagnostic pop


@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2019-Present Datadog, Inc.
*/

#import <XCTest/XCTest.h>
@import DatadogWebViewTracking;
@import WebKit;

@interface WebViewMock: WKWebView
@end

@implementation WebViewMock
@end

// MARK: - DDWebViewTracking tests

@interface DDWebViewTracking_apiTests : XCTestCase
@end

/*
* `WebViewTracking` APIs smoke tests - minimal assertions, mainly check if the interface is available to Objc.
*/
@implementation DDWebViewTracking_apiTests

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-value"

- (void)testDDWebViewTrackingAPI {
WebViewMock *webView = [WebViewMock new];
[DDWebViewTracking enableWithWebView:webView
hosts:[NSSet<NSString*> setWithArray:@[@"host1.com", @"host2.com"]]
logsSampleRate:100.0
with:nil];
[DDWebViewTracking disableWithWebView:webView];
}

- (void)testDDWebViewTrackingSessionReplayConfigurationAPI {
DDWebViewTrackingSessionReplayConfiguration *config = [[DDWebViewTrackingSessionReplayConfiguration alloc] init];
XCTAssertEqual(config.privacyLevel, DDPrivacyLevelMask);
config.privacyLevel = DDPrivacyLevelAllow;
XCTAssertEqual(config.privacyLevel, DDPrivacyLevelAllow);
config.privacyLevel = DDPrivacyLevelMaskUserInput;
XCTAssertEqual(config.privacyLevel, DDPrivacyLevelMaskUserInput);
}

#pragma clang diagnostic pop

@end
116 changes: 116 additions & 0 deletions DatadogWebViewTracking/Sources/ObjC/WebViewTracking+objc.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2019-Present Datadog, Inc.
*/

import Foundation
#if os(tvOS)
#warning("Datadog WebView Tracking does not support tvOS")
#else
import WebKit
#endif

@objc(DDWebViewTracking)
@_spi(objc)
public final class objc_WebViewTracking: NSObject {
override private init() { }

/// The Session Replay configuration to capture records coming from the web view.
///
/// Setting the Session Replay configuration in `WebViewTracking` will enable transmitting replay data from
/// the Datadog Browser SDK installed in the web page. Datadog will then be able to combine the native
/// and web recordings in a single replay.
@objc(DDWebViewTrackingSessionReplayConfiguration)
@_spi(objc)
public final class SessionReplayConfiguration: NSObject {
/// Available privacy levels for content masking.
@objc(DDPrivacyLevel)
@_spi(objc)
public enum PrivacyLevel: Int {
/// Record all content.
case allow
/// Mask all content.
case mask
/// Mask input elements, but record all other content.
case maskUserInput

internal var toSwift: WebViewTracking.SessionReplayConfiguration.PrivacyLevel {
switch self {
case .allow: return .allow
case .mask: return .mask
case .maskUserInput: return .maskUserInput
}
}
}

/// The privacy level to use for the web view replay recording.
@objc public var privacyLevel: PrivacyLevel

/// Creates Webview Session Replay configuration.
///
/// - Parameters:
/// - privacyLevel: The way sensitive content (e.g. text) should be masked. Default: `.mask`.
@objc
override public init() {
self.privacyLevel = .mask
}

/// Creates Webview Session Replay configuration.
///
/// - Parameters:
/// - privacyLevel: The way sensitive content (e.g. text) should be masked. Default: `.mask`.
@objc
public init(
privacyLevel: PrivacyLevel
) {
self.privacyLevel = privacyLevel
}

internal var toSwift: WebViewTracking.SessionReplayConfiguration {
return .init(
privacyLevel: privacyLevel.toSwift
)
}
}

/// Enables SDK to correlate Datadog RUM events and Logs from the WebView with native RUM session.
///
/// If the content loaded in WebView uses Datadog Browser SDK (`v4.2.0+`) and matches specified
/// `hosts`, web events will be correlated with the RUM session from native SDK.
///
/// - Parameters:
/// - webView: The web-view to track.
/// - hosts: A set of hosts instrumented with Browser SDK to capture Datadog events from.
/// - logsSampleRate: The sampling rate for logs coming from the WebView. Must be a value between `0` and `100`,
/// where 0 means no logs will be sent and 100 means all will be uploaded. Default: `100`.
/// - sessionReplayConfiguration: Session Replay configuration to enable linking Web and Native replays.
/// - core: Datadog SDK core to use for tracking.
@objc
public static func enable(
webView: WKWebView,
hosts: Set<String> = [],
logsSampleRate: Float = 100,
with configuration: SessionReplayConfiguration? = nil
) {
WebViewTracking.enable(
webView: webView,
hosts: hosts,
logsSampleRate: logsSampleRate,
sessionReplayConfiguration: configuration?.toSwift
)
}

/// Disables Datadog iOS SDK and Datadog Browser SDK integration.
///
/// Removes Datadog's ScriptMessageHandler and UserScript from the caller.
/// - Note: This method **must** be called when the webview can be deinitialized.
///
/// - Parameter webView: The web-view to stop tracking.
@objc
public static func disable(
webView: WKWebView
) {
WebViewTracking.disable(webView: webView)
}
}