Skip to content

Commit

Permalink
Releasing 4.4.0
Browse files Browse the repository at this point in the history
  • Loading branch information
Rover Release Bot 🤖 committed Nov 17, 2023
1 parent 5e3eaa3 commit d218807
Show file tree
Hide file tree
Showing 33 changed files with 645 additions and 465 deletions.
6 changes: 4 additions & 2 deletions Sources/AdSupport/AdSupportAssembler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ public class AdSupportAssembler: Assembler {
public init() { }

public func assemble(container: Container) {
container.register(AdSupportContextProvider.self) { _ in
AdSupportManager()
container.register(AdSupportContextProvider.self) { resolver in
AdSupportManager(
privacyService: resolver.resolve(PrivacyService.self)!
)
}
}
}
7 changes: 5 additions & 2 deletions Sources/AdSupport/AdSupportManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@ import RoverData

class AdSupportManager {
let identifierManager = ASIdentifierManager.shared()
let privacyService: PrivacyService

init() { }
init(privacyService: PrivacyService) {
self.privacyService = privacyService
}
}

extension AdSupportManager: AdSupportContextProvider {
var advertisingIdentifier: String? {
guard self.identifierManager.isAdvertisingTrackingEnabled else {
guard self.identifierManager.isAdvertisingTrackingEnabled, self.privacyService.trackingMode == .default else {
return nil
}

Expand Down
5 changes: 5 additions & 0 deletions Sources/Data/Context/Context.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ import Foundation
import RoverFoundation

public struct Context: Codable, Equatable {
// MARK: Privacy
public var trackingMode: String?

// MARK: AdSupport

public var advertisingIdentifier: String?
Expand Down Expand Up @@ -185,6 +188,7 @@ public struct Context: Codable, Equatable {
public var lastSeen: Date?

public init(
trackingMode: String?,
advertisingIdentifier: String?,
isDarkModeEnabled: Bool?,
isBluetoothEnabled: Bool?,
Expand Down Expand Up @@ -220,6 +224,7 @@ public struct Context: Codable, Equatable {
conversions: [String]?,
lastSeen: Date?
) {
self.trackingMode = trackingMode
self.advertisingIdentifier = advertisingIdentifier
self.isDarkModeEnabled = isDarkModeEnabled
self.isBluetoothEnabled = isBluetoothEnabled
Expand Down
17 changes: 10 additions & 7 deletions Sources/Data/Context/ContextManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ class ContextManager {
let persistedDeviceName = PersistedValue<String>(storageKey: "io.rover.RoverData.deviceName")
let persistedAppLastSeenTimestamp = PersistedValue<Date>(storageKey: "io.rover.RoverData.appLastSeenTimestamp")
let reachability = Reachability(hostname: "google.com")!
let privacyService: PrivacyService

init() { }
init(privacyService: PrivacyService) {
self.privacyService = privacyService
}
}

// MARK: DarkModeContextProvider
Expand Down Expand Up @@ -121,14 +124,16 @@ extension ContextManager: StaticContextProvider {
}

let scanner = Scanner(string: embeddedProfile)
var string: NSString?


guard scanner.scanUpTo("<?xml version=\"1.0\" encoding=\"UTF-8\"?>", into: nil), scanner.scanUpTo("</plist>", into: &string) else {

guard scanner.scanUpToString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>") != nil,
let string = scanner.scanUpToString("</plist>") else {
os_log("Unrecognized provisioning profile structure", log: .context, type: .error)
return .production
}

guard let data = string?.appending("</plist>").data(using: String.Encoding.utf8) else {
guard let data = string.appending("</plist>").data(using: String.Encoding.utf8) else {
os_log("Failed to decode provisioning profile", log: .context, type: .error)
return .production
}
Expand Down Expand Up @@ -173,9 +178,7 @@ extension ContextManager: StaticContextProvider {
}
}

guard let modelName = String(validatingUTF8: modelCode) else {
fatalError("Invalid data")
}
let modelName = String(modelCode)

guard let deviceModel = DeviceModel(modelName: modelName) else {
os_log("Unknown model name: %@", log: .context, type: .error, modelName)
Expand Down
4 changes: 4 additions & 0 deletions Sources/Data/Context/ModularContextProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

class ModularContextProvider {
weak var privacyContextProvider: PrivacyContextProvider?
weak var adSupportContextProvider: AdSupportContextProvider?
weak var bluetoothContextProvider: BluetoothContextProvider?
weak var darkModeContextProvider: DarkModeContextProvider?
Expand All @@ -31,6 +32,7 @@ class ModularContextProvider {
weak var appLastSeenContextProvider: AppLastSeenContextProvider?

init(
privacyContextProvider: PrivacyContextProvider?,
adSupportContextProvider: AdSupportContextProvider?,
bluetoothContextProvider: BluetoothContextProvider?,
darkModeContextProvider: DarkModeContextProvider?,
Expand All @@ -47,6 +49,7 @@ class ModularContextProvider {
conversionsContextProvider: ConversionsContextProvider?,
appLastSeenContextProvider: AppLastSeenContextProvider?
) {
self.privacyContextProvider = privacyContextProvider
self.adSupportContextProvider = adSupportContextProvider
self.bluetoothContextProvider = bluetoothContextProvider
self.darkModeContextProvider = darkModeContextProvider
Expand All @@ -68,6 +71,7 @@ class ModularContextProvider {
extension ModularContextProvider: ContextProvider {
var context: Context {
return Context(
trackingMode: self.privacyContextProvider?.trackingModeString,
advertisingIdentifier: self.adSupportContextProvider?.advertisingIdentifier,
isDarkModeEnabled: self.darkModeContextProvider?.isDarkModeEnabled,
isBluetoothEnabled: self.bluetoothContextProvider?.isBluetoothEnabled,
Expand Down
20 changes: 20 additions & 0 deletions Sources/Data/Context/Providers/PrivacyContextProvider.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
// copy, modify, and distribute this software in source code or binary form for use
// in connection with the web services and APIs provided by Rover.
//
// This copyright notice shall be included in all copies or substantial portions of
// the software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

import Foundation

public protocol PrivacyContextProvider: AnyObject {
var trackingModeString: String? { get }
}
14 changes: 12 additions & 2 deletions Sources/Data/DataAssembler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,24 @@ public struct DataAssembler: Assembler {

// swiftlint:disable:next function_body_length // Assemblers are fairly declarative.
public func assemble(container: Container) {
// MARK: Privacy

container.register(PrivacyService.self) { _ in
PrivacyService()
}

// MARK: ContextManager

container.register(ContextManager.self) { _ in
ContextManager()
container.register(ContextManager.self) { resolver in
let privacyService = resolver.resolve(PrivacyService.self)!
return ContextManager(privacyService: privacyService)
}

// MARK: ContextProvider

container.register(ContextProvider.self) { resolver in
ModularContextProvider(
privacyContextProvider: resolver.resolve(PrivacyService.self),
adSupportContextProvider: resolver.resolve(AdSupportContextProvider.self),
bluetoothContextProvider: resolver.resolve(BluetoothContextProvider.self),
darkModeContextProvider: resolver.resolve(DarkModeContextProvider.self),
Expand Down Expand Up @@ -213,5 +221,7 @@ public struct DataAssembler: Assembler {
let conversionsManager = resolver.resolve(ConversionsManager.self)!
// Migrate any conversion tags from previous versions of Rover
conversionsManager.migrateTags()

resolver.resolve(PrivacyService.self)?.refreshAllListeners()
}
}
80 changes: 80 additions & 0 deletions Sources/Data/Privacy/PrivacyService.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
// copy, modify, and distribute this software in source code or binary form for use
// in connection with the web services and APIs provided by Rover.
//
// This copyright notice shall be included in all copies or substantial portions of
// the software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

import Foundation

/// This object is responsible for the global privacy settings of the Rover SDK.
public class PrivacyService: PrivacyContextProvider {
public enum TrackingMode: String, Identifiable, CaseIterable {
case `default`
case anonymous

public var id: Self { self }
}

public var trackingMode: TrackingMode {
get {
let value = UserDefaults.standard.string(forKey: "io.rover.TrackingMode") ?? "default"
return TrackingMode(rawValue: value) ?? .default
}
set {
UserDefaults.standard.set(newValue.rawValue, forKey: "io.rover.TrackingMode")

// re-emit to listeners
refreshAllListeners()
}
}

var trackingModeListeners: [PrivacyListener] = []

public func registerTrackingEnabledListener(_ listener: PrivacyListener) {
trackingModeListeners.append(listener)
listener.trackingModeDidChange(trackingMode)
}

public func registerTrackingEnabledChangedCallback(_ callback: @escaping (TrackingMode) -> Void) {
registerTrackingEnabledListener(
PrivacyCallbackListener(callback: callback)
)
}

/// Meant to be called after didAssemble.
func refreshAllListeners() {
trackingModeListeners.forEach { $0.trackingModeDidChange(trackingMode) }
}

// MARK: Context Provider

public var trackingModeString: String? {
trackingMode.rawValue
}
}

public protocol PrivacyListener {
/// Notify this listener that tracking mode has changed.
func trackingModeDidChange(_ trackingMode: PrivacyService.TrackingMode)
}

private class PrivacyCallbackListener: PrivacyListener {
let callback: (PrivacyService.TrackingMode) -> Void

internal init(callback: @escaping (PrivacyService.TrackingMode) -> Void) {
self.callback = callback
}

func trackingModeDidChange(_ trackingMode: PrivacyService.TrackingMode) {
callback(trackingMode)
}
}
15 changes: 15 additions & 0 deletions Sources/Data/RoverDataAccessors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,19 @@ public extension Rover {
resolve(TokenManager.self)!
}
}

var privacyService: PrivacyService {
get {
resolve(PrivacyService.self)!
}
}

var trackingMode: PrivacyService.TrackingMode {
get {
privacyService.trackingMode
}
set {
privacyService.trackingMode = newValue
}
}
}
Loading

0 comments on commit d218807

Please sign in to comment.