├── demo-ios
├── Gdpr
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── ViewController.swift
│ ├── InMemoryDataSource.swift
│ ├── SimpleViewController.swift
│ ├── NavigationViewController.swift
│ ├── Info.plist
│ ├── TableViewController.swift
│ ├── AppDelegate.swift
│ └── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
└── Gdpr.xcodeproj
│ ├── xcuserdata
│ ├── cristi.xcuserdatad
│ │ ├── xcdebugger
│ │ │ └── Breakpoints_v2.xcbkptlist
│ │ └── xcschemes
│ │ │ └── xcschememanagement.plist
│ └── cristianbaluta.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
│ ├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcuserdata
│ │ ├── cristi.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ │ └── cristianbaluta.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
│ └── project.pbxproj
├── src
├── ConsentKitCellProtocol.swift
├── ConsentKitCell.swift
├── ConsentKitUserDefaultsDataSource.swift
├── CloudKitViewControllerHeader.swift
├── ConsentKitServices.swift
├── ConsentKitTableViewDataSource.swift
├── ConsentKit.swift
├── ConsentKitViewController.swift
└── ConsentKitCell.xib
├── Consent.podspec
├── LICENSE
└── README.md
/demo-ios/Gdpr/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/demo-ios/Gdpr.xcodeproj/xcuserdata/cristi.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/demo-ios/Gdpr.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/demo-ios/Gdpr.xcodeproj/project.xcworkspace/xcuserdata/cristi.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cristibaluta/ConsentKit/HEAD/demo-ios/Gdpr.xcodeproj/project.xcworkspace/xcuserdata/cristi.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/demo-ios/Gdpr.xcodeproj/project.xcworkspace/xcuserdata/cristianbaluta.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cristibaluta/ConsentKit/HEAD/demo-ios/Gdpr.xcodeproj/project.xcworkspace/xcuserdata/cristianbaluta.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/demo-ios/Gdpr.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/demo-ios/Gdpr/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // Gdpr
4 | //
5 | // Created by Cristian Baluta on 21/05/2018.
6 | // Copyright © 2018 Cristian Baluta. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ViewController: UITabBarController {
12 |
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/ConsentKitCellProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ConsentKitCellProtocol.swift
3 | //
4 | // Created by Cristian Baluta on 28/05/2018.
5 | // Copyright © 2018 Imagin soft. All rights reserved.
6 | //
7 |
8 | import Foundation
9 |
10 | protocol ConsentKitCellProtocol {
11 | var title: String {get set}
12 | var subtitle: String {get set}
13 | var value: Bool {get set}
14 | var valueDidChange: ((Bool) -> Void)? {get set}
15 | }
16 |
--------------------------------------------------------------------------------
/demo-ios/Gdpr.xcodeproj/xcuserdata/cristi.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | Gdpr.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/demo-ios/Gdpr.xcodeproj/xcuserdata/cristianbaluta.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | Gdpr.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Consent.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = 'ConsentKit'
3 | s.version = '0.9'
4 | s.summary = 'Keep track of GDPR consents in your app.'
5 | s.description = <<-DESC
6 | Keep track of GDPR consents in your app.
7 | DESC
8 | s.module_name = "ConsentKit"
9 | s.homepage = 'https://github.com/ralcr/Consent'
10 | s.license = 'MIT'
11 | s.authors = { 'Cristian Baluta' => 'cristi.baluta@gmail.com' }
12 | s.ios.deployment_target = '10.0'
13 | s.source = { :git => 'https://github.com/ralcr/Consent', :tag => s.version }
14 | s.source_files = 'src/*.{h,swift}'
15 | end
16 |
--------------------------------------------------------------------------------
/demo-ios/Gdpr/InMemoryDataSource.swift:
--------------------------------------------------------------------------------
1 | //
2 | // InMemorydataSource.swift
3 | // Gdpr
4 | //
5 | // Created by Cristian Baluta on 23/05/2018.
6 | // Copyright © 2018 Imagin soft. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class InMemoryDataSource: ConsentKitDataSource {
12 |
13 | private var dict = [String: Bool?]()
14 |
15 | func isAccepted (_ item: ConsentKitItem) -> Bool {
16 | return dict[item.rawValue] == true
17 | }
18 |
19 | func isReviewed (_ item: ConsentKitItem) -> Bool {
20 | return dict[item.rawValue] != nil
21 | }
22 |
23 | func setAccepted (_ value: Bool, for item: ConsentKitItem) {
24 | dict[item.rawValue] = value
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/demo-ios/Gdpr/SimpleViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SimpleViewController.swift
3 | // Gdpr
4 | //
5 | // Created by Cristian Baluta on 22/05/2018.
6 | // Copyright © 2018 Imagin soft. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SimpleViewController: UIViewController {
12 |
13 | @IBOutlet var label: UILabel!
14 |
15 | override func viewDidAppear(_ animated: Bool) {
16 | super.viewDidAppear(animated)
17 |
18 | if gdpr.needsReviewing([Services.icloud, Services.analytics, ConsentKitServices.location]) {
19 | label.text = "Gdpr needs reviewing!"
20 | } else {
21 | label.text = "All gdpr items already reviewed"
22 | }
23 | }
24 |
25 | @IBAction func handleGdpr() {
26 |
27 | let vc = ConsentKitViewController()
28 | vc.items = [Services.icloud, Services.analytics, ConsentKitServices.location]
29 | self.present(vc, animated: true)
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Cristian Baluta
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/demo-ios/Gdpr/NavigationViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NavigationViewController.swift
3 | // Gdpr
4 | //
5 | // Created by Cristian Baluta on 23/05/2018.
6 | // Copyright © 2018 Imagin soft. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class NavigationViewController: UIViewController {
12 |
13 | @IBOutlet var label: UILabel!
14 |
15 | override func viewDidAppear(_ animated: Bool) {
16 | super.viewDidAppear(animated)
17 |
18 | if gdpr.needsReviewing([Services.icloud, Services.analytics, ConsentKitServices.location]) {
19 | label.text = "Gdpr needs reviewing!"
20 | } else {
21 | label.text = "All gdpr items already reviewed"
22 | }
23 | }
24 |
25 | @IBAction func handleGdpr() {
26 |
27 | let vc = ConsentKitViewController()
28 | vc.items = [Services.icloud, Services.analytics, ConsentKitServices.location]
29 | vc.didFinishReview = {
30 | self.navigationController?.popViewController(animated: true)
31 | }
32 | self.navigationController?.pushViewController(vc, animated: true)
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/ConsentKitCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ConsentKitCell.swift
3 | //
4 | // Created by Cristian Baluta on 21/05/2018.
5 | // Copyright © 2018 Cristian Baluta. All rights reserved.
6 | //
7 |
8 | import UIKit
9 |
10 | class ConsentKitCell: UITableViewCell, ConsentKitCellProtocol {
11 |
12 | @IBOutlet private var titleLabel: UILabel!
13 | @IBOutlet private var subtitleLabel: UILabel!
14 | @IBOutlet private var switchButton: UISwitch!
15 |
16 | var title: String = "" {
17 | didSet {
18 | titleLabel.text = title
19 | }
20 | }
21 | var subtitle: String = "" {
22 | didSet {
23 | subtitleLabel.text = subtitle
24 | }
25 | }
26 | var value: Bool = false {
27 | didSet {
28 | switchButton.isOn = value
29 | }
30 | }
31 | var valueDidChange: ((Bool) -> Void)?
32 |
33 | override func awakeFromNib() {
34 | super.awakeFromNib()
35 | switchButton.onTintColor = UIColor.orange
36 | }
37 |
38 | static func instantiateFromXib() -> ConsentKitCell {
39 | let arrNib: Array = Bundle.main.loadNibNamed("ConsentKitCell", owner: self, options: nil)!
40 | return arrNib.first as! ConsentKitCell
41 | }
42 |
43 | @IBAction func switchChanged(_ sender: UISwitch) {
44 | valueDidChange?(sender.isOn)
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/ConsentKitUserDefaultsDataSource.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ConsentKitUserDefaultsDataSource.swift
3 | //
4 | // Created by Cristian Baluta on 23/05/2018.
5 | // Copyright © 2018 Imagin soft. All rights reserved.
6 | //
7 |
8 | import Foundation
9 |
10 | class ConsentKitUserDefaultsDataSource {
11 |
12 | fileprivate let prefix = "ConsentKit-"
13 | fileprivate let userDefaults = UserDefaults.standard
14 |
15 |
16 | fileprivate func get (_ key: String) -> Any? {
17 | return userDefaults.object(forKey: prefix + key)
18 | }
19 |
20 | fileprivate func set (_ value: Bool?, forKey key: String) {
21 | if let v = value {
22 | userDefaults.set(v, forKey: prefix + key)
23 | } else {
24 | userDefaults.removeObject(forKey: prefix + key)
25 | }
26 | userDefaults.synchronize()
27 | }
28 | }
29 |
30 | extension ConsentKitUserDefaultsDataSource: ConsentKitDataSource {
31 |
32 | func isAccepted (_ item: ConsentKitItem) -> Bool {
33 | return (get(item.rawValue) as? Bool) == true
34 | }
35 |
36 | func isReviewed (_ item: ConsentKitItem) -> Bool {
37 | return get(item.rawValue) != nil
38 | }
39 |
40 | func setAccepted (_ value: Bool, for item: ConsentKitItem) {
41 | set(value, forKey: item.rawValue)
42 | }
43 |
44 | func reset (_ item: ConsentKitItem) {
45 | set(nil, forKey: item.rawValue)
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/CloudKitViewControllerHeader.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CloudKitViewControllerHeader.swift
3 | //
4 | // Created by Cristian Baluta on 21/05/2018.
5 | // Copyright © 2018 Cristian Baluta. All rights reserved.
6 | //
7 |
8 | import UIKit
9 |
10 | class CloudKitViewControllerHeader: UIView {
11 |
12 | var didDone: (() -> Void)?
13 | private let padding = CGFloat(16)
14 |
15 | override init(frame: CGRect) {
16 | super.init(frame: frame)
17 |
18 | self.backgroundColor = UIColor(white: 0.9, alpha: 1.0)
19 |
20 | let label = UILabel()
21 | label.text = "Review services!"
22 | label.font = UIFont.boldSystemFont(ofSize: 16)
23 | label.sizeToFit()
24 | label.center = CGPoint(x: label.frame.size.width/2 + padding, y: 30)
25 | self.addSubview(label)
26 |
27 | let button = UIButton()
28 | button.setTitle("Done", for: .normal)
29 | button.setTitleColor(UIColor.orange, for: .normal)
30 | button.addTarget(self, action: #selector(handleButton), for: .touchUpInside)
31 | button.sizeToFit()
32 | button.center = CGPoint(x: frame.size.width - button.frame.size.width/2 - padding, y: 30)
33 | self.addSubview(button)
34 | }
35 |
36 | required init?(coder aDecoder: NSCoder) {
37 | fatalError("init(coder:) has not been implemented")
38 | }
39 |
40 | @objc func handleButton() {
41 | didDone?()
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/ConsentKitServices.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ConsentKitServices.swift
3 | //
4 | // Created by Cristian Baluta on 23/05/2018.
5 | // Copyright © 2018 Imagin soft. All rights reserved.
6 | //
7 |
8 | import Foundation
9 |
10 | enum ConsentKitServices: String, ConsentKitItem {
11 |
12 | case icloud = "ck-icloud"
13 | case analytics = "ck-analytics"
14 | case location = "ck-location"
15 |
16 | func title() -> String {
17 | switch self {
18 | case .icloud: return "iCloud"
19 | case .analytics: return "Google analytics"
20 | case .location: return "Location"
21 | }
22 | }
23 |
24 | func description() -> String {
25 | switch self {
26 | case .icloud: return "Store data to the Apple's iCloud. This will allow the data to by synced across all your devices."
27 | case .analytics: return "Help developer understand how the app is used by sharing usage with Google analytics."
28 | case .location: return "Store location on server"
29 | }
30 | }
31 |
32 | func alertMessage() -> String? {
33 | switch self {
34 | case .icloud: return "I accept that this app will store my data in the Apple's iCloud for the purpose of syncing it across multiple devices and backup"
35 | case .analytics: return "I accept that this app will store anonymous usage data in Google analytics for the purpose of improving the app"
36 | case .location: return "I accept to store my location on the server"
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/demo-ios/Gdpr/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/demo-ios/Gdpr/TableViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TableViewController.swift
3 | // Gdpr
4 | //
5 | // Created by Cristian Baluta on 04/06/2018.
6 | // Copyright © 2018 Imagin soft. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class TableViewController: UITableViewController {
12 |
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 |
16 | // Uncomment the following line to preserve selection between presentations
17 | // self.clearsSelectionOnViewWillAppear = false
18 | }
19 |
20 | // MARK: - Table view data source
21 |
22 | override func numberOfSections(in tableView: UITableView) -> Int {
23 | return 3
24 | }
25 |
26 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
27 | // #warning Incomplete implementation, return the number of rows
28 | return section == 1 ? 1 : 2
29 | }
30 |
31 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
32 |
33 | if indexPath.section == 1 {
34 | let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
35 | return cell
36 | } else {
37 | let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
38 | cell.textLabel?.text = "IndePath \(indexPath)"
39 | return cell
40 | }
41 | }
42 |
43 | override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
44 | switch section {
45 | case 0:
46 | return "Section 1"
47 | case 1:
48 | return "GDPR section"
49 | default:
50 | return "Section 3"
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/demo-ios/Gdpr/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Gdpr
4 | //
5 | // Created by Cristian Baluta on 21/05/2018.
6 | // Copyright © 2018 Cristian Baluta. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | enum Services: String, ConsentKitItem {
12 |
13 | case icloud = "iCloud"
14 | case analytics = "analytics"
15 |
16 | func title() -> String {
17 | switch self {
18 | case .icloud: return "iCloud"
19 | case .analytics: return "Google analytics"
20 | }
21 | }
22 |
23 | func description() -> String {
24 | switch self {
25 | case .icloud: return "Store data to the Apple's iCloud. This will allow the data to by synced across all your devices."
26 | case .analytics: return "Help developer understand how the app is used by sharing usage with Google analytics."
27 | }
28 | }
29 |
30 | func alertMessage() -> String? {
31 | switch self {
32 | case .icloud: return nil
33 | case .analytics: return nil
34 | }
35 | }
36 | }
37 |
38 | let gdpr = ConsentKit()
39 | //let gdpr = ConsentKit(dataSource: InMemoryDataSource())
40 |
41 | @UIApplicationMain
42 | class AppDelegate: UIResponder, UIApplicationDelegate {
43 |
44 | var window: UIWindow?
45 |
46 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
47 | // Override point for customization after application launch.
48 | // For testing purposes we reset all values from previous run
49 | gdpr.reset(Services.icloud)
50 | gdpr.reset(Services.analytics)
51 | gdpr.reset(ConsentKitServices.location)
52 |
53 | return true
54 | }
55 | }
56 |
57 |
--------------------------------------------------------------------------------
/demo-ios/Gdpr/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/demo-ios/Gdpr/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ConsentKit
2 | Note: This library only helps you collect consents for the services in your app, actually disabling those services is developer's job.
3 |
4 | 
5 |
6 | ## Usage
7 | ### Define the services in your app
8 | Note: Some generic services can be found in ConsentKitServices
9 |
10 | ```swift
11 | enum Services: String, ConsentKitItem {
12 |
13 | case icloud = "iCloud"
14 | case analytics = "analytics"
15 |
16 | func title() -> String {
17 | switch self {
18 | case .icloud: return "iCloud"
19 | case .analytics: return "Google analytics"
20 | }
21 | }
22 | func description() -> String {
23 | switch self {
24 | case .icloud: return "Wether to accept iCloud or not"
25 | case .analytics: return "Google analytics"
26 | }
27 | }
28 | func alertMessage() -> String? {
29 | switch self {
30 | case .icloud: return nil
31 | case .analytics: return "I accept this app to store anonymous analytics in Google Analytics!"
32 | }
33 | }
34 | }
35 | ```
36 |
37 | ### Instantiate the lib, preferably once in the AppDelegate, but can be anywhere and as many times as you like.
38 |
39 | ```swift
40 | let gdpr = ConsentKit()
41 | ```
42 |
43 | ### Check if you have missing consents
44 | If yes, add the default ConsentKitViewController to handle all the switches for you.
45 |
46 | ```swift
47 | if gdpr.needsReviewing([Services.icloud, Services.analytics]) {
48 |
49 | let vc = ConsentKitViewController()
50 | vc.items = [Services.icloud, Services.analytics, ConsentKitServices.location]
51 | self.present(vc, animated: true)
52 | }
53 | ```
54 |
55 | ### Custom storage
56 | By default ConsentKit keeps values in UserDefaults, but you can change that with the gdpr.dataSource property. Just assign or pass through constructor a class implementing the ConsentKitDataSource
57 |
58 | ```swift
59 | let gdpr = ConsentKit(dataSource: InMemoryDataSource())// InMemoryDataSource implements ConsentKitDataSource
60 |
61 | protocol ConsentKitDataSource {
62 | func isAccepted (_ item: ConsentKitItem) -> Bool
63 | func isReviewed (_ item: ConsentKitItem) -> Bool
64 | func setAccepted (_ value: Bool, for item: ConsentKitItem)
65 | func reset (_ item: ConsentKitItem)// Optional
66 | }
67 | ```
68 |
69 | ## Contribution
70 | Help me create a complete list of services that the developers can use.
71 | Thanks.
72 |
--------------------------------------------------------------------------------
/src/ConsentKitTableViewDataSource.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ConsentKitTableViewDataSource.swift
3 | // Gdpr
4 | //
5 | // Created by Cristian Baluta on 05/06/2018.
6 | // Copyright © 2018 Imagin soft. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ConsentKitTableViewDataSource: NSObject, UITableViewDelegate, UITableViewDataSource {
12 |
13 | var items: [ConsentKitItem] = []
14 |
15 | func numberOfSections(in tableView: UITableView) -> Int {
16 | return 1
17 | }
18 |
19 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
20 | return items.count
21 | }
22 |
23 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
24 |
25 | let item = items[indexPath.row]
26 | var cell: ConsentKitCellProtocol = ConsentKitCell.instantiateFromXib()
27 | cell.title = item.title()
28 | cell.subtitle = item.description()
29 | cell.value = gdpr.isAccepted(item)
30 | cell.valueDidChange = { isOn in
31 | self.item(item, didChangeValue: isOn, in: cell)
32 | }
33 |
34 | return cell as! ConsentKitCell
35 | }
36 |
37 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
38 | tableView.deselectRow(at: indexPath, animated: true)
39 | }
40 |
41 | func item(_ item: ConsentKitItem, didChangeValue value: Bool, in cell: ConsentKitCellProtocol) {
42 |
43 | if value {
44 | guard let message = item.alertMessage() else {
45 | self.gdpr.setAccepted(true, for: item)
46 | self.didAccept?(item)
47 | return
48 | }
49 | let alert = UIAlertController(title: item.title(), message: message, preferredStyle: .alert)
50 | alert.addAction(
51 | UIAlertAction(title: "Accept", style: .default, handler: { _ in
52 | self.gdpr.setAccepted(true, for: item)
53 | self.didAccept?(item)
54 | })
55 | )
56 | alert.addAction(
57 | UIAlertAction(title: "Decline", style: .cancel, handler: { _ in
58 | var cell = cell
59 | cell.value = false
60 | self.gdpr.setAccepted(false, for: item)
61 | self.didReject?(item)
62 | })
63 | )
64 | self.present(alert, animated: true, completion: nil)
65 | } else {
66 | self.gdpr.setAccepted(false, for: item)
67 | didReject?(item)
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/ConsentKit.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ConsentKit.swift
3 | //
4 | // Created by Cristian Baluta on 21/05/2018.
5 | // Copyright © 2018 Imagin soft. All rights reserved.
6 | //
7 |
8 | import Foundation
9 |
10 | protocol ConsentKitItem {
11 | var rawValue: String {get}
12 | /// Title used in the cell and alert
13 | func title() -> String
14 | /// Description used in the cell
15 | func description() -> String
16 | /// Message displayed in an alert when the switch is turned on.
17 | func alertMessage() -> String?
18 | }
19 |
20 | protocol ConsentKitDataSource {
21 | /// Returns if the item has a value of true
22 | func isAccepted (_ item: ConsentKitItem) -> Bool
23 | /// Returns if the item's value is different than nil, which means it was reviewed
24 | func isReviewed (_ item: ConsentKitItem) -> Bool
25 | /// Set a value for the item
26 | func setAccepted (_ value: Bool, for item: ConsentKitItem)
27 | /// Resets the value of an item, which means that isReviewed will return false after that
28 | func reset (_ item: ConsentKitItem)
29 | }
30 |
31 | extension ConsentKitDataSource {
32 | func reset (_ item: ConsentKitItem) {
33 | // This is a empty implementation to allow this method to be optional
34 | }
35 | }
36 |
37 | class ConsentKit {
38 |
39 | /// Assign a custom dataSource. By default UserDefaults is used and each key is prefixed with "ConsentKit-"
40 | var dataSource: ConsentKitDataSource = ConsentKitUserDefaultsDataSource()
41 |
42 | convenience init (dataSource: ConsentKitDataSource) {
43 | self.init()
44 | self.dataSource = dataSource
45 | }
46 |
47 | /// Returns if there's any value that was not reviewed
48 | /// Used to check if the ConsentKitViewController should be presented or not
49 | /// This will also be useful to present the controller if any new service added later in the app needs reviewing
50 | func needsReviewing(_ items: [ConsentKitItem]) -> Bool {
51 | for item in items {
52 | if !isReviewed(item) {
53 | return true
54 | }
55 | }
56 | return false
57 | }
58 | }
59 |
60 | extension ConsentKit: ConsentKitDataSource {
61 |
62 | func isAccepted (_ item: ConsentKitItem) -> Bool {
63 | return dataSource.isAccepted(item)
64 | }
65 |
66 | func isReviewed (_ item: ConsentKitItem) -> Bool {
67 | return dataSource.isReviewed(item)
68 | }
69 |
70 | func setAccepted (_ value: Bool, for item: ConsentKitItem) {
71 | dataSource.setAccepted(value, for: item)
72 | }
73 |
74 | func reset (_ item: ConsentKitItem) {
75 | dataSource.reset(item)
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/ConsentKitViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ConsentKitViewController.swift
3 | //
4 | // Created by Cristian Baluta on 21/05/2018.
5 | // Copyright © 2018 Cristian Baluta. All rights reserved.
6 | //
7 |
8 | import UIKit
9 |
10 | class ConsentKitViewController: UITableViewController {
11 |
12 | var didAccept: ((ConsentKitItem) -> Void)?
13 | var didReject: ((ConsentKitItem) -> Void)?
14 | var didFinishReview: (() -> Void)?
15 | var items: [ConsentKitItem] = [] {
16 | didSet {
17 | tableView.reloadData()
18 | }
19 | }
20 | fileprivate let gdpr = ConsentKit()
21 |
22 | override func viewDidLoad() {
23 | super.viewDidLoad()
24 |
25 | tableView.tableFooterView = UIView()
26 | }
27 |
28 | override func viewWillAppear(_ animated: Bool) {
29 | super.viewWillAppear(animated)
30 |
31 | if self.navigationController == nil {
32 | // Add a custom header only if the VC is not pushed into a navigationController
33 | let header = CloudKitViewControllerHeader(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 80))
34 | header.didDone = {
35 | self.handleDone()
36 | self.dismiss(animated: true, completion: nil)
37 | }
38 | tableView.tableHeaderView = header
39 | } else {
40 | self.title = "Review services!"
41 | self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(handleDone))
42 | }
43 | }
44 |
45 | // MARK: - Table view data source
46 |
47 | override func numberOfSections(in tableView: UITableView) -> Int {
48 | return 1
49 | }
50 |
51 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
52 | return items.count
53 | }
54 |
55 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
56 |
57 | let item = items[indexPath.row]
58 | var cell: ConsentKitCellProtocol = ConsentKitCell.instantiateFromXib()
59 | cell.title = item.title()
60 | cell.subtitle = item.description()
61 | cell.value = gdpr.isAccepted(item)
62 | cell.valueDidChange = { isOn in
63 | self.item(item, didChangeValue: isOn, in: cell)
64 | }
65 |
66 | return cell as! ConsentKitCell
67 | }
68 |
69 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
70 | tableView.deselectRow(at: indexPath, animated: true)
71 | }
72 |
73 | // MARK: - Switch changed
74 |
75 | func item(_ item: ConsentKitItem, didChangeValue value: Bool, in cell: ConsentKitCellProtocol) {
76 |
77 | if value {
78 | guard let message = item.alertMessage() else {
79 | self.gdpr.setAccepted(true, for: item)
80 | self.didAccept?(item)
81 | return
82 | }
83 | let alert = UIAlertController(title: item.title(), message: message, preferredStyle: .alert)
84 | alert.addAction(
85 | UIAlertAction(title: "Accept", style: .default, handler: { _ in
86 | self.gdpr.setAccepted(true, for: item)
87 | self.didAccept?(item)
88 | })
89 | )
90 | alert.addAction(
91 | UIAlertAction(title: "Decline", style: .cancel, handler: { _ in
92 | var cell = cell
93 | cell.value = false
94 | self.gdpr.setAccepted(false, for: item)
95 | self.didReject?(item)
96 | })
97 | )
98 | self.present(alert, animated: true, completion: nil)
99 | } else {
100 | self.gdpr.setAccepted(false, for: item)
101 | didReject?(item)
102 | }
103 | }
104 |
105 | @objc func handleDone() {
106 | // Set to false the untouched switches, to prevent gdpr being called again
107 | for item in items {
108 | if !gdpr.isReviewed(item) {
109 | gdpr.setAccepted(false, for: item)
110 | }
111 | }
112 | didFinishReview?()
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/src/ConsentKitCell.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/demo-ios/Gdpr/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
116 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
--------------------------------------------------------------------------------
/demo-ios/Gdpr.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 283DB05C20BADECD00A8BC14 /* ConsentKitCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 283DB05B20BADECD00A8BC14 /* ConsentKitCell.xib */; };
11 | 283DB05E20BC77D200A8BC14 /* ConsentKitCellProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 283DB05D20BC77D200A8BC14 /* ConsentKitCellProtocol.swift */; };
12 | 2845157D20B3528B009F3EE1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2845157C20B3528B009F3EE1 /* AppDelegate.swift */; };
13 | 2845157F20B3528B009F3EE1 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2845157E20B3528B009F3EE1 /* ViewController.swift */; };
14 | 2845158220B3528B009F3EE1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2845158020B3528B009F3EE1 /* Main.storyboard */; };
15 | 2845158420B3528F009F3EE1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2845158320B3528F009F3EE1 /* Assets.xcassets */; };
16 | 2845158720B3528F009F3EE1 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2845158520B3528F009F3EE1 /* LaunchScreen.storyboard */; };
17 | 2845159320B352F4009F3EE1 /* CloudKitViewControllerHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2845158F20B352F4009F3EE1 /* CloudKitViewControllerHeader.swift */; };
18 | 2845159420B352F4009F3EE1 /* ConsentKitCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2845159020B352F4009F3EE1 /* ConsentKitCell.swift */; };
19 | 2845159520B352F4009F3EE1 /* ConsentKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2845159120B352F4009F3EE1 /* ConsentKit.swift */; };
20 | 2845159620B352F4009F3EE1 /* ConsentKitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2845159220B352F4009F3EE1 /* ConsentKitViewController.swift */; };
21 | 2845159820B4BB95009F3EE1 /* SimpleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2845159720B4BB95009F3EE1 /* SimpleViewController.swift */; };
22 | 2845159A20B4BDBC009F3EE1 /* NavigationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2845159920B4BDBC009F3EE1 /* NavigationViewController.swift */; };
23 | 2845159C20B5EA1C009F3EE1 /* InMemoryDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2845159B20B5EA1C009F3EE1 /* InMemoryDataSource.swift */; };
24 | 2845159E20B5EDD6009F3EE1 /* ConsentKitUserDefaultsDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2845159D20B5EDD6009F3EE1 /* ConsentKitUserDefaultsDataSource.swift */; };
25 | 284515A020B5F738009F3EE1 /* ConsentKitServices.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2845159F20B5F738009F3EE1 /* ConsentKitServices.swift */; };
26 | 5684412C20C5A4DB00D9A471 /* TableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5684412B20C5A4DB00D9A471 /* TableViewController.swift */; };
27 | 5684413220C6D62E00D9A471 /* ConsentKitTableViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5684413120C6D62E00D9A471 /* ConsentKitTableViewDataSource.swift */; };
28 | /* End PBXBuildFile section */
29 |
30 | /* Begin PBXFileReference section */
31 | 283DB05B20BADECD00A8BC14 /* ConsentKitCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ConsentKitCell.xib; sourceTree = ""; };
32 | 283DB05D20BC77D200A8BC14 /* ConsentKitCellProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsentKitCellProtocol.swift; sourceTree = ""; };
33 | 2845157920B3528B009F3EE1 /* Gdpr.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Gdpr.app; sourceTree = BUILT_PRODUCTS_DIR; };
34 | 2845157C20B3528B009F3EE1 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
35 | 2845157E20B3528B009F3EE1 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
36 | 2845158120B3528B009F3EE1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
37 | 2845158320B3528F009F3EE1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
38 | 2845158620B3528F009F3EE1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
39 | 2845158820B3528F009F3EE1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
40 | 2845158F20B352F4009F3EE1 /* CloudKitViewControllerHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CloudKitViewControllerHeader.swift; sourceTree = ""; };
41 | 2845159020B352F4009F3EE1 /* ConsentKitCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConsentKitCell.swift; sourceTree = ""; };
42 | 2845159120B352F4009F3EE1 /* ConsentKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConsentKit.swift; sourceTree = ""; };
43 | 2845159220B352F4009F3EE1 /* ConsentKitViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConsentKitViewController.swift; sourceTree = ""; };
44 | 2845159720B4BB95009F3EE1 /* SimpleViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleViewController.swift; sourceTree = ""; };
45 | 2845159920B4BDBC009F3EE1 /* NavigationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationViewController.swift; sourceTree = ""; };
46 | 2845159B20B5EA1C009F3EE1 /* InMemoryDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InMemoryDataSource.swift; sourceTree = ""; };
47 | 2845159D20B5EDD6009F3EE1 /* ConsentKitUserDefaultsDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsentKitUserDefaultsDataSource.swift; sourceTree = ""; };
48 | 2845159F20B5F738009F3EE1 /* ConsentKitServices.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsentKitServices.swift; sourceTree = ""; };
49 | 5684412B20C5A4DB00D9A471 /* TableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewController.swift; sourceTree = ""; };
50 | 5684413120C6D62E00D9A471 /* ConsentKitTableViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsentKitTableViewDataSource.swift; sourceTree = ""; };
51 | /* End PBXFileReference section */
52 |
53 | /* Begin PBXFrameworksBuildPhase section */
54 | 2845157620B3528B009F3EE1 /* Frameworks */ = {
55 | isa = PBXFrameworksBuildPhase;
56 | buildActionMask = 2147483647;
57 | files = (
58 | );
59 | runOnlyForDeploymentPostprocessing = 0;
60 | };
61 | /* End PBXFrameworksBuildPhase section */
62 |
63 | /* Begin PBXGroup section */
64 | 2845157020B3528B009F3EE1 = {
65 | isa = PBXGroup;
66 | children = (
67 | 2845157B20B3528B009F3EE1 /* Gdpr */,
68 | 2845157A20B3528B009F3EE1 /* Products */,
69 | );
70 | sourceTree = "";
71 | };
72 | 2845157A20B3528B009F3EE1 /* Products */ = {
73 | isa = PBXGroup;
74 | children = (
75 | 2845157920B3528B009F3EE1 /* Gdpr.app */,
76 | );
77 | name = Products;
78 | sourceTree = "";
79 | };
80 | 2845157B20B3528B009F3EE1 /* Gdpr */ = {
81 | isa = PBXGroup;
82 | children = (
83 | 2845157C20B3528B009F3EE1 /* AppDelegate.swift */,
84 | 2845157E20B3528B009F3EE1 /* ViewController.swift */,
85 | 2845159720B4BB95009F3EE1 /* SimpleViewController.swift */,
86 | 2845159920B4BDBC009F3EE1 /* NavigationViewController.swift */,
87 | 5684412B20C5A4DB00D9A471 /* TableViewController.swift */,
88 | 2845159B20B5EA1C009F3EE1 /* InMemoryDataSource.swift */,
89 | 2845158020B3528B009F3EE1 /* Main.storyboard */,
90 | 2845158320B3528F009F3EE1 /* Assets.xcassets */,
91 | 2845158520B3528F009F3EE1 /* LaunchScreen.storyboard */,
92 | 2845158820B3528F009F3EE1 /* Info.plist */,
93 | 2845158E20B352F4009F3EE1 /* src */,
94 | );
95 | path = Gdpr;
96 | sourceTree = "";
97 | };
98 | 2845158E20B352F4009F3EE1 /* src */ = {
99 | isa = PBXGroup;
100 | children = (
101 | 2845159120B352F4009F3EE1 /* ConsentKit.swift */,
102 | 2845159F20B5F738009F3EE1 /* ConsentKitServices.swift */,
103 | 2845159D20B5EDD6009F3EE1 /* ConsentKitUserDefaultsDataSource.swift */,
104 | 2845159220B352F4009F3EE1 /* ConsentKitViewController.swift */,
105 | 5684413120C6D62E00D9A471 /* ConsentKitTableViewDataSource.swift */,
106 | 283DB05D20BC77D200A8BC14 /* ConsentKitCellProtocol.swift */,
107 | 2845159020B352F4009F3EE1 /* ConsentKitCell.swift */,
108 | 283DB05B20BADECD00A8BC14 /* ConsentKitCell.xib */,
109 | 2845158F20B352F4009F3EE1 /* CloudKitViewControllerHeader.swift */,
110 | );
111 | name = src;
112 | path = ../../src;
113 | sourceTree = "";
114 | };
115 | /* End PBXGroup section */
116 |
117 | /* Begin PBXNativeTarget section */
118 | 2845157820B3528B009F3EE1 /* Gdpr */ = {
119 | isa = PBXNativeTarget;
120 | buildConfigurationList = 2845158B20B3528F009F3EE1 /* Build configuration list for PBXNativeTarget "Gdpr" */;
121 | buildPhases = (
122 | 2845157520B3528B009F3EE1 /* Sources */,
123 | 2845157620B3528B009F3EE1 /* Frameworks */,
124 | 2845157720B3528B009F3EE1 /* Resources */,
125 | );
126 | buildRules = (
127 | );
128 | dependencies = (
129 | );
130 | name = Gdpr;
131 | productName = Gdpr;
132 | productReference = 2845157920B3528B009F3EE1 /* Gdpr.app */;
133 | productType = "com.apple.product-type.application";
134 | };
135 | /* End PBXNativeTarget section */
136 |
137 | /* Begin PBXProject section */
138 | 2845157120B3528B009F3EE1 /* Project object */ = {
139 | isa = PBXProject;
140 | attributes = {
141 | LastSwiftUpdateCheck = 0930;
142 | LastUpgradeCheck = 0930;
143 | ORGANIZATIONNAME = "Imagin soft";
144 | TargetAttributes = {
145 | 2845157820B3528B009F3EE1 = {
146 | CreatedOnToolsVersion = 9.3;
147 | };
148 | };
149 | };
150 | buildConfigurationList = 2845157420B3528B009F3EE1 /* Build configuration list for PBXProject "Gdpr" */;
151 | compatibilityVersion = "Xcode 9.3";
152 | developmentRegion = en;
153 | hasScannedForEncodings = 0;
154 | knownRegions = (
155 | en,
156 | Base,
157 | );
158 | mainGroup = 2845157020B3528B009F3EE1;
159 | productRefGroup = 2845157A20B3528B009F3EE1 /* Products */;
160 | projectDirPath = "";
161 | projectRoot = "";
162 | targets = (
163 | 2845157820B3528B009F3EE1 /* Gdpr */,
164 | );
165 | };
166 | /* End PBXProject section */
167 |
168 | /* Begin PBXResourcesBuildPhase section */
169 | 2845157720B3528B009F3EE1 /* Resources */ = {
170 | isa = PBXResourcesBuildPhase;
171 | buildActionMask = 2147483647;
172 | files = (
173 | 2845158720B3528F009F3EE1 /* LaunchScreen.storyboard in Resources */,
174 | 283DB05C20BADECD00A8BC14 /* ConsentKitCell.xib in Resources */,
175 | 2845158420B3528F009F3EE1 /* Assets.xcassets in Resources */,
176 | 2845158220B3528B009F3EE1 /* Main.storyboard in Resources */,
177 | );
178 | runOnlyForDeploymentPostprocessing = 0;
179 | };
180 | /* End PBXResourcesBuildPhase section */
181 |
182 | /* Begin PBXSourcesBuildPhase section */
183 | 2845157520B3528B009F3EE1 /* Sources */ = {
184 | isa = PBXSourcesBuildPhase;
185 | buildActionMask = 2147483647;
186 | files = (
187 | 2845159A20B4BDBC009F3EE1 /* NavigationViewController.swift in Sources */,
188 | 2845159E20B5EDD6009F3EE1 /* ConsentKitUserDefaultsDataSource.swift in Sources */,
189 | 5684412C20C5A4DB00D9A471 /* TableViewController.swift in Sources */,
190 | 284515A020B5F738009F3EE1 /* ConsentKitServices.swift in Sources */,
191 | 2845157F20B3528B009F3EE1 /* ViewController.swift in Sources */,
192 | 2845159C20B5EA1C009F3EE1 /* InMemoryDataSource.swift in Sources */,
193 | 2845159420B352F4009F3EE1 /* ConsentKitCell.swift in Sources */,
194 | 2845159620B352F4009F3EE1 /* ConsentKitViewController.swift in Sources */,
195 | 5684413220C6D62E00D9A471 /* ConsentKitTableViewDataSource.swift in Sources */,
196 | 283DB05E20BC77D200A8BC14 /* ConsentKitCellProtocol.swift in Sources */,
197 | 2845157D20B3528B009F3EE1 /* AppDelegate.swift in Sources */,
198 | 2845159320B352F4009F3EE1 /* CloudKitViewControllerHeader.swift in Sources */,
199 | 2845159820B4BB95009F3EE1 /* SimpleViewController.swift in Sources */,
200 | 2845159520B352F4009F3EE1 /* ConsentKit.swift in Sources */,
201 | );
202 | runOnlyForDeploymentPostprocessing = 0;
203 | };
204 | /* End PBXSourcesBuildPhase section */
205 |
206 | /* Begin PBXVariantGroup section */
207 | 2845158020B3528B009F3EE1 /* Main.storyboard */ = {
208 | isa = PBXVariantGroup;
209 | children = (
210 | 2845158120B3528B009F3EE1 /* Base */,
211 | );
212 | name = Main.storyboard;
213 | sourceTree = "";
214 | };
215 | 2845158520B3528F009F3EE1 /* LaunchScreen.storyboard */ = {
216 | isa = PBXVariantGroup;
217 | children = (
218 | 2845158620B3528F009F3EE1 /* Base */,
219 | );
220 | name = LaunchScreen.storyboard;
221 | sourceTree = "";
222 | };
223 | /* End PBXVariantGroup section */
224 |
225 | /* Begin XCBuildConfiguration section */
226 | 2845158920B3528F009F3EE1 /* Debug */ = {
227 | isa = XCBuildConfiguration;
228 | buildSettings = {
229 | ALWAYS_SEARCH_USER_PATHS = NO;
230 | CLANG_ANALYZER_NONNULL = YES;
231 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
232 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
233 | CLANG_CXX_LIBRARY = "libc++";
234 | CLANG_ENABLE_MODULES = YES;
235 | CLANG_ENABLE_OBJC_ARC = YES;
236 | CLANG_ENABLE_OBJC_WEAK = YES;
237 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
238 | CLANG_WARN_BOOL_CONVERSION = YES;
239 | CLANG_WARN_COMMA = YES;
240 | CLANG_WARN_CONSTANT_CONVERSION = YES;
241 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
242 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
243 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
244 | CLANG_WARN_EMPTY_BODY = YES;
245 | CLANG_WARN_ENUM_CONVERSION = YES;
246 | CLANG_WARN_INFINITE_RECURSION = YES;
247 | CLANG_WARN_INT_CONVERSION = YES;
248 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
249 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
250 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
251 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
252 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
253 | CLANG_WARN_STRICT_PROTOTYPES = YES;
254 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
255 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
256 | CLANG_WARN_UNREACHABLE_CODE = YES;
257 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
258 | CODE_SIGN_IDENTITY = "iPhone Developer";
259 | COPY_PHASE_STRIP = NO;
260 | DEBUG_INFORMATION_FORMAT = dwarf;
261 | ENABLE_STRICT_OBJC_MSGSEND = YES;
262 | ENABLE_TESTABILITY = YES;
263 | GCC_C_LANGUAGE_STANDARD = gnu11;
264 | GCC_DYNAMIC_NO_PIC = NO;
265 | GCC_NO_COMMON_BLOCKS = YES;
266 | GCC_OPTIMIZATION_LEVEL = 0;
267 | GCC_PREPROCESSOR_DEFINITIONS = (
268 | "DEBUG=1",
269 | "$(inherited)",
270 | );
271 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
272 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
273 | GCC_WARN_UNDECLARED_SELECTOR = YES;
274 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
275 | GCC_WARN_UNUSED_FUNCTION = YES;
276 | GCC_WARN_UNUSED_VARIABLE = YES;
277 | IPHONEOS_DEPLOYMENT_TARGET = 11.3;
278 | MTL_ENABLE_DEBUG_INFO = YES;
279 | ONLY_ACTIVE_ARCH = YES;
280 | SDKROOT = iphoneos;
281 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
282 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
283 | };
284 | name = Debug;
285 | };
286 | 2845158A20B3528F009F3EE1 /* Release */ = {
287 | isa = XCBuildConfiguration;
288 | buildSettings = {
289 | ALWAYS_SEARCH_USER_PATHS = NO;
290 | CLANG_ANALYZER_NONNULL = YES;
291 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
292 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
293 | CLANG_CXX_LIBRARY = "libc++";
294 | CLANG_ENABLE_MODULES = YES;
295 | CLANG_ENABLE_OBJC_ARC = YES;
296 | CLANG_ENABLE_OBJC_WEAK = YES;
297 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
298 | CLANG_WARN_BOOL_CONVERSION = YES;
299 | CLANG_WARN_COMMA = YES;
300 | CLANG_WARN_CONSTANT_CONVERSION = YES;
301 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
302 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
303 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
304 | CLANG_WARN_EMPTY_BODY = YES;
305 | CLANG_WARN_ENUM_CONVERSION = YES;
306 | CLANG_WARN_INFINITE_RECURSION = YES;
307 | CLANG_WARN_INT_CONVERSION = YES;
308 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
309 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
310 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
311 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
312 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
313 | CLANG_WARN_STRICT_PROTOTYPES = YES;
314 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
315 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
316 | CLANG_WARN_UNREACHABLE_CODE = YES;
317 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
318 | CODE_SIGN_IDENTITY = "iPhone Developer";
319 | COPY_PHASE_STRIP = NO;
320 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
321 | ENABLE_NS_ASSERTIONS = NO;
322 | ENABLE_STRICT_OBJC_MSGSEND = YES;
323 | GCC_C_LANGUAGE_STANDARD = gnu11;
324 | GCC_NO_COMMON_BLOCKS = YES;
325 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
326 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
327 | GCC_WARN_UNDECLARED_SELECTOR = YES;
328 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
329 | GCC_WARN_UNUSED_FUNCTION = YES;
330 | GCC_WARN_UNUSED_VARIABLE = YES;
331 | IPHONEOS_DEPLOYMENT_TARGET = 11.3;
332 | MTL_ENABLE_DEBUG_INFO = NO;
333 | SDKROOT = iphoneos;
334 | SWIFT_COMPILATION_MODE = wholemodule;
335 | SWIFT_OPTIMIZATION_LEVEL = "-O";
336 | VALIDATE_PRODUCT = YES;
337 | };
338 | name = Release;
339 | };
340 | 2845158C20B3528F009F3EE1 /* Debug */ = {
341 | isa = XCBuildConfiguration;
342 | buildSettings = {
343 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
344 | CODE_SIGN_STYLE = Automatic;
345 | DEVELOPMENT_TEAM = 5NHDC5EV44;
346 | INFOPLIST_FILE = Gdpr/Info.plist;
347 | LD_RUNPATH_SEARCH_PATHS = (
348 | "$(inherited)",
349 | "@executable_path/Frameworks",
350 | );
351 | PRODUCT_BUNDLE_IDENTIFIER = ro.imagin.Gdpr;
352 | PRODUCT_NAME = "$(TARGET_NAME)";
353 | SWIFT_VERSION = 4.0;
354 | TARGETED_DEVICE_FAMILY = "1,2";
355 | };
356 | name = Debug;
357 | };
358 | 2845158D20B3528F009F3EE1 /* Release */ = {
359 | isa = XCBuildConfiguration;
360 | buildSettings = {
361 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
362 | CODE_SIGN_STYLE = Automatic;
363 | DEVELOPMENT_TEAM = 5NHDC5EV44;
364 | INFOPLIST_FILE = Gdpr/Info.plist;
365 | LD_RUNPATH_SEARCH_PATHS = (
366 | "$(inherited)",
367 | "@executable_path/Frameworks",
368 | );
369 | PRODUCT_BUNDLE_IDENTIFIER = ro.imagin.Gdpr;
370 | PRODUCT_NAME = "$(TARGET_NAME)";
371 | SWIFT_VERSION = 4.0;
372 | TARGETED_DEVICE_FAMILY = "1,2";
373 | };
374 | name = Release;
375 | };
376 | /* End XCBuildConfiguration section */
377 |
378 | /* Begin XCConfigurationList section */
379 | 2845157420B3528B009F3EE1 /* Build configuration list for PBXProject "Gdpr" */ = {
380 | isa = XCConfigurationList;
381 | buildConfigurations = (
382 | 2845158920B3528F009F3EE1 /* Debug */,
383 | 2845158A20B3528F009F3EE1 /* Release */,
384 | );
385 | defaultConfigurationIsVisible = 0;
386 | defaultConfigurationName = Release;
387 | };
388 | 2845158B20B3528F009F3EE1 /* Build configuration list for PBXNativeTarget "Gdpr" */ = {
389 | isa = XCConfigurationList;
390 | buildConfigurations = (
391 | 2845158C20B3528F009F3EE1 /* Debug */,
392 | 2845158D20B3528F009F3EE1 /* Release */,
393 | );
394 | defaultConfigurationIsVisible = 0;
395 | defaultConfigurationName = Release;
396 | };
397 | /* End XCConfigurationList section */
398 | };
399 | rootObject = 2845157120B3528B009F3EE1 /* Project object */;
400 | }
401 |
--------------------------------------------------------------------------------