Skip to content

Commit 7e5a73b

Browse files
Merge pull request #381 from SourcePointUSA/v7
V7
2 parents 0caf10d + 4ac1a70 commit 7e5a73b

File tree

183 files changed

+94952
-10831
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

183 files changed

+94952
-10831
lines changed

CHANGELOG.md

+40-12
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,31 @@
1+
# 7.0.0 (Jan, 20, 2023)
2+
We have rewritten the network layer of the SDK almost in its entirety.
3+
Version 7 of the SDK uses new, "CDNed", heavily cached, endpoints and, as a result, it is now faster and less effected by service outages.
4+
On top of that, we have expanded our suit of tests as well as re-rewritten the majority of our UI specs to run faster and be less prone to "test flakiness".
5+
## Migrating from version 6.x.y
6+
We worked hard to keep the public API as close as possible to the previous version in order to keep your migration effort to a minimum.
7+
```diff
8+
// constructor
9+
SPConsentManager(
10+
accountId: 123,
11+
+ propertyId: 123
12+
propertyName: try! SPPropertyName("myPropertyName"),
13+
- campaignsEnv: .Public, // optional - Public by default
14+
campaigns: SPCampaigns(
15+
gdpr: SPCampaign(), // optional
16+
ccpa: SPCampaign(), // optional
17+
ios14: SPCampaign(), // optional
18+
+ environment: .Public // optional - .Public by default
19+
),
20+
delegate: self
21+
)
22+
```
23+
And that's it!
24+
25+
**Notice:** the internal data structure kept by the SDK in the `UserDefaults` has changed. If your app relied on data that was not publicly available through the `SPDelegate` protocol, you might face some issues. That does not impact the data described by the [TCF spec](https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework/blob/master/TCFv2/IAB%20Tech%20Lab%20-%20CMP%20API%20v2.md#in-app-details) (ie. data keyed and prefixed by `IABTCF_`).
26+
27+
⚠️ We are currently working on supporting TvOS in the next patch release. In other words, if you use our TvOS product, you should not upgrade to version 7.0.0 just yet.
28+
129
# 6.7.3 (Dec, 16, 2022)
230
* Fixed layout issues in the CCPA Native PM for TvOS when the message had less buttons than expected in the default UI. [#401](https://github.com/SourcePointUSA/ios-cmp-app/pull/401), [#397](https://github.com/SourcePointUSA/ios-cmp-app/pull/397)
331
* Fixed an issue preventing the "Do not sell information" button in the CCPA Native PM - from working as expected [#400](https://github.com/SourcePointUSA/ios-cmp-app/pull/400)
@@ -32,7 +60,7 @@ We have received a lot of valuable feedback from you and we listened. This relea
3260
* Fixed an issue (#359) preventing the SDK from being used with SPM. #360
3361

3462
# 6.4.0 (Jan, 31, 2022)
35-
* Added a brand new delegate method `onSPFinished`. As the name suggests, this method is invoked when the SDK is done displaying messages, sending/receiving consent to our APIs. At this point, the `UserDefaults` is garanteed to have all consent data up to date. #350
63+
* Added a brand new delegate method `onSPFinished`. As the name suggests, this method is invoked when the SDK is done displaying messages, sending/receiving consent to our APIs. At this point, the `UserDefaults` is guaranteed to have all consent data up to date. #350
3664
* Fixed an issue preventing the Native Message for AppleTV from showing the correct client logo. #358
3765
* Fixed an issue with the `SPPropertyName` not behaving correctly when the property name contained `[http|https]://`. #357
3866
* Fixed other issues regarding the Native AppleTV message. #352 #353
@@ -171,10 +199,10 @@ As always, don't hesitate to reach out to us either via GitHub issues, slack or
171199
* increase test and code coverage
172200

173201
## 5.2.3 (Jun, 09, 2020)
174-
* Fixed an issue that'd prevent the user from interacting with the app when the PMId passed to the SDK was wrong. We now encapuslate that in a `WebViewError` and call the `onError` callback on the `ConsentDelegate`.
202+
* Fixed an issue that'd prevent the user from interacting with the app when the PMId passed to the SDK was wrong. We now encapsulate that in a `WebViewError` and call the `onError` callback on the `ConsentDelegate`.
175203

176204
## 5.2.2 (Jun, 04, 2020)
177-
* Add `vendorGrants` attribute to `GDPRUserConsent` class. The `vendorGrants` attribute, simply put, is an dictionary reprensenting the consent state (on a legal basis) of all vendors and its purposes for the current user. For example:
205+
* Add `vendorGrants` attribute to `GDPRUserConsent` class. The `vendorGrants` attribute, simply put, is a dictionary representing the consent state (on a legal basis) of all vendors and its purposes for the current user. For example:
178206
```swift
179207
[
180208
"vendorId1": VendorGrant(
@@ -196,9 +224,9 @@ The `vendorGrant` attribute is derived from `purposeGrants` and will be `true` i
196224
* Fixed an issue that would in some cases show the consent message for logged in users. #144
197225

198226
## 5.2.0 (May, 15, 2020)
199-
* Added the method `customConsentTo` to `GDPRConsentViewController`. It's now possible to programatically consent the current user to a list of vendors, categories and legitimate interest caregories. The ids passed will be appended to the list of already accepted vendors, categories and leg. int. categories. The method is asynchronous so you must pass a completion handler that will receive back an instance of `GDPRUserConsent` in case of success or it'll call the delegate method `onError` in case of failure. It's important to notice, this method is intended to be used for **custom** vendors and purposes only. For IAB vendors and purposes it's still required to get consent via the consent message or privacy manager. #139
227+
* Added the method `customConsentTo` to `GDPRConsentViewController`. It's now possible to programmatically consent the current user to a list of vendors, categories and legitimate interest categories. The ids passed will be appended to the list of already accepted vendors, categories and leg. int. categories. The method is asynchronous so you must pass a completion handler that will receive back an instance of `GDPRUserConsent` in case of success or it'll call the delegate method `onError` in case of failure. It's important to notice, this method is intended to be used for **custom** vendors and purposes only. For IAB vendors and purposes it's still required to get consent via the consent message or privacy manager. #139
200228
* Fix an issue preventing consent data from being completely removed when calling `clearAllData` #141
201-
* Removed one (and hopfeully the last one) retaining cycle from our SDK #136
229+
* Removed one (and hopefully the last one) retaining cycle from our SDK #136
202230

203231

204232
## 5.1.0 (April, 16, 2020)
@@ -213,7 +241,7 @@ This is big one. We're moving more and more towards a stable API, so bare with u
213241
* `GDPRUserConsent.tcfData` has changed types from `[String: StringOrInt]` to `SPGDPRArbitraryJson`. It can be used as a dictionary by calling its `.dictionaryValue -> [String: Any]?` property.
214242

215243
## 5.0.3 (April, 03, 2020)
216-
* Storing IAB consent data ealier by persisting it at the very first http call #109
244+
* Storing IAB consent data earlier by persisting it at the very first http call #109
217245
* Added Swiftlint pod and to GitHub workflow #107
218246
* Fixed a ton of lint issues including one forced unwrap #107
219247
* Fixed an issue that was causing the Example app to crash on iPad 75e5472
@@ -257,15 +285,15 @@ As usual, if you see something wrong or have a question feel free to create an i
257285
## 3.1.0 (December, 4, 2019)
258286
* Added support to Carthage
259287
* In order to maintain compliance even in the event of an outage on our side, we’re now clearing all local consent information of a user on onErrorOccurred. This behaviour is opt-in be default but can be opted-out by setting flag .shouldCleanConsentOnError = false
260-
* changed initialisation params from siteId and siteName to propertyId and property (after all, it makes no sense to have “site” inside our apps…)
288+
* changed initialization params from siteId and siteName to propertyId and property (after all, it makes no sense to have “site” inside our apps…)
261289
* fix two memory leaks due to retaining cycle and WKWebView (thanks to [@victorbenning](https://github.com/victorbenning))
262290
* Improved test coverage
263291

264292
## 3.0.0 (October, 4, 2019)
265293
Oh wow, time flies when we're having fun huh? This is a major release and, with major releases comes major ~~responsibilities~~ changes.
266294

267295
### New Message script
268-
Our Web Team worked pretty hard to slim down our consent message platform and improve its perfomance. In this release we make use of the new message script.
296+
Our Web Team worked pretty hard to slim down our consent message platform and improve its performance. In this release we make use of the new message script.
269297

270298
**It's important to notice, SDK version 3 onwards will only be compatible with messages built using the new message builder.**
271299

@@ -309,16 +337,16 @@ In order to support the Plug & Play Privacy Manager and the `ConsentDelegate` pr
309337
## 2.3.0 (May, 20, 2019)
310338
* `ConsentViewController.getCustom*Consents` now always return an collection of Consents rather than an `Optional`
311339
* Pod is able to be built on Swift 5 projects (thanks to @pwallrich)
312-
* The example app is now simplied and the README has been updated
340+
* The example app is now simplified and the README has been updated
313341

314342
## 2.2.4 (April 20, 2019)
315-
* Moved the API calls on secondary thread to keep main thread independent and free for UI opertaion.
343+
* Moved the API calls on secondary thread to keep main thread independent and free for UI operation.
316344

317345
## 2.2.3 (April 09, 2019)
318346
* fix an issue that'd crash the client app if subclassing `ConsentViewController`
319347

320348
## 2.2.2 (April 08, 2019)
321-
* add the `ConsentViewController.messageTimeoutInSeconds` - used to controll the timeout between first load of the webview and `onMessageReady` callback
349+
* add the `ConsentViewController.messageTimeoutInSeconds` - used to control the timeout between first load of the webview and `onMessageReady` callback
322350

323351
## 2.1.2 (April 08, 2019)
324352
* fixed the interface for Objective-C, allowing the ConsentViewController to be used in Obj-c projects.
@@ -328,7 +356,7 @@ In order to support the Plug & Play Privacy Manager and the `ConsentDelegate` pr
328356

329357
## 2.1.0 (March 29, 2019)
330358
* load the webview in a separate function and call onMessageReady when the message is ready to be shown.
331-
* no longer add/remove the view from the superview. it's up to the parent to decide if/when the view should be added (we recommend using onMessageReady to add it and onInteractionComplete to remove it)
359+
* no longer add/remove the view from the super view. it's up to the parent to decide if/when the view should be added (we recommend using onMessageReady to add it and onInteractionComplete to remove it)
332360

333361
## 2.0.1 (March 21, 2019)
334362
* We now call `done()` always **after** `onErrorOccurred`

ConsentViewController.podspec

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = 'ConsentViewController'
3-
s.version = '6.7.3'
3+
s.version = '7.0.0'
44
s.summary = 'SourcePoint\'s ConsentViewController to handle privacy consents.'
55
s.homepage = 'https://www.sourcepoint.com'
66
s.license = { :type => 'MIT', :file => 'LICENSE' }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//
2+
// ConsentStatus.swift
3+
// Pods
4+
//
5+
// Created by Andre Herculano on 31.08.22.
6+
//
7+
8+
import Foundation
9+
10+
public struct ConsentStatus: Codable, Equatable {
11+
struct GranularStatus: Codable, Equatable {
12+
var vendorConsent, vendorLegInt, purposeConsent, purposeLegInt: String?
13+
var previousOptInAll, defaultConsent: Bool?
14+
}
15+
16+
var granularStatus: GranularStatus? = GranularStatus()
17+
var rejectedAny, rejectedLI, consentedAll, consentedToAny, rejectedAll, vendorListAdditions, legalBasisChanges: Bool?
18+
var hasConsentData: Bool? = false
19+
var rejectedVendors: [String?]? = []
20+
var rejectedCategories: [String?]? = []
21+
}

ConsentViewController/Classes/Consents/SPCCPAConsent.swift

+31-8
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,18 @@ import Foundation
5757

5858
public typealias SPUsPrivacyString = String
5959

60+
protocol CampaignConsent {
61+
var uuid: String? { get set }
62+
var applies: Bool { get set }
63+
var dateCreated: SPDateCreated { get set }
64+
}
65+
6066
/**
6167
The UserConsent class encapsulates the consent status, rejected vendor ids and rejected categories (purposes) ids.
6268
- Important: The `rejectedVendors` and `rejectedCategories` arrays will only be populated if the `status` is `.Some`.
6369
That is, if the user has rejected `.All` or `.None` vendors/categories, those arrays will be empty.
6470
*/
65-
@objcMembers public class SPCCPAConsent: NSObject, Codable {
71+
@objcMembers public class SPCCPAConsent: NSObject, Codable, CampaignConsent {
6672
/// represents the default state of the consumer prior to seeing the consent message
6773
/// - seealso: https://github.com/InteractiveAdvertisingBureau/USPrivacy/blob/master/CCPA/US%20Privacy%20String.md#us-privacy-string-format
6874
public static let defaultUsPrivacyString = "1---"
@@ -75,15 +81,29 @@ public typealias SPUsPrivacyString = String
7581
)}
7682

7783
/// Indicates if the user has rejected `.All`, `.Some` or `.None` of the vendors **and** categories.
78-
public let status: CCPAConsentStatus
84+
public var status: CCPAConsentStatus
85+
7986
/// The ids of the rejected vendors and categories. These can be found in SourcePoint's dashboard
80-
public let rejectedVendors, rejectedCategories: [String]
87+
public var rejectedVendors, rejectedCategories: [String]
88+
8189
/// the US Privacy String as described by the IAB
82-
public let uspstring: SPUsPrivacyString
90+
public var uspstring: SPUsPrivacyString
91+
8392
/// that's the internal Sourcepoint id we give to this consent profile
8493
public var uuid: String?
94+
95+
/// Determines if the GDPR legislation applies for this user
96+
public var applies = false
97+
98+
/// The date in which the consent profile was created or updated
99+
public var dateCreated = SPDateCreated.now()
100+
85101
/// In case `/getMessages` request was done with `groupPmId`, `childPmId` will be returned
86-
let childPmId: String?
102+
var childPmId: String?
103+
104+
var lastMessage: LastMessageData?
105+
106+
var consentStatus: ConsentStatus
87107

88108
public static func rejectedNone () -> SPCCPAConsent { SPCCPAConsent(
89109
status: CCPAConsentStatus.RejectedNone,
@@ -92,28 +112,30 @@ public typealias SPUsPrivacyString = String
92112
uspstring: ""
93113
)}
94114

95-
public init(
115+
init(
96116
uuid: String? = nil,
97117
status: CCPAConsentStatus,
98118
rejectedVendors: [String],
99119
rejectedCategories: [String],
100120
uspstring: SPUsPrivacyString,
101-
childPmId: String? = nil
121+
childPmId: String? = nil,
122+
consentStatus: ConsentStatus = ConsentStatus()
102123
) {
103124
self.uuid = uuid
104125
self.status = status
105126
self.rejectedVendors = rejectedVendors
106127
self.rejectedCategories = rejectedCategories
107128
self.uspstring = uspstring
108129
self.childPmId = childPmId
130+
self.consentStatus = consentStatus
109131
}
110132

111133
open override var description: String {
112134
"UserConsent(uuid: \(uuid ?? ""), status: \(status.rawValue), rejectedVendors: \(rejectedVendors), rejectedCategories: \(rejectedCategories), uspstring: \(uspstring))"
113135
}
114136

115137
enum CodingKeys: CodingKey {
116-
case status, rejectedVendors, rejectedCategories, uspstring, uuid, childPmId
138+
case status, rejectedVendors, rejectedCategories, uspstring, uuid, childPmId, consentStatus
117139
}
118140

119141
required public init(from decoder: Decoder) throws {
@@ -124,6 +146,7 @@ public typealias SPUsPrivacyString = String
124146
uspstring = try values.decode(SPUsPrivacyString.self, forKey: .uspstring)
125147
let statusString = try values.decode(String.self, forKey: .status)
126148
childPmId = try values.decodeIfPresent(String.self, forKey: .childPmId)
149+
consentStatus = (try? values.decodeIfPresent(ConsentStatus.self, forKey: .consentStatus)) ?? ConsentStatus()
127150
switch statusString {
128151
case "rejectedNone": status = .RejectedNone
129152
case "rejectedSome": status = .RejectedSome

ConsentViewController/Classes/Consents/SPGDPRConsent.swift

+34-7
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,20 @@
77

88
import Foundation
99

10+
struct LastMessageData: Codable {
11+
var id, categoryId, subCategoryId: Int
12+
var partitionUUID: String
13+
}
14+
15+
extension LastMessageData {
16+
init(from metadata: MessageMetaData) {
17+
id = Int(metadata.messageId) ?? 0
18+
categoryId = metadata.categoryId.rawValue
19+
subCategoryId = metadata.subCategoryId.rawValue
20+
partitionUUID = metadata.messagePartitionUUID ?? ""
21+
}
22+
}
23+
1024
/// A dictionary in which the keys represent the Vendor Id
1125
public typealias SPGDPRVendorGrants = [GDPRVendorId: SPGDPRVendorGrant]
1226
public typealias GDPRVendorId = String
@@ -49,7 +63,7 @@ public typealias SPGDPRPurposeId = String
4963
/**
5064
SPGDPRConsent encapsulates all consent data from a user.
5165
*/
52-
@objcMembers public class SPGDPRConsent: NSObject, Codable {
66+
@objcMembers public class SPGDPRConsent: NSObject, Codable, CampaignConsent {
5367
/// Convenience initialiser to return an empty consent object.
5468
public static func empty() -> SPGDPRConsent { SPGDPRConsent(
5569
vendorGrants: SPGDPRVendorGrants(),
@@ -75,19 +89,19 @@ public typealias SPGDPRPurposeId = String
7589
/// considered fully consented. Either via legitimate interest or explicit user consent.
7690
/// Each key/value pair of `"purposeId: Bool`, indicates if that purpose has been consented
7791
/// either via leg. interest or explicit user consent.
78-
public let vendorGrants: SPGDPRVendorGrants
92+
public var vendorGrants: SPGDPRVendorGrants
7993

8094
/// The iAB consent string.
81-
public let euconsent: String
95+
public var euconsent: String
8296

8397
/// A dictionary with all TCFv2 related data
84-
public let tcfData: SPJson
98+
public var tcfData: SPJson?
8599

86100
/// That's the internal Sourcepoint id we give to this consent profile
87101
public var uuid: String?
88102

89103
/// In case `/getMessages` request was done with `groupPmId`, `childPmId` will be returned
90-
let childPmId: String?
104+
var childPmId: String?
91105

92106
/// A list of ids of the categories accepted by the user in all its vendors.
93107
/// If a category has been rejected in a single vendor, its id won't part of the `acceptedCategories` list.
@@ -102,18 +116,30 @@ public typealias SPGDPRPurposeId = String
102116
}
103117
}
104118

105-
public init(
119+
/// The date in which the consent profile was created or updated
120+
public var dateCreated = SPDateCreated.now()
121+
122+
/// Determines if the GDPR legislation applies for this user
123+
public var applies = false
124+
125+
var consentStatus: ConsentStatus
126+
127+
var lastMessage: LastMessageData?
128+
129+
init(
106130
uuid: String? = nil,
107131
vendorGrants: SPGDPRVendorGrants,
108132
euconsent: String,
109133
tcfData: SPJson,
110-
childPmId: String? = nil
134+
childPmId: String? = nil,
135+
consentStatus: ConsentStatus = ConsentStatus()
111136
) {
112137
self.uuid = uuid
113138
self.vendorGrants = vendorGrants
114139
self.euconsent = euconsent
115140
self.tcfData = tcfData
116141
self.childPmId = childPmId
142+
self.consentStatus = consentStatus
117143
}
118144

119145
public override func isEqual(_ object: Any?) -> Bool {
@@ -141,5 +167,6 @@ public typealias SPGDPRPurposeId = String
141167
case tcfData = "TCData"
142168
case vendorGrants = "grants"
143169
case childPmId
170+
case consentStatus
144171
}
145172
}

0 commit comments

Comments
 (0)