react-native-device-secure-info 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/README.md +175 -0
  2. package/android/app/build.gradle +119 -0
  3. package/android/app/debug.keystore +0 -0
  4. package/android/app/proguard-rules.pro +10 -0
  5. package/android/app/src/debug/AndroidManifest.xml +9 -0
  6. package/android/app/src/main/AndroidManifest.xml +26 -0
  7. package/android/app/src/main/java/com/reactnativedevicesecureinfo/DeviceSecureInfoModule.kt +167 -0
  8. package/android/app/src/main/java/com/reactnativedevicesecureinfo/DeviceSecureInfoPackage.kt +22 -0
  9. package/android/app/src/main/java/com/reactnativedevicesecureinfo/DeviceSecureInfoTurboModule.kt +169 -0
  10. package/android/app/src/main/java/com/reactnativedevicesecureinfo/DeviceSecureInfoTurboPackage.kt +46 -0
  11. package/android/app/src/main/java/com/reactnativedevicesecureinfo/MainActivity.kt +22 -0
  12. package/android/app/src/main/java/com/reactnativedevicesecureinfo/MainApplication.kt +49 -0
  13. package/android/app/src/main/res/drawable/rn_edit_text_material.xml +37 -0
  14. package/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  15. package/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
  16. package/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  17. package/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
  18. package/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  19. package/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  20. package/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  21. package/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  22. package/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  23. package/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  24. package/android/app/src/main/res/values/strings.xml +3 -0
  25. package/android/app/src/main/res/values/styles.xml +9 -0
  26. package/android/build.gradle +21 -0
  27. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  28. package/android/gradle/wrapper/gradle-wrapper.properties +7 -0
  29. package/android/gradle.properties +39 -0
  30. package/android/gradlew +251 -0
  31. package/android/gradlew.bat +94 -0
  32. package/android/settings.gradle +6 -0
  33. package/ios/.xcode.env +11 -0
  34. package/ios/.xcode.env.local +1 -0
  35. package/ios/DeviceSecureInfoModule.h +7 -0
  36. package/ios/DeviceSecureInfoModule.m +217 -0
  37. package/ios/DeviceSecureInfoTurboModule.h +19 -0
  38. package/ios/DeviceSecureInfoTurboModule.mm +230 -0
  39. package/ios/Podfile +35 -0
  40. package/ios/ReactNativeDeviceSecureInfo/AppDelegate.swift +30 -0
  41. package/ios/ReactNativeDeviceSecureInfo/Images.xcassets/AppIcon.appiconset/Contents.json +53 -0
  42. package/ios/ReactNativeDeviceSecureInfo/Images.xcassets/Contents.json +6 -0
  43. package/ios/ReactNativeDeviceSecureInfo/Info.plist +52 -0
  44. package/ios/ReactNativeDeviceSecureInfo/LaunchScreen.storyboard +47 -0
  45. package/ios/ReactNativeDeviceSecureInfo/PrivacyInfo.xcprivacy +37 -0
  46. package/ios/ReactNativeDeviceSecureInfo-Bridging-Header.h +4 -0
  47. package/ios/ReactNativeDeviceSecureInfo.xcodeproj/project.pbxproj +504 -0
  48. package/ios/ReactNativeDeviceSecureInfo.xcodeproj/xcshareddata/xcschemes/ReactNativeDeviceSecureInfo.xcscheme +88 -0
  49. package/ios/ReactNativeDeviceSecureInfo.xcworkspace/contents.xcworkspacedata +10 -0
  50. package/ios/ReactNativeDeviceSecureInfo.xcworkspace/xcuserdata/dengbin.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  51. package/package.json +77 -0
  52. package/react-native-device-secure-info.podspec +20 -0
  53. package/react-native.config.js +13 -0
  54. package/src/NativeDeviceSecureInfo.ts +67 -0
  55. package/src/assets/image.png +0 -0
  56. package/src/index.ts +90 -0
