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

[Issue #125] Enable DatadogCore and DatadogLogs to compile on watchOS platform #1918

1 change: 1 addition & 0 deletions DatadogCore.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Pod::Spec.new do |s|
s.swift_version = '5.9'
s.ios.deployment_target = '12.0'
s.tvos.deployment_target = '12.0'
s.watchos.deployment_target = '7.0'

s.source = { :git => "https://github.com/DataDog/dd-sdk-ios.git", :tag => s.version.to_s }

Expand Down
27 changes: 17 additions & 10 deletions DatadogCore/Sources/Core/Context/ApplicationStatePublisher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,19 @@
#if canImport(UIKit)
import UIKit
import DatadogInternal
#if canImport(WatchKit)
import WatchKit
#endif

internal final class ApplicationStatePublisher: ContextValuePublisher {
typealias Snapshot = AppStateHistory.Snapshot

private static var currentApplicationState: UIApplication.State {
private static var currentApplicationState: ApplicationState {
#if canImport(WatchKit)
WKExtension.dd.shared.applicationState
#else
UIApplication.dd.managedShared?.applicationState ?? .active // fallback to most expected state
#endif
}

/// The default publisher queue.
Expand Down Expand Up @@ -85,7 +92,7 @@ internal final class ApplicationStatePublisher: ContextValuePublisher {
/// - dateProvider: The date provider for the Application state snapshot timestamp.
/// - notificationCenter: The notification center where this publisher observes `UIApplication` notifications.
convenience init(
applicationState: UIApplication.State = ApplicationStatePublisher.currentApplicationState,
applicationState: ApplicationState = ApplicationStatePublisher.currentApplicationState,
queue: DispatchQueue = ApplicationStatePublisher.defaultQueue,
dateProvider: DateProvider = SystemDateProvider(),
notificationCenter: NotificationCenter = .default
Expand All @@ -100,10 +107,10 @@ internal final class ApplicationStatePublisher: ContextValuePublisher {

func publish(to receiver: @escaping ContextValueReceiver<AppStateHistory>) {
queue.async { self.receiver = receiver }
notificationCenter.addObserver(self, selector: #selector(applicationDidBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil)
notificationCenter.addObserver(self, selector: #selector(applicationWillResignActive), name: UIApplication.willResignActiveNotification, object: nil)
notificationCenter.addObserver(self, selector: #selector(applicationDidEnterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
notificationCenter.addObserver(self, selector: #selector(applicationWillEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
notificationCenter.addObserver(self, selector: #selector(applicationDidBecomeActive), name: ApplicationNotifications.didBecomeActive, object: nil)
notificationCenter.addObserver(self, selector: #selector(applicationWillResignActive), name: ApplicationNotifications.willResignActive, object: nil)
notificationCenter.addObserver(self, selector: #selector(applicationDidEnterBackground), name: ApplicationNotifications.didEnterBackground, object: nil)
notificationCenter.addObserver(self, selector: #selector(applicationWillEnterForeground), name: ApplicationNotifications.willEnterForeground, object: nil)
}

@objc
Expand Down Expand Up @@ -135,10 +142,10 @@ internal final class ApplicationStatePublisher: ContextValuePublisher {
}

func cancel() {
notificationCenter.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil)
notificationCenter.removeObserver(self, name: UIApplication.willResignActiveNotification, object: nil)
notificationCenter.removeObserver(self, name: UIApplication.didEnterBackgroundNotification, object: nil)
notificationCenter.removeObserver(self, name: UIApplication.willEnterForegroundNotification, object: nil)
notificationCenter.removeObserver(self, name: ApplicationNotifications.didBecomeActive, object: nil)
notificationCenter.removeObserver(self, name: ApplicationNotifications.willResignActive, object: nil)
notificationCenter.removeObserver(self, name: ApplicationNotifications.didEnterBackground, object: nil)
notificationCenter.removeObserver(self, name: ApplicationNotifications.willEnterForeground, object: nil)
queue.async { self.receiver = nil }
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ internal protocol BackgroundTaskCoordinator {
import UIKit
import DatadogInternal

#if !os(watchOS)
/// Bridge protocol that calls corresponding `UIApplication` interface for background tasks. Allows easier testablity.
internal protocol UIKitAppBackgroundTaskCoordinator {
func beginBgTask(_ handler: (() -> Void)?) -> UIBackgroundTaskIdentifier
Expand Down Expand Up @@ -69,6 +70,7 @@ internal class AppBackgroundTaskCoordinator: BackgroundTaskCoordinator {
self.currentTaskId = nil
}
}
#endif

/// Bridge protocol that matches `ProcessInfo` interface for background activity. Allows easier testablity.
internal protocol ProcessInfoActivityCoordinator {
Expand Down
4 changes: 4 additions & 0 deletions DatadogCore/Sources/Core/Upload/FeatureUpload.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ internal struct FeatureUpload {
let backgroundTaskCoordinator: BackgroundTaskCoordinator?
switch (backgroundTasksEnabled, isRunFromExtension) {
case (true, false):
#if os(watchOS)
backgroundTaskCoordinator = ExtensionBackgroundTaskCoordinator()
#else
backgroundTaskCoordinator = AppBackgroundTaskCoordinator()
#endif
case (true, true):
backgroundTaskCoordinator = ExtensionBackgroundTaskCoordinator()
case (false, _):
Expand Down
2 changes: 2 additions & 0 deletions DatadogCore/Sources/Core/Upload/URLSessionClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ internal class URLSessionClient: HTTPClient {
configuration.urlCache = nil
configuration.connectionProxyDictionary = proxyConfiguration

#if !os(watchOS)
// URLSession does not set the `Proxy-Authorization` header automatically when using a proxy
// configuration. We manually set the HTTP basic authentication header.
if let user = proxyConfiguration?[kCFProxyUsernameKey] as? String,
let password = proxyConfiguration?[kCFProxyPasswordKey] as? String {
let authorization = basicHTTPAuthentication(username: user, password: password)
configuration.httpAdditionalHeaders = ["Proxy-Authorization": authorization]
}
#endif

self.init(session: URLSession(configuration: configuration))
}
Expand Down
6 changes: 6 additions & 0 deletions DatadogCore/Sources/Kronos/KronosDNSResolver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ internal final class KronosDNSResolver {
timeout: TimeInterval = kDefaultTimeout,
completion: @escaping ([KronosInternetAddress]) -> Void
) {
#if os(watchOS)
completion([])
#else
let callback: CFHostClientCallBack = { host, _, _, info in
guard let info = info else {
return
Expand Down Expand Up @@ -79,8 +82,10 @@ internal final class KronosDNSResolver {
CFHostSetClient(hostReference, callback, &clientContext)
CFHostScheduleWithRunLoop(hostReference, CFRunLoopGetMain(), CFRunLoopMode.commonModes.rawValue)
CFHostStartInfoResolution(hostReference, .addresses, nil)
#endif
}

#if !os(watchOS)
@objc
private func onTimeout() {
defer {
Expand All @@ -99,4 +104,5 @@ internal final class KronosDNSResolver {
CFHostUnscheduleFromRunLoop(hostReference, CFRunLoopGetMain(), CFRunLoopMode.commonModes.rawValue)
CFHostSetClient(hostReference, nil, nil)
}
#endif
}
1 change: 1 addition & 0 deletions DatadogInternal.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Pod::Spec.new do |s|
s.swift_version = '5.9'
s.ios.deployment_target = '12.0'
s.tvos.deployment_target = '12.0'
s.watchos.deployment_target = '7.0'

s.source = { :git => "https://github.com/DataDog/dd-sdk-ios.git", :tag => s.version.to_s }

Expand Down
10 changes: 9 additions & 1 deletion DatadogInternal/Sources/Context/AppState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,16 @@ extension AppStateHistory {

import UIKit

#if canImport(WatchKit)
import WatchKit

public typealias ApplicationState = WKApplicationState
#else
public typealias ApplicationState = UIApplication.State
#endif

extension AppState {
public init(_ state: UIApplication.State) {
public init(_ state: ApplicationState) {
switch state {
case .active:
self = .active
Expand Down
49 changes: 49 additions & 0 deletions DatadogInternal/Sources/Context/ApplicationNotifications.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* 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 canImport(UIKit)
import UIKit
#if canImport(WatchKit)
import WatchKit
#endif

/// Convenient wrapper to get system notifications independent from platform
public enum ApplicationNotifications {
public static var didBecomeActive: Notification.Name {
#if canImport(WatchKit)
WKExtension.applicationDidBecomeActiveNotification
#else
UIApplication.didBecomeActiveNotification
#endif
}

public static var willResignActive: Notification.Name {
#if canImport(WatchKit)
WKExtension.applicationWillResignActiveNotification
#else
UIApplication.willResignActiveNotification
#endif
}

public static var didEnterBackground: Notification.Name {
#if canImport(WatchKit)
WKExtension.applicationDidEnterBackgroundNotification
#else
UIApplication.didEnterBackgroundNotification
#endif
}

public static var willEnterForeground: Notification.Name {
#if canImport(WatchKit)
WKExtension.applicationWillEnterForegroundNotification
#else
UIApplication.willEnterForegroundNotification
#endif
}
}
#endif
10 changes: 5 additions & 5 deletions DatadogInternal/Sources/Context/DeviceInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,14 @@ import MachO
import UIKit

extension DeviceInfo {
/// Creates device info based on UIKit description.
/// Creates device info based on device description.
///
/// - Parameters:
/// - processInfo: The current process information.
/// - device: The `UIDevice` description.
/// - device: The `DeviceProtocol` description.
public init(
processInfo: ProcessInfo = .processInfo,
device: UIDevice = .current,
device: DeviceProtocol = DeviceFactory.current,
sysctl: SysctlProviding = Sysctl()
) {
var architecture = "unknown"
Expand All @@ -96,7 +96,7 @@ extension DeviceInfo {

#if !targetEnvironment(simulator)
let model = try? sysctl.model()
// Real iOS device
// Real device
self.init(
name: device.model,
model: model ?? device.model,
Expand All @@ -111,7 +111,7 @@ extension DeviceInfo {
)
#else
let model = processInfo.environment["SIMULATOR_MODEL_IDENTIFIER"] ?? device.model
// iOS Simulator - battery monitoring doesn't work on Simulator, so return "always OK" value
// Simulator - battery monitoring doesn't work on Simulator, so return "always OK" value
self.init(
name: device.model,
model: "\(model) Simulator",
Expand Down
38 changes: 38 additions & 0 deletions DatadogInternal/Sources/Context/DeviceProtocol.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* 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

/// Abstraction protocol to get device information on the current platform
public protocol DeviceProtocol {
var model: String { get }
var systemName: String { get }
var systemVersion: String { get }
var identifierForVendor: UUID? { get }
}

#if canImport(UIKit)
import UIKit

#if canImport(WatchKit)
import WatchKit

extension WKInterfaceDevice: DeviceProtocol {}
#else
extension UIDevice: DeviceProtocol {}
#endif

public enum DeviceFactory {
/// Get the current device
public static var current: DeviceProtocol {
#if canImport(WatchKit)
WKInterfaceDevice.current()
#else
UIDevice.current
#endif
}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ extension DatadogExtension where ExtendedType: URLSessionTask {

/// Returns the delegate instance the task is reporting to.
var delegate: URLSessionDelegate? {
if #available(iOS 15.0, tvOS 15.0, *), let delegate = type.delegate {
if #available(iOS 15.0, tvOS 15.0, watchOS 8.0, *), let delegate = type.delegate {
return delegate
}

Expand Down
2 changes: 1 addition & 1 deletion DatadogInternal/Sources/Utils/UIKitExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import Foundation

#if canImport(UIKit)
#if canImport(UIKit) && !os(watchOS)
import UIKit

extension DatadogExtension where ExtendedType == UIApplication {
Expand Down
19 changes: 19 additions & 0 deletions DatadogInternal/Sources/Utils/WatchKitExtensions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* 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 canImport(WatchKit)
import WatchKit

extension DatadogExtension where ExtendedType == WKExtension {
public static var shared: WKExtension {
.shared()
}
}

extension WKExtension: DatadogExtended { }
#endif
1 change: 1 addition & 0 deletions DatadogLogs.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Pod::Spec.new do |s|
s.swift_version = '5.9'
s.ios.deployment_target = '12.0'
s.tvos.deployment_target = '12.0'
s.watchos.deployment_target = '7.0'

s.source = { :git => "https://github.com/DataDog/dd-sdk-ios.git", :tag => s.version.to_s }

Expand Down
3 changes: 2 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ let package = Package(
platforms: [
.iOS(.v12),
.tvOS(.v12),
.macOS(.v12)
.macOS(.v12),
.watchOS(.v7)
],
products: [
.library(
Expand Down
1 change: 1 addition & 0 deletions xcconfigs/Base.xcconfig
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ ARCHS[sdk=iphoneos*]=$(ARCHS_STANDARD) arm64e
IPHONEOS_DEPLOYMENT_TARGET=12.0
TVOS_DEPLOYMENT_TARGET=12.0
MACOSX_DEPLOYMENT_TARGET=12.6
WATCHOS_DEPLOYMENT_TARGET=7.0

// Minimum supported Swift version
SWIFT_VERSION=5.9
Expand Down