├── .gitignore ├── DemoSymbols ├── DemoSymbols.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── DemoSymbols │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json │ ├── DemoSymbols-Bridging-Header.h │ ├── DemoSymbolsApp.swift │ ├── ObjcUtils.h │ ├── ObjcUtils.m │ └── Preview Content │ └── Preview Assets.xcassets │ └── Contents.json ├── README.md ├── required_reason_api_binary_scanner.sh └── required_reason_api_text_scanner.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | xcuserdata/ 3 | -------------------------------------------------------------------------------- /DemoSymbols/DemoSymbols.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 56; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | BBB4044F2B33AE0900461D9F /* DemoSymbolsApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBB4044E2B33AE0900461D9F /* DemoSymbolsApp.swift */; }; 11 | BBB404532B33AE0B00461D9F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BBB404522B33AE0B00461D9F /* Assets.xcassets */; }; 12 | BBB404562B33AE0B00461D9F /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BBB404552B33AE0B00461D9F /* Preview Assets.xcassets */; }; 13 | BBB4047A2B34AC2F00461D9F /* ObjcUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = BBB404792B34AC2F00461D9F /* ObjcUtils.m */; }; 14 | /* End PBXBuildFile section */ 15 | 16 | /* Begin PBXFileReference section */ 17 | BBB4044B2B33AE0900461D9F /* DemoSymbols.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DemoSymbols.app; sourceTree = BUILT_PRODUCTS_DIR; }; 18 | BBB4044E2B33AE0900461D9F /* DemoSymbolsApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoSymbolsApp.swift; sourceTree = ""; }; 19 | BBB404522B33AE0B00461D9F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 20 | BBB404552B33AE0B00461D9F /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 21 | BBB404782B34AC2F00461D9F /* DemoSymbols-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "DemoSymbols-Bridging-Header.h"; sourceTree = ""; }; 22 | BBB404792B34AC2F00461D9F /* ObjcUtils.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ObjcUtils.m; sourceTree = ""; }; 23 | BBB4047B2B34AC8F00461D9F /* ObjcUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ObjcUtils.h; sourceTree = ""; }; 24 | /* End PBXFileReference section */ 25 | 26 | /* Begin PBXFrameworksBuildPhase section */ 27 | BBB404482B33AE0900461D9F /* Frameworks */ = { 28 | isa = PBXFrameworksBuildPhase; 29 | buildActionMask = 2147483647; 30 | files = ( 31 | ); 32 | runOnlyForDeploymentPostprocessing = 0; 33 | }; 34 | /* End PBXFrameworksBuildPhase section */ 35 | 36 | /* Begin PBXGroup section */ 37 | BBB404422B33AE0900461D9F = { 38 | isa = PBXGroup; 39 | children = ( 40 | BBB4044D2B33AE0900461D9F /* DemoSymbols */, 41 | BBB4044C2B33AE0900461D9F /* Products */, 42 | ); 43 | sourceTree = ""; 44 | }; 45 | BBB4044C2B33AE0900461D9F /* Products */ = { 46 | isa = PBXGroup; 47 | children = ( 48 | BBB4044B2B33AE0900461D9F /* DemoSymbols.app */, 49 | ); 50 | name = Products; 51 | sourceTree = ""; 52 | }; 53 | BBB4044D2B33AE0900461D9F /* DemoSymbols */ = { 54 | isa = PBXGroup; 55 | children = ( 56 | BBB4044E2B33AE0900461D9F /* DemoSymbolsApp.swift */, 57 | BBB404792B34AC2F00461D9F /* ObjcUtils.m */, 58 | BBB4047B2B34AC8F00461D9F /* ObjcUtils.h */, 59 | BBB404522B33AE0B00461D9F /* Assets.xcassets */, 60 | BBB404542B33AE0B00461D9F /* Preview Content */, 61 | BBB404782B34AC2F00461D9F /* DemoSymbols-Bridging-Header.h */, 62 | ); 63 | path = DemoSymbols; 64 | sourceTree = ""; 65 | }; 66 | BBB404542B33AE0B00461D9F /* Preview Content */ = { 67 | isa = PBXGroup; 68 | children = ( 69 | BBB404552B33AE0B00461D9F /* Preview Assets.xcassets */, 70 | ); 71 | path = "Preview Content"; 72 | sourceTree = ""; 73 | }; 74 | /* End PBXGroup section */ 75 | 76 | /* Begin PBXNativeTarget section */ 77 | BBB4044A2B33AE0900461D9F /* DemoSymbols */ = { 78 | isa = PBXNativeTarget; 79 | buildConfigurationList = BBB4046F2B33AE0B00461D9F /* Build configuration list for PBXNativeTarget "DemoSymbols" */; 80 | buildPhases = ( 81 | BBB404472B33AE0900461D9F /* Sources */, 82 | BBB404482B33AE0900461D9F /* Frameworks */, 83 | BBB404492B33AE0900461D9F /* Resources */, 84 | ); 85 | buildRules = ( 86 | ); 87 | dependencies = ( 88 | ); 89 | name = DemoSymbols; 90 | productName = DemoSymbols; 91 | productReference = BBB4044B2B33AE0900461D9F /* DemoSymbols.app */; 92 | productType = "com.apple.product-type.application"; 93 | }; 94 | /* End PBXNativeTarget section */ 95 | 96 | /* Begin PBXProject section */ 97 | BBB404432B33AE0900461D9F /* Project object */ = { 98 | isa = PBXProject; 99 | attributes = { 100 | BuildIndependentTargetsInParallel = 1; 101 | LastSwiftUpdateCheck = 1420; 102 | LastUpgradeCheck = 1420; 103 | TargetAttributes = { 104 | BBB4044A2B33AE0900461D9F = { 105 | CreatedOnToolsVersion = 14.2; 106 | LastSwiftMigration = 1420; 107 | }; 108 | }; 109 | }; 110 | buildConfigurationList = BBB404462B33AE0900461D9F /* Build configuration list for PBXProject "DemoSymbols" */; 111 | compatibilityVersion = "Xcode 14.0"; 112 | developmentRegion = en; 113 | hasScannedForEncodings = 0; 114 | knownRegions = ( 115 | en, 116 | Base, 117 | ); 118 | mainGroup = BBB404422B33AE0900461D9F; 119 | productRefGroup = BBB4044C2B33AE0900461D9F /* Products */; 120 | projectDirPath = ""; 121 | projectRoot = ""; 122 | targets = ( 123 | BBB4044A2B33AE0900461D9F /* DemoSymbols */, 124 | ); 125 | }; 126 | /* End PBXProject section */ 127 | 128 | /* Begin PBXResourcesBuildPhase section */ 129 | BBB404492B33AE0900461D9F /* Resources */ = { 130 | isa = PBXResourcesBuildPhase; 131 | buildActionMask = 2147483647; 132 | files = ( 133 | BBB404562B33AE0B00461D9F /* Preview Assets.xcassets in Resources */, 134 | BBB404532B33AE0B00461D9F /* Assets.xcassets in Resources */, 135 | ); 136 | runOnlyForDeploymentPostprocessing = 0; 137 | }; 138 | /* End PBXResourcesBuildPhase section */ 139 | 140 | /* Begin PBXSourcesBuildPhase section */ 141 | BBB404472B33AE0900461D9F /* Sources */ = { 142 | isa = PBXSourcesBuildPhase; 143 | buildActionMask = 2147483647; 144 | files = ( 145 | BBB4047A2B34AC2F00461D9F /* ObjcUtils.m in Sources */, 146 | BBB4044F2B33AE0900461D9F /* DemoSymbolsApp.swift in Sources */, 147 | ); 148 | runOnlyForDeploymentPostprocessing = 0; 149 | }; 150 | /* End PBXSourcesBuildPhase section */ 151 | 152 | /* Begin XCBuildConfiguration section */ 153 | BBB4046D2B33AE0B00461D9F /* Debug */ = { 154 | isa = XCBuildConfiguration; 155 | buildSettings = { 156 | ALWAYS_SEARCH_USER_PATHS = NO; 157 | CLANG_ANALYZER_NONNULL = YES; 158 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 159 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 160 | CLANG_ENABLE_MODULES = YES; 161 | CLANG_ENABLE_OBJC_ARC = YES; 162 | CLANG_ENABLE_OBJC_WEAK = YES; 163 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 164 | CLANG_WARN_BOOL_CONVERSION = YES; 165 | CLANG_WARN_COMMA = YES; 166 | CLANG_WARN_CONSTANT_CONVERSION = YES; 167 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 168 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 169 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 170 | CLANG_WARN_EMPTY_BODY = YES; 171 | CLANG_WARN_ENUM_CONVERSION = YES; 172 | CLANG_WARN_INFINITE_RECURSION = YES; 173 | CLANG_WARN_INT_CONVERSION = YES; 174 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 175 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 176 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 177 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 178 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 179 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 180 | CLANG_WARN_STRICT_PROTOTYPES = YES; 181 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 182 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 183 | CLANG_WARN_UNREACHABLE_CODE = YES; 184 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 185 | COPY_PHASE_STRIP = NO; 186 | DEBUG_INFORMATION_FORMAT = dwarf; 187 | ENABLE_STRICT_OBJC_MSGSEND = YES; 188 | ENABLE_TESTABILITY = YES; 189 | GCC_C_LANGUAGE_STANDARD = gnu11; 190 | GCC_DYNAMIC_NO_PIC = NO; 191 | GCC_NO_COMMON_BLOCKS = YES; 192 | GCC_OPTIMIZATION_LEVEL = 0; 193 | GCC_PREPROCESSOR_DEFINITIONS = ( 194 | "DEBUG=1", 195 | "$(inherited)", 196 | ); 197 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 198 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 199 | GCC_WARN_UNDECLARED_SELECTOR = YES; 200 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 201 | GCC_WARN_UNUSED_FUNCTION = YES; 202 | GCC_WARN_UNUSED_VARIABLE = YES; 203 | IPHONEOS_DEPLOYMENT_TARGET = 16.2; 204 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 205 | MTL_FAST_MATH = YES; 206 | ONLY_ACTIVE_ARCH = YES; 207 | SDKROOT = iphoneos; 208 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 209 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 210 | }; 211 | name = Debug; 212 | }; 213 | BBB4046E2B33AE0B00461D9F /* Release */ = { 214 | isa = XCBuildConfiguration; 215 | buildSettings = { 216 | ALWAYS_SEARCH_USER_PATHS = NO; 217 | CLANG_ANALYZER_NONNULL = YES; 218 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 219 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 220 | CLANG_ENABLE_MODULES = YES; 221 | CLANG_ENABLE_OBJC_ARC = YES; 222 | CLANG_ENABLE_OBJC_WEAK = YES; 223 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 224 | CLANG_WARN_BOOL_CONVERSION = YES; 225 | CLANG_WARN_COMMA = YES; 226 | CLANG_WARN_CONSTANT_CONVERSION = YES; 227 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 228 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 229 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 230 | CLANG_WARN_EMPTY_BODY = YES; 231 | CLANG_WARN_ENUM_CONVERSION = YES; 232 | CLANG_WARN_INFINITE_RECURSION = YES; 233 | CLANG_WARN_INT_CONVERSION = YES; 234 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 235 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 236 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 237 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 238 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 239 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 240 | CLANG_WARN_STRICT_PROTOTYPES = YES; 241 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 242 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 243 | CLANG_WARN_UNREACHABLE_CODE = YES; 244 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 245 | COPY_PHASE_STRIP = NO; 246 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 247 | ENABLE_NS_ASSERTIONS = NO; 248 | ENABLE_STRICT_OBJC_MSGSEND = YES; 249 | GCC_C_LANGUAGE_STANDARD = gnu11; 250 | GCC_NO_COMMON_BLOCKS = YES; 251 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 252 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 253 | GCC_WARN_UNDECLARED_SELECTOR = YES; 254 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 255 | GCC_WARN_UNUSED_FUNCTION = YES; 256 | GCC_WARN_UNUSED_VARIABLE = YES; 257 | IPHONEOS_DEPLOYMENT_TARGET = 16.2; 258 | MTL_ENABLE_DEBUG_INFO = NO; 259 | MTL_FAST_MATH = YES; 260 | SDKROOT = iphoneos; 261 | SWIFT_COMPILATION_MODE = wholemodule; 262 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 263 | VALIDATE_PRODUCT = YES; 264 | }; 265 | name = Release; 266 | }; 267 | BBB404702B33AE0B00461D9F /* Debug */ = { 268 | isa = XCBuildConfiguration; 269 | buildSettings = { 270 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 271 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 272 | CLANG_ENABLE_MODULES = YES; 273 | CODE_SIGN_STYLE = Automatic; 274 | CURRENT_PROJECT_VERSION = 1; 275 | DEVELOPMENT_ASSET_PATHS = "\"DemoSymbols/Preview Content\""; 276 | DEVELOPMENT_TEAM = 9F3T5CPKWG; 277 | ENABLE_PREVIEWS = YES; 278 | GENERATE_INFOPLIST_FILE = YES; 279 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 280 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 281 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 282 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 283 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 284 | LD_RUNPATH_SEARCH_PATHS = ( 285 | "$(inherited)", 286 | "@executable_path/Frameworks", 287 | ); 288 | MARKETING_VERSION = 1.0; 289 | PRODUCT_BUNDLE_IDENTIFIER = com.omarzl.DemoSymbols; 290 | PRODUCT_NAME = "$(TARGET_NAME)"; 291 | SWIFT_EMIT_LOC_STRINGS = YES; 292 | SWIFT_OBJC_BRIDGING_HEADER = "DemoSymbols/DemoSymbols-Bridging-Header.h"; 293 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 294 | SWIFT_VERSION = 5.0; 295 | TARGETED_DEVICE_FAMILY = "1,2"; 296 | }; 297 | name = Debug; 298 | }; 299 | BBB404712B33AE0B00461D9F /* Release */ = { 300 | isa = XCBuildConfiguration; 301 | buildSettings = { 302 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 303 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 304 | CLANG_ENABLE_MODULES = YES; 305 | CODE_SIGN_STYLE = Automatic; 306 | CURRENT_PROJECT_VERSION = 1; 307 | DEVELOPMENT_ASSET_PATHS = "\"DemoSymbols/Preview Content\""; 308 | DEVELOPMENT_TEAM = 9F3T5CPKWG; 309 | ENABLE_PREVIEWS = YES; 310 | GENERATE_INFOPLIST_FILE = YES; 311 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 312 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 313 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 314 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 315 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 316 | LD_RUNPATH_SEARCH_PATHS = ( 317 | "$(inherited)", 318 | "@executable_path/Frameworks", 319 | ); 320 | MARKETING_VERSION = 1.0; 321 | PRODUCT_BUNDLE_IDENTIFIER = com.omarzl.DemoSymbols; 322 | PRODUCT_NAME = "$(TARGET_NAME)"; 323 | SWIFT_EMIT_LOC_STRINGS = YES; 324 | SWIFT_OBJC_BRIDGING_HEADER = "DemoSymbols/DemoSymbols-Bridging-Header.h"; 325 | SWIFT_VERSION = 5.0; 326 | TARGETED_DEVICE_FAMILY = "1,2"; 327 | }; 328 | name = Release; 329 | }; 330 | /* End XCBuildConfiguration section */ 331 | 332 | /* Begin XCConfigurationList section */ 333 | BBB404462B33AE0900461D9F /* Build configuration list for PBXProject "DemoSymbols" */ = { 334 | isa = XCConfigurationList; 335 | buildConfigurations = ( 336 | BBB4046D2B33AE0B00461D9F /* Debug */, 337 | BBB4046E2B33AE0B00461D9F /* Release */, 338 | ); 339 | defaultConfigurationIsVisible = 0; 340 | defaultConfigurationName = Release; 341 | }; 342 | BBB4046F2B33AE0B00461D9F /* Build configuration list for PBXNativeTarget "DemoSymbols" */ = { 343 | isa = XCConfigurationList; 344 | buildConfigurations = ( 345 | BBB404702B33AE0B00461D9F /* Debug */, 346 | BBB404712B33AE0B00461D9F /* Release */, 347 | ); 348 | defaultConfigurationIsVisible = 0; 349 | defaultConfigurationName = Release; 350 | }; 351 | /* End XCConfigurationList section */ 352 | }; 353 | rootObject = BBB404432B33AE0900461D9F /* Project object */; 354 | } 355 | -------------------------------------------------------------------------------- /DemoSymbols/DemoSymbols.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DemoSymbols/DemoSymbols.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /DemoSymbols/DemoSymbols/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "platform" : "ios", 6 | "size" : "1024x1024" 7 | } 8 | ], 9 | "info" : { 10 | "author" : "xcode", 11 | "version" : 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /DemoSymbols/DemoSymbols/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /DemoSymbols/DemoSymbols/DemoSymbols-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | #import "ObjcUtils.h" 6 | -------------------------------------------------------------------------------- /DemoSymbols/DemoSymbols/DemoSymbolsApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DemoSymbolsApp.swift 3 | // DemoSymbols 4 | // 5 | // Created by Omar Zuñiga on 20/12/23. 6 | // 7 | 8 | import UIKit 9 | import SwiftUI 10 | 11 | @main 12 | struct DemoSymbolsApp: App { 13 | var body: some Scene { 14 | WindowGroup { 15 | Color.clear 16 | } 17 | } 18 | 19 | init() { 20 | fgetattrlist(0, nil, nil, 0, 0) 21 | _ = try? FileManager.default.attributesOfItem(atPath: "").first(where: { 22 | $0.key == .modificationDate || 23 | $0.key == .creationDate || 24 | $0.key == .systemFreeSize || 25 | $0.key == .systemSize 26 | }) 27 | fstat(0, nil) 28 | fstatat(0, nil, nil, 0) 29 | fstatfs(0, nil) 30 | fstatvfs(0, nil) 31 | getattrlist(nil, nil, nil, 0, 0) 32 | getattrlistat(0, nil, nil, nil, 0, 0) 33 | getattrlistbulk(0, nil, nil, 0, 0) 34 | lstat(nil, nil) 35 | mach_absolute_time() 36 | 37 | _ = URLResourceKey.contentModificationDateKey 38 | _ = URLResourceKey.creationDateKey 39 | _ = URLResourceKey.volumeAvailableCapacityForImportantUsageKey 40 | _ = URLResourceKey.volumeAvailableCapacityForOpportunisticUsageKey 41 | _ = URLResourceKey.volumeAvailableCapacityKey 42 | _ = URLResourceKey.volumeTotalCapacityKey 43 | UserDefaults.standard.object(forKey: "") 44 | _ = stat() 45 | statfs(nil, nil) 46 | statvfs(nil, nil) 47 | 48 | // Using Swift's `ProcessInfo.processInfo.systemUptime` & 49 | // `UITextInputMode.activeInputModes` wasn't showing the symbol with `nm` 50 | // so I force it with ObjC 51 | let utils = ObjcUtils() 52 | utils.uptime() 53 | utils.activeModes() 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /DemoSymbols/DemoSymbols/ObjcUtils.h: -------------------------------------------------------------------------------- 1 | // 2 | // ObjcUtils.h 3 | // DemoSymbols 4 | // 5 | // Created by Omar Zuñiga on 21/12/23. 6 | // 7 | 8 | #import 9 | 10 | @interface ObjcUtils: NSObject 11 | 12 | - (NSTimeInterval)uptime; 13 | - (NSArray*)activeModes; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /DemoSymbols/DemoSymbols/ObjcUtils.m: -------------------------------------------------------------------------------- 1 | // 2 | // ObjcUtils.m 3 | // DemoSymbols 4 | // 5 | // Created by Omar Zuñiga on 21/12/23. 6 | // 7 | 8 | #import "ObjcUtils.h" 9 | #include 10 | #include 11 | 12 | @implementation ObjcUtils 13 | 14 | - (NSTimeInterval)uptime { 15 | return [NSProcessInfo processInfo].systemUptime; 16 | } 17 | 18 | - (NSArray*)activeModes { 19 | return [UITextInputMode activeInputModes]; 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /DemoSymbols/DemoSymbols/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Scanners for possible use of "iOS required reason API". 2 | 3 | ## Text-based scanner 4 | 5 | The scan is very rudimentary and based on comparing strings, but should be very helpful for a first analysis. 6 | 7 | See https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api for details. 8 | 9 | Usage: 10 | 11 | `sh required_reason_api_text_scanner.sh {directory_name}` 12 | 13 | Example Output: 14 | 15 | `Found potentially required reason API usage 'UserDefaults' in './ViewController.swift' 16 | Line numbers: 28` 17 | 18 | See the following medium post for more details: https://jochen-holzer.medium.com/embrace-the-evolution-preparing-your-ios-app-for-the-required-reason-api-38f2d12bbce5?source=friends_link&sk=d146c22f3e18c6551231f4b55c934b05 19 | 20 | ## Binary-based scanner 21 | 22 | This scanner looks for symbols in the binaries in DerivedData folder using `nm`. 23 | 24 | It will find the `.app`, `.framework` and `.a` binaries. 25 | Keep in mind that the symbols found in the app (`.app`) will be duplicated from the ones found in the static libraries `.a` since they are statically linked. 26 | 27 | Usage: 28 | `sh required_reason_api_binary_scanner.sh {directory}` 29 | 30 | Example output: 31 | ``` 32 | sh required_reason_api_scanner_binary.sh \ 33 | ~/Library/Developer/Xcode/DerivedData/DemoSymbols-aymfeypsyhqwfuaieijkrqdeohcd/Build/Products/Debug-iphonesimulator 34 | 35 | > Analyzing binaries: ./DemoSymbols.app/DemoSymbols 36 | > --- 37 | > Used symbols in binary ./DemoSymbols.app/DemoSymbols: activeInputModes, fgetattrlist, fstat, fstatat, fstatfs, fstatvfs, getattrlist, getattrlistat, getattrlistbulk, lstat, mach_absolute_time, NSFileCreationDate, NSFileModificationDate, NSFileSystemFreeSize, NSFileSystemSize, NSURLContentModificationDateKey, NSURLCreationDateKey, NSURLVolumeAvailableCapacityForImportantUsageKey, NSURLVolumeAvailableCapacityForOpportunisticUsageKey, NSURLVolumeAvailableCapacityKey, NSURLVolumeTotalCapacityKey, NSUserDefaults, stat, statfs, statvfs, systemUptime 38 | ``` 39 | 40 | ## Example project 41 | 42 | In the directory `DemoSymbols` you will find a project that uses all the code that Apple asks for a required reason. 43 | 44 | It is used to test these scanners. 45 | -------------------------------------------------------------------------------- /required_reason_api_binary_scanner.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | symbols=( 6 | activeInputModes 7 | fgetattrlist 8 | fstat 9 | fstatat 10 | fstatfs 11 | fstatvfs 12 | getattrlist 13 | getattrlistat 14 | getattrlistbulk 15 | lstat 16 | mach_absolute_time 17 | NSFileCreationDate 18 | NSFileModificationDate 19 | NSFileSystemFreeSize 20 | NSFileSystemSize 21 | NSURLContentModificationDateKey 22 | NSURLCreationDateKey 23 | NSURLVolumeAvailableCapacityForImportantUsageKey 24 | NSURLVolumeAvailableCapacityForOpportunisticUsageKey 25 | NSURLVolumeAvailableCapacityKey 26 | NSURLVolumeTotalCapacityKey 27 | NSUserDefaults 28 | stat 29 | statfs 30 | statvfs 31 | systemUptime 32 | ) 33 | 34 | function join_by { 35 | local d=${1-} f=${2-} 36 | if shift 2; then 37 | printf %s "$f" "${@/#/$d}" 38 | fi 39 | } 40 | 41 | function search_binaries_with_directory { 42 | extension=$1 43 | for binary in $(find . -iname "*.$extension"); do 44 | name=$(basename $binary); 45 | binary_name=$(echo $name | sed "s/.$extension//"); 46 | binaries+=("$(dirname $binary)/${name}/${binary_name}") 47 | done 48 | } 49 | 50 | function search_binaries_with_filename { 51 | extension=$1 52 | for binary in $(find . -iname "*.$extension"); do 53 | binaries+=($binary) 54 | done 55 | } 56 | 57 | cd $1 58 | 59 | declare -a binaries 60 | 61 | # Adds the .app binary 62 | search_binaries_with_directory app 63 | # Adds the (dynamic/static) .framework binaries 64 | search_binaries_with_directory framework 65 | # Adds the static libs .a binaries 66 | search_binaries_with_filename a 67 | 68 | echo "Analyzing binaries: ${binaries[@]}" 69 | echo '---' 70 | 71 | for binary in "${binaries[@]}"; do 72 | if ! [ -f $binary ]; then 73 | echo "binary '$binary' doesn't exist" 74 | exit 1 75 | fi 76 | used_symbols=() 77 | for symbol in "${symbols[@]}"; do 78 | if nm "$binary" 2>/dev/null | xcrun swift-demangle | grep -E "$symbol$" >/dev/null; then 79 | used_symbols+=($symbol) 80 | fi 81 | done 82 | echo "Used symbols in binary $binary: $(join_by ', ' ${used_symbols[@]})" 83 | done 84 | -------------------------------------------------------------------------------- /required_reason_api_text_scanner.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Array of directories to exclude from the search 4 | excluded_dirs=() # e.g. ("Pods" "3rdparty") 5 | 6 | # Global variable for search strings that may indicate a use of "iOS required reason API" 7 | # taken from here: https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api 8 | search_string=(#"creationDate" 9 | ".modificationDate" 10 | ".fileModificationDate" 11 | ".contentModificationDateKey" 12 | "getattrlist(" 13 | "getattrlistbulk(" 14 | "fgetattrlist(" 15 | "stat.st_" # see https://developer.apple.com/documentation/kernel/stat 16 | "fstat(" 17 | "fstatat(" 18 | "lstat(" 19 | "getattrlistat(" 20 | "systemUptime" 21 | "mach_absolute_time()" 22 | "volumeAvailableCapacityKey" 23 | "volumeAvailableCapacityForImportantUsageKey" 24 | "volumeAvailableCapacityForOpportunisticUsageKey" 25 | "volumeTotalCapacityKey" 26 | "systemFreeSize" 27 | "systemSize" 28 | "statfs(" 29 | "statvfs(" 30 | "fstatfs(" 31 | "getattrlist(" 32 | "fgetattrlist(" 33 | "getattrlistat(" 34 | "activeInputModes" 35 | "UserDefaults" 36 | ) 37 | 38 | # Function to search for equired reason API strings in a Swift files 39 | search_in_swift_file() { 40 | local file="$1" 41 | 42 | # Loop through each search string 43 | for string in "${search_string[@]}"; do 44 | # Search for the string in the file and get the line numbers 45 | lines=$(grep -n "$string" "$file" | cut -d ":" -f 1) 46 | if [ -n "$lines" ]; then 47 | echo "Found potentially required reason API usage '$string' in '$file'" 48 | one_line_string=$(echo "$lines" | tr '\n' ' ') 49 | echo "Line numbers: $one_line_string" 50 | fi 51 | done 52 | } 53 | 54 | # Function to check if a directory is in the excluded list 55 | is_excluded_dir() { 56 | local dir_name="$1" 57 | for excluded_dir in "${excluded_dirs[@]}"; do 58 | if [ "$dir_name" == "$excluded_dir" ]; then 59 | return 0 60 | fi 61 | done 62 | return 1 63 | } 64 | 65 | 66 | # Function to traverse directories recursively and search for Swift files 67 | traverse_and_search() { 68 | local folder="$1" 69 | 70 | # Get the name of the current directory 71 | local dir_name=$(basename "$folder") 72 | 73 | # Check if the directory is in the excluded list 74 | if is_excluded_dir "$dir_name"; then 75 | return 76 | fi 77 | 78 | # Loop through each item in the folder 79 | for item in "$folder"/*; do 80 | if [ -d "$item" ]; then 81 | # If it's a directory, call the function recursively 82 | traverse_and_search "$item" 83 | elif [ -f "$item" ] && [[ "$item" == *.swift ]]; then 84 | # If it's a file with .swift extension, search for the strings 85 | search_in_swift_file "$item" 86 | fi 87 | done 88 | } 89 | 90 | # Check if a directory path is provided as an argument 91 | if [ -z "$1" ]; then 92 | echo "Usage: $0 " 93 | exit 1 94 | fi 95 | 96 | # Start the search 97 | echo "Searching for use of required reason API" 98 | echo "See https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api" 99 | 100 | traverse_and_search "$1" 101 | --------------------------------------------------------------------------------