@@ -0,0 +1,230 @@
1
+ // DeviceSecureInfoTurboModule.mm
2
+ // iOS 原生设备安全信息模块 - RN 新架构 TurboModule 版本
3
+ // 使用 .mm 扩展名(Objective-C++),新架构 TurboModule 需要 C++ 支持
4
+ // 包含设备基础信息、内存、CPU、电池信息
5
+
6
+ #import "DeviceSecureInfoTurboModule.h"
7
+ #import <UIKit/UIKit.h>
8
+ #import <CoreTelephony/CTTelephonyNetworkInfo.h>
9
+ #import <CoreTelephony/CTCarrier.h>
10
+ #import <sys/utsname.h>
11
+ #import <mach/mach.h>
12
+ #import <sys/sysctl.h>
13
+
14
+ // 新架构:Codegen 生成的头文件
15
+ // 名称来源于 package.json 中 codegenConfig.name = "DeviceSecureInfoSpec"
16
+ #ifdef RCT_NEW_ARCH_ENABLED
17
+ #import <DeviceSecureInfoSpec/DeviceSecureInfoSpec.h>
18
+ #endif
19
+
20
+ @implementation DeviceSecureInfoTurboModule
21
+
22
+ RCT_EXPORT_MODULE(DeviceSecureInfoModule);
23
+
24
+ + (BOOL)requiresMainQueueSetup {
25
+ return NO;
26
+ }
27
+
28
+ #pragma mark - 获取设备机型标识(如 iPhone14,2)
29
+ - (NSString *)getDeviceModel {
30
+ struct utsname systemInfo;
31
+ uname(&systemInfo);
32
+ return [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
33
+ }
34
+
35
+ #pragma mark - 获取运营商名称
36
+ - (NSString *)getCarrierName {
37
+ CTTelephonyNetworkInfo *networkInfo = [[CTTelephonyNetworkInfo alloc] init];
38
+
39
+ if (@available(iOS 12.0, *)) {
40
+ NSDictionary<NSString *, CTCarrier *> *carriers = networkInfo.serviceSubscriberCellularProviders;
41
+ for (CTCarrier *carrier in carriers.allValues) {
42
+ NSString *name = carrier.carrierName;
43
+ if (name && name.length > 0) {
44
+ return name;
45
+ }
46
+ }
47
+ } else {
48
+ CTCarrier *carrier = networkInfo.subscriberCellularProvider;
49
+ if (carrier.carrierName) {
50
+ return carrier.carrierName;
51
+ }
52
+ }
53
+
54
+ return @"";
55
+ }
56
+
57
+ #pragma mark - 获取总物理内存(字节)
58
+ - (long long)getTotalMemory {
59
+ return [NSProcessInfo processInfo].physicalMemory;
60
+ }
61
+
62
+ #pragma mark - 获取可用内存(字节)
63
+ - (long long)getAvailableMemory {
64
+ vm_statistics64_data_t vmStats;
65
+ mach_msg_type_number_t infoCount = HOST_VM_INFO64_COUNT;
66
+ kern_return_t kernReturn = host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info64_t)&vmStats, &infoCount);
67
+
68
+ if (kernReturn != KERN_SUCCESS) {
69
+ return -1;
70
+ }
71
+
72
+ long long freeMemory = (long long)(vmStats.free_count + vmStats.inactive_count) * vm_page_size;
73
+ return freeMemory;
74
+ }
75
+
76
+ #pragma mark - 获取 CPU 核心数
77
+ - (NSInteger)getCpuCores {
78
+ return [NSProcessInfo processInfo].activeProcessorCount;
79
+ }
80
+
81
+ #pragma mark - 获取 CPU 架构
82
+ - (NSString *)getCpuArchitecture {
83
+ #if defined(__arm64__)
84
+ return @"arm64";
85
+ #elif defined(__x86_64__)
86
+ return @"x86_64";
87
+ #elif defined(__arm__)
88
+ return @"arm";
89
+ #elif defined(__i386__)
90
+ return @"i386";
91
+ #else
92
+ return @"unknown";
93
+ #endif
94
+ }
95
+
96
+ #pragma mark - 获取 CPU 使用率(百分比)
97
+ - (double)getCpuUsagePercent {
98
+ kern_return_t kr;
99
+ mach_msg_type_number_t count;
100
+ host_cpu_load_info_data_t cpuLoadInfo;
101
+
102
+ count = HOST_CPU_LOAD_INFO_COUNT;
103
+ kr = host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, (host_info_t)&cpuLoadInfo, &count);
104
+
105
+ if (kr != KERN_SUCCESS) {
106
+ return -1.0;
107
+ }
108
+
109
+ unsigned long long totalTicks = 0;
110
+ for (int i = 0; i < CPU_STATE_MAX; i++) {
111
+ totalTicks += cpuLoadInfo.cpu_ticks[i];
112
+ }
113
+
114
+ unsigned long long idleTicks = cpuLoadInfo.cpu_ticks[CPU_STATE_IDLE];
115
+
116
+ if (totalTicks == 0) {
117
+ return -1.0;
118
+ }
119
+
120
+ double usagePercent = ((double)(totalTicks - idleTicks) / (double)totalTicks) * 100.0;
121
+ return usagePercent;
122
+ }
123
+
124
+ #pragma mark - 获取电池信息
125
+ - (NSDictionary *)getBatteryInfo {
126
+ UIDevice *device = [UIDevice currentDevice];
127
+ device.batteryMonitoringEnabled = YES;
128
+
129
+ float batteryLevelRaw = device.batteryLevel;
130
+ NSInteger batteryLevel = (batteryLevelRaw >= 0) ? (NSInteger)(batteryLevelRaw * 100) : -1;
131
+
132
+ UIDeviceBatteryState state = device.batteryState;
133
+ NSString *batteryState;
134
+ BOOL isCharging = NO;
135
+
136
+ switch (state) {
137
+ case UIDeviceBatteryStateCharging:
138
+ batteryState = @"charging";
139
+ isCharging = YES;
140
+ break;
141
+ case UIDeviceBatteryStateFull:
142
+ batteryState = @"full";
143
+ isCharging = YES;
144
+ break;
145
+ case UIDeviceBatteryStateUnplugged:
146
+ batteryState = @"discharging";
147
+ break;
148
+ default:
149
+ batteryState = @"unknown";
150
+ break;
151
+ }
152
+
153
+ return @{
154
+ @"batteryLevel": @(batteryLevel),
155
+ @"batteryState": batteryState,
156
+ @"isCharging": @(isCharging),
157
+ };
158
+ }
159
+
160
+ #pragma mark - 导出方法:获取设备信息(Promise 方式)
161
+ RCT_EXPORT_METHOD(getDeviceInfo:(RCTPromiseResolveBlock)resolve
162
+ reject:(RCTPromiseRejectBlock)reject) {
163
+ @try {
164
+ UIDevice *device = [UIDevice currentDevice];
165
+
166
+ // ---- 基础设备信息 ----
167
+ NSString *deviceName = device.name;
168
+ NSString *systemVersion = device.systemVersion;
169
+ NSString *brand = @"Apple";
170
+ NSString *manufacturer = @"Apple";
171
+ NSString *deviceId = device.identifierForVendor.UUIDString ?: @"unknown";
172
+ NSString *carrierName = [self getCarrierName];
173
+ NSString *deviceModel = [self getDeviceModel];
174
+
175
+ // ---- 内存信息 ----
176
+ long long totalMemory = [self getTotalMemory];
177
+ long long availableMemory = [self getAvailableMemory];
178
+ long long usedMemory = totalMemory - (availableMemory > 0 ? availableMemory : 0);
179
+ NSInteger memoryUsagePercent = (totalMemory > 0) ? (NSInteger)((double)usedMemory / (double)totalMemory * 100) : 0;
180
+
181
+ // ---- 电池信息 ----
182
+ NSDictionary *batteryInfo = [self getBatteryInfo];
183
+
184
+ NSMutableDictionary *deviceInfo = [NSMutableDictionary dictionaryWithDictionary:@{
185
+ // 基础信息
186
+ @"deviceName": deviceName ?: @"unknown",
187
+ @"systemVersion": systemVersion ?: @"unknown",
188
+ @"brand": brand,
189
+ @"manufacturer": manufacturer,
190
+ @"deviceId": deviceId,
191
+ @"carrierName": carrierName ?: @"",
192
+ @"sdkVersion": @(__IPHONE_OS_VERSION_MAX_ALLOWED / 10000),
193
+ @"deviceModel": deviceModel ?: @"unknown",
194
+ @"systemName": device.systemName ?: @"iOS",
195
+
196
+ // 内存信息
197
+ @"totalMemory": @(totalMemory),
198
+ @"availableMemory": @(availableMemory),
199
+ @"usedMemory": @(usedMemory),
200
+ @"memoryUsagePercent": @(memoryUsagePercent),
201
+
202
+ // CPU 信息
203
+ @"cpuArchitecture": [self getCpuArchitecture],
204
+ @"cpuCores": @([self getCpuCores]),
205
+ @"cpuUsagePercent": @([self getCpuUsagePercent]),
206
+
207
+ // 电池信息
208
+ @"batteryLevel": batteryInfo[@"batteryLevel"],
209
+ @"batteryState": batteryInfo[@"batteryState"],
210
+ @"isCharging": batteryInfo[@"isCharging"],
211
+ }];
212
+
213
+ resolve(deviceInfo);
214
+ } @catch (NSException *exception) {
215
+ reject(@"DEVICE_INFO_ERROR",
216
+ [NSString stringWithFormat:@"获取设备信息失败: %@", exception.reason],
217
+ nil);
218
+ }
219
+ }
220
+
221
+ // ======================== 新架构核心:C++ TurboModule 桥接 ========================
222
+ // 只在新架构下编译 getTurboModule 方法
223
+ #ifdef RCT_NEW_ARCH_ENABLED
224
+ - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
225
+ (const facebook::react::ObjCTurboModule::InitParams &)params {
226
+ return std::make_shared<facebook::react::NativeDeviceSecureInfoSpecJSI>(params);
227
+ }
228
+ #endif
229
+
230
+ @end
package/ios/Podfile ADDED
@@ -0,0 +1,35 @@
1
+ # Resolve react_native_pods.rb with node to allow for hoisting
2
+ require Pod::Executable.execute_command('node', ['-p',
3
+ 'require.resolve(
4
+ "react-native/scripts/react_native_pods.rb",
5
+ {paths: [process.argv[1]]},
6
+ )', __dir__]).strip
7
+
8
+ platform :ios, min_ios_version_supported
9
+ prepare_react_native_project!
10
+
11
+ linkage = ENV['USE_FRAMEWORKS']
12
+ if linkage != nil
13
+ Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green
14
+ use_frameworks! :linkage => linkage.to_sym
15
+ end
16
+
17
+ target 'ReactNativeDeviceSecureInfo' do
18
+ config = use_native_modules!
19
+
20
+ use_react_native!(
21
+ :path => config[:reactNativePath],
22
+ # An absolute path to your application root.
23
+ :app_path => "#{Pod::Config.instance.installation_root}/.."
24
+ )
25
+
26
+ post_install do |installer|
27
+ # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202
28
+ react_native_post_install(
29
+ installer,
30
+ config[:reactNativePath],
31
+ :mac_catalyst_enabled => false,
32
+ # :ccache_enabled => true
33
+ )
34
+ end
35
+ end
@@ -0,0 +1,30 @@
1
+ import UIKit
2
+ import React
3
+ import React_RCTAppDelegate
4
+ import ReactAppDependencyProvider
5
+
6
+ @main
7
+ class AppDelegate: RCTAppDelegate {
8
+ override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
9
+ self.moduleName = "ReactNativeDeviceSecureInfo"
10
+ self.dependencyProvider = RCTAppDependencyProvider()
11
+
12
+ // You can add your custom initial props in the dictionary below.
13
+ // They will be passed down to the ViewController used by React Native.
14
+ self.initialProps = [:]
15
+
16
+ return super.application(application, didFinishLaunchingWithOptions: launchOptions)
17
+ }
18
+
19
+ override func sourceURL(for bridge: RCTBridge) -> URL? {
20
+ self.bundleURL()
21
+ }
22
+
23
+ override func bundleURL() -> URL? {
24
+ #if DEBUG
25
+ RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
26
+ #else
27
+ Bundle.main.url(forResource: "main", withExtension: "jsbundle")
28
+ #endif
29
+ }
30
+ }
@@ -0,0 +1,53 @@
1
+ {
2
+ "images" : [
3
+ {
4
+ "idiom" : "iphone",
5
+ "scale" : "2x",
6
+ "size" : "20x20"
7
+ },
8
+ {
9
+ "idiom" : "iphone",
10
+ "scale" : "3x",
11
+ "size" : "20x20"
12
+ },
13
+ {
14
+ "idiom" : "iphone",
15
+ "scale" : "2x",
16
+ "size" : "29x29"
17
+ },
18
+ {
19
+ "idiom" : "iphone",
20
+ "scale" : "3x",
21
+ "size" : "29x29"
22
+ },
23
+ {
24
+ "idiom" : "iphone",
25
+ "scale" : "2x",
26
+ "size" : "40x40"
27
+ },
28
+ {
29
+ "idiom" : "iphone",
30
+ "scale" : "3x",
31
+ "size" : "40x40"
32
+ },
33
+ {
34
+ "idiom" : "iphone",
35
+ "scale" : "2x",
36
+ "size" : "60x60"
37
+ },
38
+ {
39
+ "idiom" : "iphone",
40
+ "scale" : "3x",
41
+ "size" : "60x60"
42
+ },
43
+ {
44
+ "idiom" : "ios-marketing",
45
+ "scale" : "1x",
46
+ "size" : "1024x1024"
47
+ }
48
+ ],
49
+ "info" : {
50
+ "author" : "xcode",
51
+ "version" : 1
52
+ }
53
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "info" : {
3
+ "version" : 1,
4
+ "author" : "xcode"
5
+ }
6
+ }
@@ -0,0 +1,52 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>CFBundleDevelopmentRegion</key>
6
+ <string>en</string>
7
+ <key>CFBundleDisplayName</key>
8
+ <string>ReactNativeDeviceSecureInfo</string>
9
+ <key>CFBundleExecutable</key>
10
+ <string>$(EXECUTABLE_NAME)</string>
11
+ <key>CFBundleIdentifier</key>
12
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
13
+ <key>CFBundleInfoDictionaryVersion</key>
14
+ <string>6.0</string>
15
+ <key>CFBundleName</key>
16
+ <string>$(PRODUCT_NAME)</string>
17
+ <key>CFBundlePackageType</key>
18
+ <string>APPL</string>
19
+ <key>CFBundleShortVersionString</key>
20
+ <string>$(MARKETING_VERSION)</string>
21
+ <key>CFBundleSignature</key>
22
+ <string>????</string>
23
+ <key>CFBundleVersion</key>
24
+ <string>$(CURRENT_PROJECT_VERSION)</string>
25
+ <key>LSRequiresIPhoneOS</key>
26
+ <true/>
27
+ <key>NSAppTransportSecurity</key>
28
+ <dict>
29
+ <!-- Do not change NSAllowsArbitraryLoads to true, or you will risk app rejection! -->
30
+ <key>NSAllowsArbitraryLoads</key>
31
+ <false/>
32
+ <key>NSAllowsLocalNetworking</key>
33
+ <true/>
34
+ </dict>
35
+ <key>NSLocationWhenInUseUsageDescription</key>
36
+ <string></string>
37
+ <key>UILaunchStoryboardName</key>
38
+ <string>LaunchScreen</string>
39
+ <key>UIRequiredDeviceCapabilities</key>
40
+ <array>
41
+ <string>arm64</string>
42
+ </array>
43
+ <key>UISupportedInterfaceOrientations</key>
44
+ <array>
45
+ <string>UIInterfaceOrientationPortrait</string>
46
+ <string>UIInterfaceOrientationLandscapeLeft</string>
47
+ <string>UIInterfaceOrientationLandscapeRight</string>
48
+ </array>
49
+ <key>UIViewControllerBasedStatusBarAppearance</key>
50
+ <false/>
51
+ </dict>
52
+ </plist>
@@ -0,0 +1,47 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
3
+ <device id="retina4_7" orientation="portrait" appearance="light"/>
4
+ <dependencies>
5
+ <deployment identifier="iOS"/>
6
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
7
+ <capability name="Safe area layout guides" minToolsVersion="9.0"/>
8
+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
9
+ </dependencies>
10
+ <scenes>
11
+ <!--View Controller-->
12
+ <scene sceneID="EHf-IW-A2E">
13
+ <objects>
14
+ <viewController id="01J-lp-oVM" sceneMemberID="viewController">
15
+ <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
16
+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
17
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
18
+ <subviews>
19
+ <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="ReactNativeDeviceSecureInfo" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="GJd-Yh-RWb">
20
+ <rect key="frame" x="0.0" y="202" width="375" height="43"/>
21
+ <fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
22
+ <nil key="highlightedColor"/>
23
+ </label>
24
+ <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Powered by React Native" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="MN2-I3-ftu">
25
+ <rect key="frame" x="0.0" y="626" width="375" height="21"/>
26
+ <fontDescription key="fontDescription" type="system" pointSize="17"/>
27
+ <nil key="highlightedColor"/>
28
+ </label>
29
+ </subviews>
30
+ <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
31
+ <constraints>
32
+ <constraint firstItem="Bcu-3y-fUS" firstAttribute="bottom" secondItem="MN2-I3-ftu" secondAttribute="bottom" constant="20" id="OZV-Vh-mqD"/>
33
+ <constraint firstItem="Bcu-3y-fUS" firstAttribute="centerX" secondItem="GJd-Yh-RWb" secondAttribute="centerX" id="Q3B-4B-g5h"/>
34
+ <constraint firstItem="MN2-I3-ftu" firstAttribute="centerX" secondItem="Bcu-3y-fUS" secondAttribute="centerX" id="akx-eg-2ui"/>
35
+ <constraint firstItem="MN2-I3-ftu" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" id="i1E-0Y-4RG"/>
36
+ <constraint firstItem="GJd-Yh-RWb" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="bottom" multiplier="1/3" constant="1" id="moa-c2-u7t"/>
37
+ <constraint firstItem="GJd-Yh-RWb" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" symbolic="YES" id="x7j-FC-K8j"/>
38
+ </constraints>
39
+ <viewLayoutGuide key="safeArea" id="Bcu-3y-fUS"/>
40
+ </view>
41
+ </viewController>
42
+ <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
43
+ </objects>
44
+ <point key="canvasLocation" x="52.173913043478265" y="375"/>
45
+ </scene>
46
+ </scenes>
47
+ </document>
@@ -0,0 +1,37 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>NSPrivacyAccessedAPITypes</key>
6
+ <array>
7
+ <dict>
8
+ <key>NSPrivacyAccessedAPIType</key>
9
+ <string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
10
+ <key>NSPrivacyAccessedAPITypeReasons</key>
11
+ <array>
12
+ <string>C617.1</string>
13
+ </array>
14
+ </dict>
15
+ <dict>
16
+ <key>NSPrivacyAccessedAPIType</key>
17
+ <string>NSPrivacyAccessedAPICategoryUserDefaults</string>
18
+ <key>NSPrivacyAccessedAPITypeReasons</key>
19
+ <array>
20
+ <string>CA92.1</string>
21
+ </array>
22
+ </dict>
23
+ <dict>
24
+ <key>NSPrivacyAccessedAPIType</key>
25
+ <string>NSPrivacyAccessedAPICategorySystemBootTime</string>
26
+ <key>NSPrivacyAccessedAPITypeReasons</key>
27
+ <array>
28
+ <string>35F9.1</string>
29
+ </array>
30
+ </dict>
31
+ </array>
32
+ <key>NSPrivacyCollectedDataTypes</key>
33
+ <array/>
34
+ <key>NSPrivacyTracking</key>
35
+ <false/>
36
+ </dict>
37
+ </plist>
@@ -0,0 +1,4 @@
1
+ //
2
+ // Use this file to import your target's public headers that you would like to expose to Swift.
3
+ //
4
+