Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The importance of Privacy on iOS (State of the ...

The importance of Privacy on iOS (State of the Union late 2025)

A lot of time Privacy of my data as a user is not a priority for Developers. Wether it’s my calendar, my contacts, my location, photos, I want as a user to be able to use an app without all of those attacks in my privacy.

I summarise here some things an iOS developer should do to ensure the most critical user can still use an app in some regards, and not just say “I need all your information” like on other platforms. This is the beauty of iOS, being able to have fine grained control over your data (although not enough) so let’s do this all together, as a beautiful community concerned by Privacy.

This talk will also be a “State of the Union” where we are in 2025, since many new additions arised since I wrote my book about Privacy. Most notably, I will try to motivate you to support iOS 18 as the lowest, for many Privacy reasons.

Avatar for Manu Carrasco Molina

Manu Carrasco Molina

November 12, 2025
Tweet

More Decks by Manu Carrasco Molina

Other Decks in Programming

Transcript

  1. The importance of Privacy on iOS State of the Union

    late 2025 Manu @StuFFmc Carrasco Molina
  2. > who/whyami? speaks ! " guy born in # living

    in Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 3
  3. > who/whyami? speaks ! " guy born in # living

    in XX years * + as a dev, XX with #techs Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 3
  4. > who/whyami? speaks ! " guy born in # living

    in XX years * + as a dev, XX with #techs Since Day 1 with iPhoneOS, Swift, SwiftUI, visionOS Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 3
  5. > who/whyami? speaks ! " guy born in # living

    in XX years * + as a dev, XX with #techs Since Day 1 with iPhoneOS, Swift, SwiftUI, visionOS XX years of political involvement with the #party Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 3
  6. > who/whyami? speaks ! " guy born in # living

    in XX years * + as a dev, XX with #techs Since Day 1 with iPhoneOS, Swift, SwiftUI, visionOS XX years of political involvement with the #party XX years of climate / & human rights #activism #palestine Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 3
  7. > who/whyami? speaks ! " guy born in # living

    in XX years * + as a dev, XX with #techs Since Day 1 with iPhoneOS, Swift, SwiftUI, visionOS XX years of political involvement with the #party XX years of climate / & human rights #activism #palestine 12+ 1 y 2 without 3 meat, 9+ of it #vegan Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 3
  8. We’ve come a loooooong way iPhoneOS wasn’t so much about

    Privacy This is my iPhone running iPhoneOS 3.1.3 Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 5
  9. Give Steve 3 Minutes This was late 2010. Before anyone

    spoke about Privacy Before GDPR, but after iOS 4.2 Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 6
  10. 's Privacy Pilars Data Minimization Manu @StuFFmc Carrasco Molina •

    The Importance of Privacy on iOS, Do iOS ‘25 8
  11. 's Privacy Pilars Data Minimization On-device processing Manu @StuFFmc Carrasco

    Molina • The Importance of Privacy on iOS, Do iOS ‘25 8
  12. 's Privacy Pilars Data Minimization On-device processing Tried for webapps?

    Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 8
  13. 's Privacy Pilars Data Minimization On-device processing Tried for webapps?

    Transparency and control Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 8
  14. 's Privacy Pilars Data Minimization On-device processing Tried for webapps?

    Transparency and control Security Protections Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 8
  15. Location Services A video from early 2013 and lovely iOS

    6 import Core Location early 2013 YouTube: DHTV: How To Use And Turn On Location Services iPhone Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 9
  16. Location Services A video from early 2013 and lovely iOS

    6 import Core Location early 2013 YouTube: DHTV: How To Use And Turn On Location Services iPhone Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 9
  17. Location Services A video from early 2013 and lovely iOS

    6 import Core Location early 2013 YouTube: DHTV: How To Use And Turn On Location Services iPhone Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 9
  18. Location Services A video from early 2013 and lovely iOS

    6 import Core Location First, let’s compare 2013 to 2025 early 2013 YouTube: DHTV: How To Use And Turn On Location Services iPhone Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 9
  19. 10

  20. 11

  21. 12

  22. 13

  23. The Manager @Observable class LocationManager { var authorizationStatus: CLAuthorizationStatus? }

    struct LocationView: View { @State private var manager = LocationManager() var body: some View { if let status = manager.authorizationStatus { Text("\(status.rawValue)") } // nil, nothing to see here... } } Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 17
  24. The Manager @Observable class LocationManager { var authorizationStatus: CLAuthorizationStatus? }

    struct LocationView: View { @State private var manager = LocationManager() var body: some View { if let status = manager.authorizationStatus { Text("\(status.rawValue)") } // nil, nothing to see here... } } Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 17
  25. The Manager @Observable class LocationManager { var authorizationStatus: CLAuthorizationStatus? }

    struct LocationView: View { @State private var manager = LocationManager() var body: some View { if let status = manager.authorizationStatus { Text("\(status.rawValue)") } // nil, nothing to see here... } } Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 17
  26. The Manager @Observable class LocationManager { var authorizationStatus: CLAuthorizationStatus? }

    struct LocationView: View { @State private var manager = LocationManager() var body: some View { if let status = manager.authorizationStatus { Text("\(status.rawValue)") } // nil, nothing to see here... } } Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 17
  27. Statuses enum CLAuthorizationStatus { case notDetermined = 0 // "When

    I Share" case restricted = 1 case denied = 2 // "Never" case authorizedAlways = 3 // iOS 8 case authorizedWhenInUse = 4 // iOS 8 static var authorized // authorizedAlways } Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 18
  28. Statuses enum CLAuthorizationStatus { case notDetermined = 0 // "When

    I Share" case restricted = 1 case denied = 2 // "Never" case authorizedAlways = 3 // iOS 8 case authorizedWhenInUse = 4 // iOS 8 static var authorized // authorizedAlways } Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 18
  29. Statuses enum CLAuthorizationStatus { case notDetermined = 0 // "When

    I Share" case restricted = 1 case denied = 2 // "Never" case authorizedAlways = 3 // iOS 8 case authorizedWhenInUse = 4 // iOS 8 static var authorized // authorizedAlways } Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 18
  30. Statuses enum CLAuthorizationStatus { case notDetermined = 0 // "When

    I Share" case restricted = 1 case denied = 2 // "Never" case authorizedAlways = 3 // iOS 8 case authorizedWhenInUse = 4 // iOS 8 static var authorized // authorizedAlways } Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 18
  31. Statuses enum CLAuthorizationStatus { case notDetermined = 0 // "When

    I Share" case restricted = 1 case denied = 2 // "Never" case authorizedAlways = 3 // iOS 8 case authorizedWhenInUse = 4 // iOS 8 static var authorized // authorizedAlways } Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 18
  32. 19

  33. 20

  34. @Observable class LocationManager: NSObject, CLLocationManagerDelegate { private var manager =

    CLLocationManager() override init() { super.init() manager.delegate = self } func locationManagerDidChangeAuthorization( _ manager: CLLocationManager ) { authorizationStatus = manager.authorizationStatus } // 0, notDetermined } Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 21
  35. @Observable class LocationManager: NSObject, CLLocationManagerDelegate { private var manager =

    CLLocationManager() override init() { super.init() manager.delegate = self } func locationManagerDidChangeAuthorization( _ manager: CLLocationManager ) { authorizationStatus = manager.authorizationStatus } // 0, notDetermined } Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 21
  36. @Observable class LocationManager: NSObject, CLLocationManagerDelegate { private var manager =

    CLLocationManager() override init() { super.init() manager.delegate = self } func locationManagerDidChangeAuthorization( _ manager: CLLocationManager ) { authorizationStatus = manager.authorizationStatus } // 0, notDetermined } Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 21
  37. “Ask Next Time Or When I Share” import CoreLocationUI var

    body: some View { if let status = manager.authorizationStatus { Text("\(status.rawValue)") } LocationButton(.currentLocation) { // since iOS 15 manager.startUpdatingLocation() } } Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 22
  38. “Ask Next Time Or When I Share” import CoreLocationUI var

    body: some View { if let status = manager.authorizationStatus { Text("\(status.rawValue)") } LocationButton(.currentLocation) { // since iOS 15 manager.startUpdatingLocation() } } Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 22
  39. “Ask Next Time Or When I Share” import CoreLocationUI var

    body: some View { if let status = manager.authorizationStatus { Text("\(status.rawValue)") } LocationButton(.currentLocation) { // since iOS 15 manager.startUpdatingLocation() } } Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 22
  40. 23

  41. Missing in LocationManager var locations = [CLLocation]() func locationManager(_ manager:

    CLLocationManager, didUpdateLocations locations: [CLLocation]) { self.locations = locations } Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 24
  42. I like to use it, use it List(manager.locations, id: \.timestamp)

    { Text($0.timestamp .formatted(date: .omitted, time: .shortened) ) Text($0.coordinate.latitude.description) Text($0.coordinate.longitude.description) } Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 25
  43. I like to use it, use it List(manager.locations, id: \.timestamp)

    { Text($0.timestamp .formatted(date: .omitted, time: .shortened) ) Text($0.coordinate.latitude.description) Text($0.coordinate.longitude.description) } Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 25
  44. I like to use it, use it List(manager.locations, id: \.timestamp)

    { Text($0.timestamp .formatted(date: .omitted, time: .shortened) ) Text($0.coordinate.latitude.description) Text($0.coordinate.longitude.description) } Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 25
  45. I like to use it, use it List(manager.locations, id: \.timestamp)

    { Text($0.timestamp .formatted(date: .omitted, time: .shortened) ) Text($0.coordinate.latitude.description) Text($0.coordinate.longitude.description) } Convenient Date().formatted new since iOS 15 Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 25
  46. Save ! & " , Get only 1 Location LocationButton(.currentLocation)

    { manager.requestLocation() } Z. Veselinovic (CC BY-SA 2.0) 26
  47. Save ! & " , Get only 1 Location start?

    Don’t forget to stopLocation! 1 LocationButton(.currentLocation) { manager.requestLocation() } 1 ... when you get enough! Find My talk about Energy Optimization @ speakerdeck.com Z. Veselinovic (CC BY-SA 2.0) 26
  48. Save ! & " , Get only 1 Location start?

    Don’t forget to stopLocation! 1 requestLocation only gives one Delegate Callback LocationButton(.currentLocation) { manager.requestLocation() } 1 ... when you get enough! Find My talk about Energy Optimization @ speakerdeck.com Z. Veselinovic (CC BY-SA 2.0) 26
  49. Save ! & " , Get only 1 Location start?

    Don’t forget to stopLocation! 1 requestLocation only gives one Delegate Callback LocationButton(.currentLocation) { manager.requestLocation() } 1 ... when you get enough! Find My talk about Energy Optimization @ speakerdeck.com Z. Veselinovic (CC BY-SA 2.0) 26
  50. Save ! & " , Get only 1 Location start?

    Don’t forget to stopLocation! 1 requestLocation only gives one Delegate Callback LocationButton(.currentLocation) { manager.requestLocation() } 1 ... when you get enough! Find My talk about Energy Optimization @ speakerdeck.com Z. Veselinovic (CC BY-SA 2.0) 26
  51. !" CLLocationAccuracy typealias CLLocationAccuracy = Double The location service does

    its best to achieve the requested accuracy; however, apps must be prepared to use less accurate data. @available(iOS 4.0, *) let _BestForNavigation let _Best let _NearestTenMeters let _HundredMeters: let _Kilometer let _ThreeKilometers Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 27
  52. !" CLLocationAccuracy typealias CLLocationAccuracy = Double The location service does

    its best to achieve the requested accuracy; however, apps must be prepared to use less accurate data. @available(iOS 4.0, *) let _BestForNavigation let _Best let _NearestTenMeters let _HundredMeters: let _Kilometer let _ThreeKilometers Your decision as a developer! Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 27
  53. I Made a wish in the book Manu @StuFFmc Carrasco

    Molina • The Importance of Privacy on iOS, Do iOS ‘25 28
  54. I Made a wish in the book The book has

    “fresh” ! iOS 13 Code, and sooo... Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 28
  55. ↘ Accuracy ⚽ @available(iOS 14.0, *) let kCLLocationAccuracyReduced : CLLocationAccuracy

    Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 29
  56. ↘ Accuracy ⚽ @available(iOS 14.0, *) let kCLLocationAccuracyReduced : CLLocationAccuracy

    6 Kilometers in my tests Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 29
  57. Full or reduced @available(iOS, introduced: 14.0, deprecated: 14.0) open var

    isAuthorizedForPreciseLocation: Bool { get } @available(iOS 14.0, *) open var accuracyAuthorization: CLAccuracyAuthorization { get } public enum CLAccuracyAuthorization : Int { case fullAccuracy = 0 case reducedAccuracy = 1 } } Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 30
  58. The user has chosen to grant this application access to

    location information with reduced accuracy. Region monitoring and beacon ranging are not available to the application. Other CoreLocation APIs are available with reduced accuracy. Location estimates will have a horizontalAccuracy on the order of about 5km. Applications should be prepared to receive locations that are up to 20 minutes old. Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 31
  59. The Modern Manager (iOS 17) LocationButton(.shareMyCurrentLocation) { Task { for

    try await update in CLLocationUpdate.liveUpdates() { if let coordinate = update.location?.coordinate { latitude = coordinate.latitude longitude = coordinate.longitude } } } } // No Delegate, No Request! Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 32
  60. Explicitly Request Only If you can’t avoid it Manu @StuFFmc

    Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 34
  61. Allow once Arrived in iOS 13 Manu @StuFFmc Carrasco Molina

    • The Importance of Privacy on iOS, Do iOS ‘25 35
  62. Allow once Arrived in iOS 13 requestWhenInUseAuthorization Manu @StuFFmc Carrasco

    Molina • The Importance of Privacy on iOS, Do iOS ‘25 35
  63. Allow once Arrived in iOS 13 requestWhenInUseAuthorization Will also be

    displayed first for: Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 35
  64. Allow once Arrived in iOS 13 requestWhenInUseAuthorization Will also be

    displayed first for: requestAlwaysAuthorization Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 35
  65. Allow once Button order swapped in iOS 14 Error Domain=kCLErrorDomain

    Code=1 "(null)" NSLocationWhenInUseUsageDescription NSLocationAlwaysAndWhenInUseUsageDescription Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 36
  66. Allow once Button order swapped in iOS 14 If you

    don’t see the prompt but Error Domain=kCLErrorDomain Code=1 "(null)" NSLocationWhenInUseUsageDescription NSLocationAlwaysAndWhenInUseUsageDescription Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 36
  67. Allow once Button order swapped in iOS 14 If you

    don’t see the prompt but Error Domain=kCLErrorDomain Code=1 "(null)" NSLocationWhenInUseUsageDescription NSLocationAlwaysAndWhenInUseUsageDescription Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 36
  68. Allow once Button order swapped in iOS 14 If you

    don’t see the prompt but Error Domain=kCLErrorDomain Code=1 "(null)" NSLocationWhenInUseUsageDescription NSLocationAlwaysAndWhenInUseUsageDescription Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 36
  69. Allow once Button order swapped in iOS 14 If you

    don’t see the prompt but Error Domain=kCLErrorDomain Code=1 "(null)" NSLocationWhenInUseUsageDescription NSLocationAlwaysAndWhenInUseUsageDescription Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 36
  70. Allow once Button order swapped in iOS 14 If you

    don’t see the prompt but Error Domain=kCLErrorDomain Code=1 "(null)" You’ve probably forget NSLocationWhenInUseUsageDescription NSLocationAlwaysAndWhenInUseUsageDescription Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 36
  71. Allow once Button order swapped in iOS 14 If you

    don’t see the prompt but Error Domain=kCLErrorDomain Code=1 "(null)" You’ve probably forget NSLocationWhenInUseUsageDescription NSLocationAlwaysAndWhenInUseUsageDescription Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 36
  72. Allow once Button order swapped in iOS 14 If you

    don’t see the prompt but Error Domain=kCLErrorDomain Code=1 "(null)" You’ve probably forget NSLocationWhenInUseUsageDescription NSLocationAlwaysAndWhenInUseUsageDescription Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 36
  73. Allow once Button order swapped in iOS 14 If you

    don’t see the prompt but Error Domain=kCLErrorDomain Code=1 "(null)" You’ve probably forget NSLocationWhenInUseUsageDescription NSLocationAlwaysAndWhenInUseUsageDescription Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 36
  74. Allow once Button order swapped in iOS 14 If you

    don’t see the prompt but Error Domain=kCLErrorDomain Code=1 "(null)" You’ve probably forget NSLocationWhenInUseUsageDescription NSLocationAlwaysAndWhenInUseUsageDescription Settings only show the last one Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 36
  75. Allow once It is authorizedWhenInUse Manu @StuFFmc Carrasco Molina •

    The Importance of Privacy on iOS, Do iOS ‘25 37
  76. Allow once It is authorizedWhenInUse but only for one session

    Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 37
  77. Allow once It is authorizedWhenInUse but only for one session

    WHEN IN USE? My lame Demo String Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 37
  78. Always ! Will only happen after Manu @StuFFmc Carrasco Molina

    • The Importance of Privacy on iOS, Do iOS ‘25 38
  79. Always ! Will only happen after Avoid it if you

    can Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 38
  80. Always ! Will only happen after Avoid it if you

    can It’s draining battery Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 38
  81. Always ! The user will get a prompt To go

    back to When In Use Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 39
  82. Save ! & " , Region Monitoring Manu @StuFFmc Carrasco

    Molina • The Importance of Privacy on iOS, Do iOS ‘25 40
  83. Save ! & " , Region Monitoring Instead of checking

    the location Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 40
  84. Save ! & " , Region Monitoring Instead of checking

    the location Needs Always if running in the background Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 40
  85. Save ! & " , Region Monitoring Instead of checking

    the location Needs Always if running in the background Check the new CLMonitor since iOS 17 Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 40
  86. Save ! & " , Region Monitoring Instead of checking

    the location Needs Always if running in the background Check the new CLMonitor since iOS 17 Remember this won’t work with approximate location Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 40
  87. But wait... You can request it once! requestTemporary FullAccuracyAuthorization Manu

    @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 41
  88. But wait... You can request it once! requestTemporary FullAccuracyAuthorization Since

    iOS 14! Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 41
  89. Upgrade your code and users! Manu @StuFFmc Carrasco Molina •

    The Importance of Privacy on iOS, Do iOS ‘25 42
  90. Upgrade your code and users! Try to move to current

    (not Beta!) every year after WWDC Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 42
  91. Upgrade your code and users! Try to move to current

    (not Beta!) every year after WWDC e.g. by now your App should ideally only support iOS 18 Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 42
  92. Upgrade your code and users! Try to move to current

    (not Beta!) every year after WWDC e.g. by now your App should ideally only support iOS 18 It's your chance to clean your code, and get more privacy Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 42
  93. Upgrade your code and users! Try to move to current

    (not Beta!) every year after WWDC e.g. by now your App should ideally only support iOS 18 It's your chance to clean your code, and get more privacy … and now let’s give Tim 12 seconds ;) Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 42
  94. 43

  95. 45

  96. Access the library status = await PHPhotoLibrary.requestAuthorization(for: .readWrite) enum PHAuthorizationStatus

    { @available(iOS 8, *) case notDetermined = 0 case restricted = 1 case denied = 2 case authorized = 3 @available(iOS 14, *) case limited = 4 } Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 46
  97. Booom This app has crashed because it attempted to access

    privacy-sensitive data without a usage description. The app's Info.plist must contain an NSPhotoLibraryUsageDescription key with a string value explaining to the user how the app uses this data. Use descriptive Strings. Explain your users what you do. Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 47
  98. import PhotosUI Pick one or multiple, on demand Manu @StuFFmc

    Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 48
  99. PhotosPicker Uses Transferable Has many configurable options Manu @StuFFmc Carrasco

    Molina • The Importance of Privacy on iOS, Do iOS ‘25 49
  100. Dear User, You are a Manu @StuFFmc Carrasco Molina •

    The Importance of Privacy on iOS, Do iOS ‘25 52
  101. 53

  102. The Manager @Observable class ContactsManager { private var store =

    CNContactStore() var status: CNAuthorizationStatus init() { status = CNContactStore.authorizationStatus(for: .contacts) } } struct ContactsView: View { @State private var manager = ContactsManager() var body: some View { Text(manager.status.rawValue.description) } } Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 55
  103. CNAuthorizationStatus @available(iOS 9.0, *) // 2015. Before, we had `ABAddressBook`

    in C! public enum CNAuthorizationStatus : Int, @unchecked Sendable { case notDetermined = 0 case restricted = 1 case denied = 2 case authorized = 3 /** This application is authorized to access some contact data. */ @available(iOS 18.0, *) case limited = 4 } Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 56
  104. Good, Bad func good() { let descriptors = [ CNContactGivenNameKey,

    CNContactFamilyNameKey ] predicate(with: descriptors) } func bad() { predicate(with: descriptors) } Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 57
  105. Good, Bad func good() { let descriptors = [ CNContactGivenNameKey,

    CNContactFamilyNameKey ] predicate(with: descriptors) } func bad() { predicate(with: descriptors) } As a user, I have no clue about your descriptors / keysToFetch! Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 57
  106. Searchable (iOS 17) NavigationStack { List(manager.contacts) { Text($0.givenName) } .searchable(text:

    $search) } .task { manager.search("") } .onChange(of: search) { Task { await manager.search(search) } } Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 58
  107. func search(_ filter: String) async { if let _ =

    try? await store.requestAccess(for: .contacts) { let predictate = filter.isEmpty ? NSPredicate(value: true) : CNContact.predicateForContacts(matchingName: filter) contacts = try! store.unifiedContacts( matching: predictate, keysToFetch: descriptors as [CNKeyDescriptor] ) } } // Instead of NSPredicate true: CNContact.predicateForContactsInContainer(withIdentifier: store.defaultContainerIdentifier()) Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 59
  108. Uuuugly, at least pre iOS 18 Manu @StuFFmc Carrasco Molina

    • The Importance of Privacy on iOS, Do iOS ‘25 60
  109. Uuuugly, at least pre iOS 18 Since iOS 18, the

    user might put you in limited Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 60
  110. Uuuugly, at least pre iOS 18 Since iOS 18, the

    user might put you in limited If you take all the fields from all the people Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 60
  111. Uuuugly, at least pre iOS 18 Since iOS 18, the

    user might put you in limited If you take all the fields from all the people Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 60
  112. 62

  113. Proactive ⌨ / Autofill everywhere TextField("E-mail", text: $email) / TextEditor(text:

    $email) .textContentType(.emailAddress) .creditCardNumber .telephoneNumber .fullStreetAddress .addressCity Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 63
  114. SwiftUI & limited access Manu @StuFFmc Carrasco Molina • The

    Importance of Privacy on iOS, Do iOS ‘25 64
  115. SwiftUI & limited access ContactAccessButton Manu @StuFFmc Carrasco Molina •

    The Importance of Privacy on iOS, Do iOS ‘25 64
  116. SwiftUI & limited access ContactAccessButton .contactAccessPicker Modifier Works a bit

    wonky in my tests Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 64
  117. ContactAccessButton(queryString: search) { fetch($0) } List(contacts) { Detail($0) } .searchable(text:

    $search) .toolbar { Button("", systemImage: "person.crop.circle.badge.plus") { isPresented.toggle() }.contactAccessPicker(isPresented: $isPresented) { // ... } } private func fetch(_ ids: [String]) { let keys = [CNContactFormatter.descriptorForRequiredKeys(for: .fullName)] let fetchRequest = CNContactFetchRequest(keysToFetch: keys) fetchRequest.predicate = CNContact.predicateForContacts(withIdentifiers: ids) try! CNContactStore().enumerateContacts(with: fetchRequest) { contact, _ in contacts.append(contact) } } Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 66
  118. More limited, without SwiftUI let picker = CNContactPickerViewController() picker.delegate =

    sender.tag == 1 ? contactVC : self present(picker, animated: true) { } // self func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) // ContactVC() func contactPicker(_ picker: CNContactPickerViewController, didSelect contacts: [CNContact]) Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 67
  119. More limited, without SwiftUI let picker = CNContactPickerViewController() picker.delegate =

    sender.tag == 1 ? contactVC : self present(picker, animated: true) { } // self func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) // ContactVC() func contactPicker(_ picker: CNContactPickerViewController, didSelect contacts: [CNContact]) Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 67
  120. More limited, without SwiftUI let picker = CNContactPickerViewController() picker.delegate =

    sender.tag == 1 ? contactVC : self present(picker, animated: true) { } // self func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) // ContactVC() func contactPicker(_ picker: CNContactPickerViewController, didSelect contacts: [CNContact]) Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 67
  121. Same with Calendar let eventEditViewController = EKEventEditViewController() eventEditViewController.event = event

    eventEditViewController.eventStore = store eventEditViewController.editViewDelegate = self // Present the view controller present (eventEditViewController, animated: true) Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 68
  122. Crash Boom Bang This app has crashed... Info.plist must contain

    an NSContactsUsageDescription key with a string value explaining to the user how the app uses this data. Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 69
  123. Murica! Tim Cook, MSNBC, 2018 Manu @StuFFmc Carrasco Molina •

    The Importance of Privacy on iOS, Do iOS ‘25 70
  124. 71

  125. Sorry Tim, but no Privacy ain’t no Murica thing, buddy

    Manu @StuFFmc Carrasco Molina • The Importance of Privacy on iOS, Do iOS ‘25 72