Describing use of required reason API
Ensure your use of covered API is consistent with policy.
If you upload an app to App Store Connect that uses required reason API without describing the reason in its privacy manifest file, Apple sends you an email reminding you to add the reason to the app’s privacy manifest.
Starting May 1, 2024, apps that don’t describe their use of required reason API in their privacy manifest file aren’t accepted by App Store Connect.
Although the deadline of May 1 is past, we at least know why we'll be getting a rejection if we fail to provide these details in a plist. Luckily, an open source tool to help us try our best gives us a nice ripgrep script that scans for the vague things we need to list out and include in a plist. https://github.com/Wooder/ios_17_required_reason_api_scanner
I think these are a good catch of the things we could list according to the documentation and the ripgrep wrapper that matches these apis
fileModificationDate
fstat
lstat
mach_absolute_time
NSFileCreationDate
NSFileCreationDate
NSFileSystemSize
NSUserDefaults
stat
systemUptime
Output is clearer in your own terminal highlighting the usages we should list
```sh
$ sh ripgrep_required_reason_api_text_scanner.sh ../AAO-React-Native/
Searching for use of required reason API
See https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api
../AAO-React-Native/node_modules/@react-native-async-storage/async-storage/ios/RNCAsyncStorage.mm
256: return [attributes fileModificationDate];
../AAO-React-Native/node_modules/react-native-gesture-handler/ios/Handlers/RNLongPressHandler.m
43: previousTime = mach_absolute_time();
64: startTime = mach_absolute_time();
../AAO-React-Native/node_modules/react-native/React/Base/RCTBundleURLProvider.mm
57: [[NSUserDefaults standardUserDefaults] removeObjectForKey:key];
305: [[NSUserDefaults standardUserDefaults] setObject:object forKey:key];
306: [[NSUserDefaults standardUserDefaults] synchronize];
312: return [[NSUserDefaults standardUserDefaults] boolForKey:kRCTEnableDevKey];
317: return [[NSUserDefaults standardUserDefaults] boolForKey:kRCTEnableMinificationKey];
322: return [[NSUserDefaults standardUserDefaults] stringForKey:kRCTJsLocationKey];
327: NSString *packagerScheme = [[NSUserDefaults standardUserDefaults] stringForKey:kRCTPackagerSchemeKey];
368: [[NSUserDefaults standardUserDefaults] registerDefaults:[self defaults]];
../AAO-React-Native/node_modules/react-native/ReactAndroid/src/main/jni/third-party/libevent/event-config.h
67:/* Define to 1 if you have ERR_remove_thread_stat(). */
../AAO-React-Native/node_modules/react-native/React/Base/RCTJavaScriptLoader.mm
198: if (stat(scriptURL.path.UTF8String, &statInfo) != 0) {
../AAO-React-Native/node_modules/react-native/Libraries/Image/RCTImageLoader.mm
56: return (mach_absolute_time() * tb_info.numer) / tb_info.denom;
../AAO-React-Native/node_modules/react-native/Libraries/Settings/RCTSettingsManager.h
14:- (instancetype)initWithUserDefaults:(NSUserDefaults *)defaults NS_DESIGNATED_INITIALIZER;
../AAO-React-Native/node_modules/react-native/Libraries/Settings/RCTSettingsManager.mm
23: NSUserDefaults *_defaults;
37: return [self initWithUserDefaults:[NSUserDefaults standardUserDefaults]];
40:- (instancetype)initWithUserDefaults:(NSUserDefaults *)defaults
47: name:NSUserDefaultsDidChangeNotification
../AAO-React-Native/node_modules/react-native/React/Modules/RCTI18nUtil.m
50: NSNumber *value = [[NSUserDefaults standardUserDefaults] objectForKey:@"RCTI18nUtil_allowRTL"];
59: [[NSUserDefaults standardUserDefaults] setBool:rtlStatus forKey:@"RCTI18nUtil_allowRTL"];
60: [[NSUserDefaults standardUserDefaults] synchronize];
69: BOOL rtlStatus = [[NSUserDefaults standardUserDefaults] boolForKey:@"RCTI18nUtil_forceRTL"];
75: [[NSUserDefaults standardUserDefaults] setBool:rtlStatus forKey:@"RCTI18nUtil_forceRTL"];
76: [[NSUserDefaults standardUserDefaults] synchronize];
81: return [[NSUserDefaults standardUserDefaults] boolForKey:@"RCTI18nUtil_makeRTLFlipLeftAndRightStyles"];
86: [[NSUserDefaults standardUserDefaults] setBool:value forKey:@"RCTI18nUtil_makeRTLFlipLeftAndRightStyles"];
87: [[NSUserDefaults standardUserDefaults] synchronize];
../AAO-React-Native/node_modules/react-native/React/CoreModules/RCTDevSettings.h
17: * The default implementation persists settings using NSUserDefaults.
../AAO-React-Native/node_modules/react-native/React/CoreModules/RCTDevSettings.mm
64: NSUserDefaults *_userDefaults;
75: _userDefaults = [NSUserDefaults standardUserDefaults];
145: // Default behavior is to use NSUserDefaults with shake and hot loading enabled.
348: // This value is passed as a command-line argument, so fall back to reading from NSUserDefaults directly
349: NSString *executorOverride = [[NSUserDefaults standardUserDefaults] stringForKey:kRCTDevSettingExecutorOverrideClass];
../AAO-React-Native/node_modules/react-native-reanimated/apple/sensor/ReanimatedSensor.m
51: double currentTime = [[NSProcessInfo processInfo] systemUptime];
72: double currentTime = [[NSProcessInfo processInfo] systemUptime];
99: double currentTime = [[NSProcessInfo processInfo] systemUptime];
124: double currentTime = [[NSProcessInfo processInfo] systemUptime];
160: double currentTime = [[NSProcessInfo processInfo] systemUptime];
../AAO-React-Native/node_modules/react-native-device-info/ios/RNDeviceInfo/DeviceUID.m
44: - NSUserDefaults
67:/*! Persist UID to NSUserDefaults and Keychain
74:/*! Persist UID to NSUserDefaults and Keychain, if not yet saved
165:#pragma mark - NSUserDefaults methods
168: [[NSUserDefaults standardUserDefaults] setObject:value forKey:key];
169: return [[NSUserDefaults standardUserDefaults] synchronize];
173: return [[NSUserDefaults standardUserDefaults] objectForKey:key];
../AAO-React-Native/node_modules/react-native-device-info/ios/RNDeviceInfo/RNDeviceInfo.m
513: NSNumber *fileSystemSizeInBytes = [storage objectForKey: NSFileSystemSize];
532: NSNumber *freeFileSystemSizeInBytes = [storage objectForKey: NSFileSystemFreeSize];
876: NSDate *installDate = [[[NSFileManager defaultManager] attributesOfItemAtPath:urlToDocumentsFolder.path error:&error] objectForKey:NSFileCreationDate];
../AAO-React-Native/ios/Pods/FlipperKit/iOS/Plugins/FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.m
18:@property(nonatomic, strong) NSUserDefaults* standardUserDefaults;
19:@property(nonatomic, strong) NSUserDefaults* appSuiteUserDefaults;
28: _standardUserDefaults = [NSUserDefaults standardUserDefaults];
32: class:[NSUserDefaults class]
40: isKindOfClass:[NSUserDefaults
56: [[NSUserDefaults alloc] initWithSuiteName:_suiteName];
78: NSUserDefaults* sharedPreferences =
88: NSUserDefaults* sharedPreferences =
106:- (NSUserDefaults*)sharedPreferencesForParams:(NSDictionary*)params {
119:- (void)userDefaults:(NSUserDefaults*)userDefaults
../AAO-React-Native/ios/Pods/FlipperKit/iOS/Plugins/FlipperKitNetworkPlugin/SKIOSNetworkPlugin/FLEXNetworkLib/FLEXNetworkRecorder.mm
43: NSUInteger responseCacheLimit = [[[NSUserDefaults standardUserDefaults]
86: [[NSUserDefaults standardUserDefaults]
../AAO-React-Native/ios/Pods/FlipperKit/iOS/FlipperKit/SKEnvironmentVariables.m
57: value = [[NSUserDefaults standardUserDefaults]
68: value = [[NSUserDefaults standardUserDefaults]
../AAO-React-Native/ios/Pods/Sentry/Sources/Sentry/SentryFileManager.m
201: if (!dict || !dict[NSFileCreationDate]) {
202: SENTRY_LOG_WARN(@"Could not get NSFileCreationDate from %@", fullPath);
206: NSTimeInterval age = now - [dict[NSFileCreationDate] timeIntervalSince1970];
../AAO-React-Native/ios/Pods/Sentry/Sources/Sentry/SentryTime.mm
24: return mach_absolute_time();
../AAO-React-Native/ios/Pods/Sentry/Sources/Sentry/SentryCrashExceptionApplication.m
11: [[NSUserDefaults standardUserDefaults]
../AAO-React-Native/ios/Pods/Sentry/Sources/Sentry/include/SentryAppStateManager.h
29: * @c NSProcesInfo.systemUptime . @c NSProcesInfo.systemUptime returns the amount of time the system
../AAO-React-Native/ios/Pods/Sentry/Sources/SentryCrash/Recording/Monitors/SentryCrashMonitor_System.m
498: error:nil] objectForKey:NSFileSystemSize];
507: error:nil] objectForKey:NSFileSystemFreeSize];
../AAO-React-Native/ios/Pods/Flipper-Folly/folly/portability/SysStat.h
48:int lstat(const char* path, struct stat* st);
../AAO-React-Native/ios/Pods/Flipper-Folly/folly/FileUtil.h
141: if (fstat(fd, &buf) == -1) {
../AAO-React-Native/ios/Pods/RCT-Folly/folly/portability/SysStat.h
48:int lstat(const char* path, struct stat* st);
../AAO-React-Native/ios/Pods/RCT-Folly/folly/FileUtil.h
141: if (fstat(fd, &buf) == -1) {
```
Apple has given us a vague thing to abide by. We will try our best here https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api
Although the deadline of May 1 is past, we at least know why we'll be getting a rejection if we fail to provide these details in a plist. Luckily, an open source tool to help us try our best gives us a nice ripgrep script that scans for the vague things we need to list out and include in a plist. https://github.com/Wooder/ios_17_required_reason_api_scanner
I think these are a good catch of the things we could list according to the documentation and the ripgrep wrapper that matches these apis
Output is clearer in your own terminal highlighting the usages we should list
```sh $ sh ripgrep_required_reason_api_text_scanner.sh ../AAO-React-Native/ Searching for use of required reason API See https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api ../AAO-React-Native/node_modules/@react-native-async-storage/async-storage/ios/RNCAsyncStorage.mm 256: return [attributes fileModificationDate]; ../AAO-React-Native/node_modules/react-native-gesture-handler/ios/Handlers/RNLongPressHandler.m 43: previousTime = mach_absolute_time(); 64: startTime = mach_absolute_time(); ../AAO-React-Native/node_modules/react-native/React/Base/RCTBundleURLProvider.mm 57: [[NSUserDefaults standardUserDefaults] removeObjectForKey:key]; 305: [[NSUserDefaults standardUserDefaults] setObject:object forKey:key]; 306: [[NSUserDefaults standardUserDefaults] synchronize]; 312: return [[NSUserDefaults standardUserDefaults] boolForKey:kRCTEnableDevKey]; 317: return [[NSUserDefaults standardUserDefaults] boolForKey:kRCTEnableMinificationKey]; 322: return [[NSUserDefaults standardUserDefaults] stringForKey:kRCTJsLocationKey]; 327: NSString *packagerScheme = [[NSUserDefaults standardUserDefaults] stringForKey:kRCTPackagerSchemeKey]; 368: [[NSUserDefaults standardUserDefaults] registerDefaults:[self defaults]]; ../AAO-React-Native/node_modules/react-native/ReactAndroid/src/main/jni/third-party/libevent/event-config.h 67:/* Define to 1 if you have ERR_remove_thread_stat(). */ ../AAO-React-Native/node_modules/react-native/React/Base/RCTJavaScriptLoader.mm 198: if (stat(scriptURL.path.UTF8String, &statInfo) != 0) { ../AAO-React-Native/node_modules/react-native/Libraries/Image/RCTImageLoader.mm 56: return (mach_absolute_time() * tb_info.numer) / tb_info.denom; ../AAO-React-Native/node_modules/react-native/Libraries/Settings/RCTSettingsManager.h 14:- (instancetype)initWithUserDefaults:(NSUserDefaults *)defaults NS_DESIGNATED_INITIALIZER; ../AAO-React-Native/node_modules/react-native/Libraries/Settings/RCTSettingsManager.mm 23: NSUserDefaults *_defaults; 37: return [self initWithUserDefaults:[NSUserDefaults standardUserDefaults]]; 40:- (instancetype)initWithUserDefaults:(NSUserDefaults *)defaults 47: name:NSUserDefaultsDidChangeNotification ../AAO-React-Native/node_modules/react-native/React/Modules/RCTI18nUtil.m 50: NSNumber *value = [[NSUserDefaults standardUserDefaults] objectForKey:@"RCTI18nUtil_allowRTL"]; 59: [[NSUserDefaults standardUserDefaults] setBool:rtlStatus forKey:@"RCTI18nUtil_allowRTL"]; 60: [[NSUserDefaults standardUserDefaults] synchronize]; 69: BOOL rtlStatus = [[NSUserDefaults standardUserDefaults] boolForKey:@"RCTI18nUtil_forceRTL"]; 75: [[NSUserDefaults standardUserDefaults] setBool:rtlStatus forKey:@"RCTI18nUtil_forceRTL"]; 76: [[NSUserDefaults standardUserDefaults] synchronize]; 81: return [[NSUserDefaults standardUserDefaults] boolForKey:@"RCTI18nUtil_makeRTLFlipLeftAndRightStyles"]; 86: [[NSUserDefaults standardUserDefaults] setBool:value forKey:@"RCTI18nUtil_makeRTLFlipLeftAndRightStyles"]; 87: [[NSUserDefaults standardUserDefaults] synchronize]; ../AAO-React-Native/node_modules/react-native/React/CoreModules/RCTDevSettings.h 17: * The default implementation persists settings using NSUserDefaults. ../AAO-React-Native/node_modules/react-native/React/CoreModules/RCTDevSettings.mm 64: NSUserDefaults *_userDefaults; 75: _userDefaults = [NSUserDefaults standardUserDefaults]; 145: // Default behavior is to use NSUserDefaults with shake and hot loading enabled. 348: // This value is passed as a command-line argument, so fall back to reading from NSUserDefaults directly 349: NSString *executorOverride = [[NSUserDefaults standardUserDefaults] stringForKey:kRCTDevSettingExecutorOverrideClass]; ../AAO-React-Native/node_modules/react-native-reanimated/apple/sensor/ReanimatedSensor.m 51: double currentTime = [[NSProcessInfo processInfo] systemUptime]; 72: double currentTime = [[NSProcessInfo processInfo] systemUptime]; 99: double currentTime = [[NSProcessInfo processInfo] systemUptime]; 124: double currentTime = [[NSProcessInfo processInfo] systemUptime]; 160: double currentTime = [[NSProcessInfo processInfo] systemUptime]; ../AAO-React-Native/node_modules/react-native-device-info/ios/RNDeviceInfo/DeviceUID.m 44: - NSUserDefaults 67:/*! Persist UID to NSUserDefaults and Keychain 74:/*! Persist UID to NSUserDefaults and Keychain, if not yet saved 165:#pragma mark - NSUserDefaults methods 168: [[NSUserDefaults standardUserDefaults] setObject:value forKey:key]; 169: return [[NSUserDefaults standardUserDefaults] synchronize]; 173: return [[NSUserDefaults standardUserDefaults] objectForKey:key]; ../AAO-React-Native/node_modules/react-native-device-info/ios/RNDeviceInfo/RNDeviceInfo.m 513: NSNumber *fileSystemSizeInBytes = [storage objectForKey: NSFileSystemSize]; 532: NSNumber *freeFileSystemSizeInBytes = [storage objectForKey: NSFileSystemFreeSize]; 876: NSDate *installDate = [[[NSFileManager defaultManager] attributesOfItemAtPath:urlToDocumentsFolder.path error:&error] objectForKey:NSFileCreationDate]; ../AAO-React-Native/ios/Pods/FlipperKit/iOS/Plugins/FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.m 18:@property(nonatomic, strong) NSUserDefaults* standardUserDefaults; 19:@property(nonatomic, strong) NSUserDefaults* appSuiteUserDefaults; 28: _standardUserDefaults = [NSUserDefaults standardUserDefaults]; 32: class:[NSUserDefaults class] 40: isKindOfClass:[NSUserDefaults 56: [[NSUserDefaults alloc] initWithSuiteName:_suiteName]; 78: NSUserDefaults* sharedPreferences = 88: NSUserDefaults* sharedPreferences = 106:- (NSUserDefaults*)sharedPreferencesForParams:(NSDictionary*)params { 119:- (void)userDefaults:(NSUserDefaults*)userDefaults ../AAO-React-Native/ios/Pods/FlipperKit/iOS/Plugins/FlipperKitNetworkPlugin/SKIOSNetworkPlugin/FLEXNetworkLib/FLEXNetworkRecorder.mm 43: NSUInteger responseCacheLimit = [[[NSUserDefaults standardUserDefaults] 86: [[NSUserDefaults standardUserDefaults] ../AAO-React-Native/ios/Pods/FlipperKit/iOS/FlipperKit/SKEnvironmentVariables.m 57: value = [[NSUserDefaults standardUserDefaults] 68: value = [[NSUserDefaults standardUserDefaults] ../AAO-React-Native/ios/Pods/Sentry/Sources/Sentry/SentryFileManager.m 201: if (!dict || !dict[NSFileCreationDate]) { 202: SENTRY_LOG_WARN(@"Could not get NSFileCreationDate from %@", fullPath); 206: NSTimeInterval age = now - [dict[NSFileCreationDate] timeIntervalSince1970]; ../AAO-React-Native/ios/Pods/Sentry/Sources/Sentry/SentryTime.mm 24: return mach_absolute_time(); ../AAO-React-Native/ios/Pods/Sentry/Sources/Sentry/SentryCrashExceptionApplication.m 11: [[NSUserDefaults standardUserDefaults] ../AAO-React-Native/ios/Pods/Sentry/Sources/Sentry/include/SentryAppStateManager.h 29: * @c NSProcesInfo.systemUptime . @c NSProcesInfo.systemUptime returns the amount of time the system ../AAO-React-Native/ios/Pods/Sentry/Sources/SentryCrash/Recording/Monitors/SentryCrashMonitor_System.m 498: error:nil] objectForKey:NSFileSystemSize]; 507: error:nil] objectForKey:NSFileSystemFreeSize]; ../AAO-React-Native/ios/Pods/Flipper-Folly/folly/portability/SysStat.h 48:int lstat(const char* path, struct stat* st); ../AAO-React-Native/ios/Pods/Flipper-Folly/folly/FileUtil.h 141: if (fstat(fd, &buf) == -1) { ../AAO-React-Native/ios/Pods/RCT-Folly/folly/portability/SysStat.h 48:int lstat(const char* path, struct stat* st); ../AAO-React-Native/ios/Pods/RCT-Folly/folly/FileUtil.h 141: if (fstat(fd, &buf) == -1) { ```