├── ECPrivacyCheckTools ├── Assets │ └── .gitkeep └── Classes │ ├── .gitkeep │ ├── Core │ ├── ECPrivacyCheckFilesAndFolders.h │ ├── ECPrivacyCheckFilesAndFolders.m │ ├── ECPrivacyCheckHomeKit.h │ ├── ECPrivacyCheckHealth.h │ ├── ECPrivacyCheckPhotos.h │ ├── ECPrivacyCheckCamera.h │ ├── ECPrivacyCheckCalendars.h │ ├── ECPrivacyCheckReminders.h │ ├── ECPrivacyCheckContacts.h │ ├── ECPrivacyCheckMicrophone.h │ ├── ECPrivacyCheckBluetooth.h │ ├── ECPrivacyCheckMotionAndFitness.h │ ├── ECPrivacyCheckSpeechRecognition.h │ ├── ECPrivacyCheckLocationServices.h │ ├── ECPrivacyCheckMediaAndAppleMusic.h │ ├── ECPrivacyCheckMicrophone.m │ ├── ECPrivacyCheckReminders.m │ ├── ECPrivacyCheckCalendars.m │ ├── ECPrivacyCheckPhotos.m │ ├── ECPrivacyCheckCamera.m │ ├── ECPrivacyCheckHealth.m │ ├── ECPrivacyCheckMediaAndAppleMusic.m │ ├── ECPrivacyCheckSpeechRecognition.m │ ├── ECPrivacyCheckHomeKit.m │ ├── ECPrivacyCheckMotionAndFitness.m │ ├── ECPrivacyCheckBluetooth.m │ ├── ECPrivacyCheckContacts.m │ └── ECPrivacyCheckLocationServices.m │ ├── ECPrivacyCheckHelp.h │ └── ECPrivacyCheckGatherTool.h ├── _Pods.xcodeproj ├── Example ├── Tests │ ├── en.lproj │ │ └── InfoPlist.strings │ ├── Tests-Prefix.pch │ ├── Tests-Info.plist │ └── Tests.m ├── ECPrivacyCheckTools │ ├── en.lproj │ │ └── InfoPlist.strings │ ├── Images.xcassets │ │ ├── Contents.json │ │ └── AppIcon.appiconset │ │ │ ├── CarPlay-60@2x.png │ │ │ ├── CarPlay-60@3x.png │ │ │ ├── iPad App-76.png │ │ │ ├── App Store-1024.png │ │ │ ├── App Store-1025.png │ │ │ ├── iPad App-76@2x.png │ │ │ ├── iPad Settings-29.png │ │ │ ├── iPad Spotlight-40.png │ │ │ ├── iPhone App-60@2x.png │ │ │ ├── iPhone App-60@3x.png │ │ │ ├── iPad Pro App-83.5@2x.png │ │ │ ├── iPad Settings-29@2x.png │ │ │ ├── iPad Spotlight-40@2x.png │ │ │ ├── iPad Notifications-20.png │ │ │ ├── iPhone Settings-29@2x.png │ │ │ ├── iPhone Settings-29@3x.png │ │ │ ├── iPhone Spotlight-40@2x.png │ │ │ ├── iPhone Spotlight-40@3x.png │ │ │ ├── iPad Notifications-20@2x.png │ │ │ ├── iPhone Notification-20@2x.png │ │ │ ├── iPhone Notification-20@3x.png │ │ │ ├── iPad Notifications-20@2x-1.png │ │ │ └── Contents.json │ ├── Resources │ │ ├── 01.PNG │ │ ├── 02.PNG │ │ ├── 健康@2x.png │ │ ├── 健康@3x.png │ │ ├── 日历@2x.png │ │ ├── 日历@3x.png │ │ ├── 照片@2x.png │ │ ├── 照片@3x.png │ │ ├── 相机@2x.png │ │ ├── 相机@3x.png │ │ ├── 蓝牙@2x.png │ │ ├── 蓝牙@3x.png │ │ ├── 定位服务@2x.png │ │ ├── 定位服务@3x.png │ │ ├── 提醒事项@2x.png │ │ ├── 提醒事项@3x.png │ │ ├── 语音识别@2x.png │ │ ├── 语音识别@3x.png │ │ ├── 运动与健身@2x.png │ │ ├── 运动与健身@3x.png │ │ ├── 通讯录@2x.png │ │ ├── 通讯录@3x.png │ │ ├── 麦克风@2x.png │ │ ├── 麦克风@3x.png │ │ ├── HomeKit@2x.png │ │ ├── HomeKit@3x.png │ │ ├── 文件和文件夹@2x.png │ │ ├── 文件和文件夹@3x.png │ │ ├── 媒体与AppleMusic@2x.png │ │ └── 媒体与AppleMusic@3x.png │ ├── ECViewController.h │ ├── ECAppDelegate.h │ ├── main.m │ ├── ECPrivacyCheckTools-Prefix.pch │ ├── LaunchScreen.storyboard │ ├── ECMacros.h │ ├── utils │ │ ├── ECAlert.h │ │ └── ECAlert.m │ ├── ECAppDelegate.m │ └── ECPrivacyCheckTools-Info.plist ├── Pods │ ├── Target Support Files │ │ ├── FBSnapshotTestCase │ │ │ ├── FBSnapshotTestCase.modulemap │ │ │ ├── FBSnapshotTestCase-dummy.m │ │ │ ├── FBSnapshotTestCase-prefix.pch │ │ │ ├── FBSnapshotTestCase-umbrella.h │ │ │ ├── FBSnapshotTestCase-Info.plist │ │ │ ├── FBSnapshotTestCase.debug.xcconfig │ │ │ └── FBSnapshotTestCase.release.xcconfig │ │ ├── ECPrivacyCheckTools │ │ │ ├── ECPrivacyCheckTools.modulemap │ │ │ ├── ECPrivacyCheckTools-dummy.m │ │ │ ├── ECPrivacyCheckTools-prefix.pch │ │ │ ├── ECPrivacyCheckTools.debug.xcconfig │ │ │ ├── ECPrivacyCheckTools.release.xcconfig │ │ │ ├── ECPrivacyCheckTools-Info.plist │ │ │ └── ECPrivacyCheckTools-umbrella.h │ │ ├── Pods-ECPrivacyCheckTools_Tests │ │ │ ├── Pods-ECPrivacyCheckTools_Tests.modulemap │ │ │ ├── Pods-ECPrivacyCheckTools_Tests-dummy.m │ │ │ ├── Pods-ECPrivacyCheckTools_Tests-umbrella.h │ │ │ ├── Pods-ECPrivacyCheckTools_Tests-Info.plist │ │ │ ├── Pods-ECPrivacyCheckTools_Tests.debug.xcconfig │ │ │ ├── Pods-ECPrivacyCheckTools_Tests.release.xcconfig │ │ │ ├── Pods-ECPrivacyCheckTools_Tests-acknowledgements.markdown │ │ │ └── Pods-ECPrivacyCheckTools_Tests-acknowledgements.plist │ │ └── Pods-ECPrivacyCheckTools_Example │ │ │ ├── Pods-ECPrivacyCheckTools_Example.modulemap │ │ │ ├── Pods-ECPrivacyCheckTools_Example-dummy.m │ │ │ ├── Pods-ECPrivacyCheckTools_Example-umbrella.h │ │ │ ├── Pods-ECPrivacyCheckTools_Example.debug.xcconfig │ │ │ ├── Pods-ECPrivacyCheckTools_Example.release.xcconfig │ │ │ ├── Pods-ECPrivacyCheckTools_Example-Info.plist │ │ │ ├── Pods-ECPrivacyCheckTools_Example-acknowledgements.markdown │ │ │ └── Pods-ECPrivacyCheckTools_Example-acknowledgements.plist │ ├── FBSnapshotTestCase │ │ ├── FBSnapshotTestCase │ │ │ ├── Categories │ │ │ │ ├── UIApplication+StrictKeyWindow.h │ │ │ │ ├── UIImage+Snapshot.h │ │ │ │ ├── UIApplication+StrictKeyWindow.m │ │ │ │ ├── UIImage+Diff.h │ │ │ │ ├── UIImage+Compare.h │ │ │ │ ├── UIImage+Snapshot.m │ │ │ │ ├── UIImage+Diff.m │ │ │ │ └── UIImage+Compare.m │ │ │ ├── FBSnapshotTestCasePlatform.h │ │ │ ├── FBSnapshotTestCasePlatform.m │ │ │ ├── SwiftSupport.swift │ │ │ ├── FBSnapshotTestController.h │ │ │ ├── FBSnapshotTestCase.m │ │ │ └── FBSnapshotTestCase.h │ │ ├── LICENSE │ │ └── README.md │ ├── Manifest.lock │ ├── Local Podspecs │ │ └── ECPrivacyCheckTools.podspec.json │ └── Pods.xcodeproj │ │ └── xcuserdata │ │ └── EchoZuo.xcuserdatad │ │ └── xcschemes │ │ ├── Pods-ECPrivacyCheckTools_Tests.xcscheme │ │ ├── Pods-ECPrivacyCheckTools_Example.xcscheme │ │ ├── FBSnapshotTestCase.xcscheme │ │ └── ECPrivacyCheckTools.xcscheme ├── ECPrivacyCheckTools.xcodeproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── ECPrivacyCheckTools-Example.xcscheme ├── Podfile ├── ECPrivacyCheckTools.xcworkspace │ └── contents.xcworkspacedata ├── ECPrivacyCheckTools_Example │ └── ECPrivacyCheckTools_Example.entitlements └── Podfile.lock ├── LICENSE └── ECPrivacyCheckTools.podspec /ECPrivacyCheckTools/Assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_Pods.xcodeproj: -------------------------------------------------------------------------------- 1 | Example/Pods/Pods.xcodeproj -------------------------------------------------------------------------------- /Example/Tests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/01.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/01.PNG -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/02.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/02.PNG -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/健康@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/健康@2x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/健康@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/健康@3x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/日历@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/日历@2x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/日历@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/日历@3x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/照片@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/照片@2x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/照片@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/照片@3x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/相机@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/相机@2x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/相机@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/相机@3x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/蓝牙@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/蓝牙@2x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/蓝牙@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/蓝牙@3x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/定位服务@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/定位服务@2x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/定位服务@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/定位服务@3x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/提醒事项@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/提醒事项@2x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/提醒事项@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/提醒事项@3x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/语音识别@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/语音识别@2x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/语音识别@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/语音识别@3x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/运动与健身@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/运动与健身@2x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/运动与健身@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/运动与健身@3x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/通讯录@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/通讯录@2x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/通讯录@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/通讯录@3x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/麦克风@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/麦克风@2x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/麦克风@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/麦克风@3x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/HomeKit@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/HomeKit@2x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/HomeKit@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/HomeKit@3x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/文件和文件夹@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/文件和文件夹@2x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/文件和文件夹@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/文件和文件夹@3x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/媒体与AppleMusic@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/媒体与AppleMusic@2x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Resources/媒体与AppleMusic@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Resources/媒体与AppleMusic@3x.png -------------------------------------------------------------------------------- /Example/Tests/Tests-Prefix.pch: -------------------------------------------------------------------------------- 1 | // The contents of this file are implicitly included at the beginning of every test case source file. 2 | 3 | #ifdef __OBJC__ 4 | 5 | @import FBSnapshotTestCase; 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/CarPlay-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/CarPlay-60@2x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/CarPlay-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/CarPlay-60@3x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPad App-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPad App-76.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/App Store-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/App Store-1024.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/App Store-1025.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/App Store-1025.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPad App-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPad App-76@2x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPad Settings-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPad Settings-29.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPad Spotlight-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPad Spotlight-40.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPhone App-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPhone App-60@2x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPhone App-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPhone App-60@3x.png -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/FBSnapshotTestCase/FBSnapshotTestCase.modulemap: -------------------------------------------------------------------------------- 1 | framework module FBSnapshotTestCase { 2 | umbrella header "FBSnapshotTestCase-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPad Pro App-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPad Pro App-83.5@2x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPad Settings-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPad Settings-29@2x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPad Spotlight-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPad Spotlight-40@2x.png -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/ECPrivacyCheckTools/ECPrivacyCheckTools.modulemap: -------------------------------------------------------------------------------- 1 | framework module ECPrivacyCheckTools { 2 | umbrella header "ECPrivacyCheckTools-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPad Notifications-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPad Notifications-20.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPhone Settings-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPhone Settings-29@2x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPhone Settings-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPhone Settings-29@3x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPhone Spotlight-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPhone Spotlight-40@2x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPhone Spotlight-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPhone Spotlight-40@3x.png -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/ECPrivacyCheckTools/ECPrivacyCheckTools-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_ECPrivacyCheckTools : NSObject 3 | @end 4 | @implementation PodsDummy_ECPrivacyCheckTools 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/FBSnapshotTestCase/FBSnapshotTestCase-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_FBSnapshotTestCase : NSObject 3 | @end 4 | @implementation PodsDummy_FBSnapshotTestCase 5 | @end 6 | -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPad Notifications-20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPad Notifications-20@2x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPhone Notification-20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPhone Notification-20@2x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPhone Notification-20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPhone Notification-20@3x.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPad Notifications-20@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EchoZuo/ECPrivacyCheckTools/HEAD/Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/iPad Notifications-20@2x-1.png -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ECPrivacyCheckTools_Tests/Pods-ECPrivacyCheckTools_Tests.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_ECPrivacyCheckTools_Tests { 2 | umbrella header "Pods-ECPrivacyCheckTools_Tests-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ECPrivacyCheckTools_Example/Pods-ECPrivacyCheckTools_Example.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_ECPrivacyCheckTools_Example { 2 | umbrella header "Pods-ECPrivacyCheckTools_Example-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ECPrivacyCheckTools_Tests/Pods-ECPrivacyCheckTools_Tests-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_ECPrivacyCheckTools_Tests : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_ECPrivacyCheckTools_Tests 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ECPrivacyCheckTools_Example/Pods-ECPrivacyCheckTools_Example-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_ECPrivacyCheckTools_Example : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_ECPrivacyCheckTools_Example 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | use_frameworks! 2 | 3 | platform :ios, '8.0' 4 | 5 | target 'ECPrivacyCheckTools_Example' do 6 | pod 'ECPrivacyCheckTools', :path => '../' 7 | 8 | target 'ECPrivacyCheckTools_Tests' do 9 | inherit! :search_paths 10 | 11 | pod 'FBSnapshotTestCase' 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/ECViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECViewController.h 3 | // ECPrivacyCheckTools 4 | // 5 | // Created by EchoZuo on 05/22/2020. 6 | // Copyright (c) 2020 EchoZuo. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | @interface ECViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/FBSnapshotTestCase/FBSnapshotTestCase-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/ECPrivacyCheckTools/ECPrivacyCheckTools-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/ECAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECAppDelegate.h 3 | // ECPrivacyCheckTools 4 | // 5 | // Created by EchoZuo on 05/22/2020. 6 | // Copyright (c) 2020 EchoZuo. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | @import Foundation; 11 | 12 | @interface ECAppDelegate : UIResponder 13 | 14 | @property (strong, nonatomic) UIWindow *window; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // ECPrivacyCheckTools 4 | // 5 | // Created by EchoZuo on 05/22/2020. 6 | // Copyright (c) 2020 EchoZuo. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | #import "ECAppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) 13 | { 14 | @autoreleasepool { 15 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([ECAppDelegate class])); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools_Example/ECPrivacyCheckTools_Example.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.healthkit 6 | 7 | com.apple.developer.healthkit.access 8 | 9 | com.apple.developer.homekit 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/ECPrivacyCheckTools-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | @import UIKit; 15 | @import Foundation; 16 | 17 | #import "ECMacros.h" 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ECPrivacyCheckTools_Tests/Pods-ECPrivacyCheckTools_Tests-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_ECPrivacyCheckTools_TestsVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_ECPrivacyCheckTools_TestsVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ECPrivacyCheckTools_Example/Pods-ECPrivacyCheckTools_Example-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_ECPrivacyCheckTools_ExampleVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_ECPrivacyCheckTools_ExampleVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/ECPrivacyCheckTools/ECPrivacyCheckTools.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/ECPrivacyCheckTools 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | PODS_BUILD_DIR = ${BUILD_DIR} 4 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 5 | PODS_ROOT = ${SRCROOT} 6 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. 7 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 8 | SKIP_INSTALL = YES 9 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 10 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/ECPrivacyCheckTools/ECPrivacyCheckTools.release.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/ECPrivacyCheckTools 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | PODS_BUILD_DIR = ${BUILD_DIR} 4 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 5 | PODS_ROOT = ${SRCROOT} 6 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. 7 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 8 | SKIP_INSTALL = YES 9 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 10 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/FBSnapshotTestCase/FBSnapshotTestCase-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | #import "FBSnapshotTestCase.h" 14 | #import "FBSnapshotTestCasePlatform.h" 15 | #import "FBSnapshotTestController.h" 16 | 17 | FOUNDATION_EXPORT double FBSnapshotTestCaseVersionNumber; 18 | FOUNDATION_EXPORT const unsigned char FBSnapshotTestCaseVersionString[]; 19 | 20 | -------------------------------------------------------------------------------- /Example/Pods/FBSnapshotTestCase/FBSnapshotTestCase/Categories/UIApplication+StrictKeyWindow.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #import 12 | 13 | @interface UIApplication (StrictKeyWindow) 14 | 15 | /** 16 | @return The receiver's @c keyWindow. Raises an assertion if @c nil. 17 | */ 18 | - (UIWindow *)fb_strictKeyWindow; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Example/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - ECPrivacyCheckTools (2.0.0) 3 | - FBSnapshotTestCase (2.1.4): 4 | - FBSnapshotTestCase/SwiftSupport (= 2.1.4) 5 | - FBSnapshotTestCase/Core (2.1.4) 6 | - FBSnapshotTestCase/SwiftSupport (2.1.4): 7 | - FBSnapshotTestCase/Core 8 | 9 | DEPENDENCIES: 10 | - ECPrivacyCheckTools (from `../`) 11 | - FBSnapshotTestCase 12 | 13 | SPEC REPOS: 14 | trunk: 15 | - FBSnapshotTestCase 16 | 17 | EXTERNAL SOURCES: 18 | ECPrivacyCheckTools: 19 | :path: "../" 20 | 21 | SPEC CHECKSUMS: 22 | ECPrivacyCheckTools: 0b4fdc38d0662b5f608703b87adbec2efb834819 23 | FBSnapshotTestCase: 094f9f314decbabe373b87cc339bea235a63e07a 24 | 25 | PODFILE CHECKSUM: 4e63a890b09734415de7b01d5879721275433a49 26 | 27 | COCOAPODS: 1.9.1 28 | -------------------------------------------------------------------------------- /Example/Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - ECPrivacyCheckTools (2.0.0) 3 | - FBSnapshotTestCase (2.1.4): 4 | - FBSnapshotTestCase/SwiftSupport (= 2.1.4) 5 | - FBSnapshotTestCase/Core (2.1.4) 6 | - FBSnapshotTestCase/SwiftSupport (2.1.4): 7 | - FBSnapshotTestCase/Core 8 | 9 | DEPENDENCIES: 10 | - ECPrivacyCheckTools (from `../`) 11 | - FBSnapshotTestCase 12 | 13 | SPEC REPOS: 14 | trunk: 15 | - FBSnapshotTestCase 16 | 17 | EXTERNAL SOURCES: 18 | ECPrivacyCheckTools: 19 | :path: "../" 20 | 21 | SPEC CHECKSUMS: 22 | ECPrivacyCheckTools: 0b4fdc38d0662b5f608703b87adbec2efb834819 23 | FBSnapshotTestCase: 094f9f314decbabe373b87cc339bea235a63e07a 24 | 25 | PODFILE CHECKSUM: 4e63a890b09734415de7b01d5879721275433a49 26 | 27 | COCOAPODS: 1.9.1 28 | -------------------------------------------------------------------------------- /Example/Tests/Tests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Example/Tests/Tests.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckToolsTests.m 3 | // ECPrivacyCheckToolsTests 4 | // 5 | // Created by EchoZuo on 05/22/2020. 6 | // Copyright (c) 2020 EchoZuo. All rights reserved. 7 | // 8 | 9 | @import XCTest; 10 | 11 | @interface Tests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation Tests 16 | 17 | - (void)setUp 18 | { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown 24 | { 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | [super tearDown]; 27 | } 28 | 29 | - (void)testExample 30 | { 31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); 32 | } 33 | 34 | @end 35 | 36 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ECPrivacyCheckTools_Example/Pods-ECPrivacyCheckTools_Example.debug.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/ECPrivacyCheckTools" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/ECPrivacyCheckTools/ECPrivacyCheckTools.framework/Headers" 4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 5 | OTHER_LDFLAGS = $(inherited) -framework "ECPrivacyCheckTools" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 11 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ECPrivacyCheckTools_Example/Pods-ECPrivacyCheckTools_Example.release.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/ECPrivacyCheckTools" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/ECPrivacyCheckTools/ECPrivacyCheckTools.framework/Headers" 4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 5 | OTHER_LDFLAGS = $(inherited) -framework "ECPrivacyCheckTools" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 11 | -------------------------------------------------------------------------------- /Example/Pods/Local Podspecs/ECPrivacyCheckTools.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ECPrivacyCheckTools", 3 | "version": "2.0.0", 4 | "summary": "iOS 系统隐私权限检测工具。iOS system privacy permission check tools.", 5 | "description": "iOS 系统隐私权限检测工具.\n支持 iOS 8.0+\niOS system privacy permission check tools.\nSupport iOS 8.0+", 6 | "homepage": "https://github.com/EchoZuo/ECPrivacyCheckTools", 7 | "license": { 8 | "type": "MIT", 9 | "file": "LICENSE" 10 | }, 11 | "authors": { 12 | "EchoZuo": "zuoqianheng@foxmail.com" 13 | }, 14 | "source": { 15 | "git": "https://github.com/EchoZuo/ECPrivacyCheckTools.git", 16 | "tag": "2.0.0" 17 | }, 18 | "platforms": { 19 | "ios": "8.0" 20 | }, 21 | "requires_arc": true, 22 | "source_files": [ 23 | "ECPrivacyCheckTools/Classes/*.{h,m}", 24 | "ECPrivacyCheckTools/Classes/Core/*.{h,m}" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /Example/Pods/FBSnapshotTestCase/FBSnapshotTestCase/Categories/UIImage+Snapshot.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #import 12 | 13 | @interface UIImage (Snapshot) 14 | 15 | /// Uses renderInContext: to get a snapshot of the layer. 16 | + (UIImage *)fb_imageForLayer:(CALayer *)layer; 17 | 18 | /// Uses renderInContext: to get a snapshot of the view layer. 19 | + (UIImage *)fb_imageForViewLayer:(UIView *)view; 20 | 21 | /// Uses drawViewHierarchyInRect: to get a snapshot of the view and adds the view into a window if needed. 22 | + (UIImage *)fb_imageForView:(UIView *)view; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/Core/ECPrivacyCheckFilesAndFolders.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckFilesAndFolders.h 3 | // Expecta 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | /// 文件和文件夹 8 | 9 | /** 10 | 拷贝模式:将文档拷贝到自己项目中 11 | 在 Info.plist中,添加 “Document Types” 键值 12 | - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options{ 13 | } 14 | 15 | 存储模式:将文档存储到”文件“中 16 | //打开项目中的info.plist,添加 “Supports Document Browser” 键值 17 | UIDocumentPickerViewController * controller = [[UIDocumentPickerViewController alloc]initWithDocumentTypes:[@""] inMode:UIDocumentPickerModeOpen]; 18 | controller.delegate = self; 19 | [self presentViewController:controller animated:YES completion:nil]; 20 | 21 | */ 22 | 23 | #import 24 | 25 | NS_ASSUME_NONNULL_BEGIN 26 | 27 | @interface ECPrivacyCheckFilesAndFolders : NSObject 28 | 29 | @end 30 | 31 | NS_ASSUME_NONNULL_END 32 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/Core/ECPrivacyCheckFilesAndFolders.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckFilesAndFolders.m 3 | // Expecta 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | 8 | #import "ECPrivacyCheckFilesAndFolders.h" 9 | 10 | @implementation ECPrivacyCheckFilesAndFolders 11 | 12 | - (void)test { 13 | 14 | /** 15 | 拷贝模式:将文档拷贝到自己项目中 16 | 在 Info.plist中,添加 “Document Types” 键值 17 | - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options{ 18 | } 19 | 20 | 存储模式:将文档存储到”文件“中 21 | //打开项目中的info.plist,添加 “Supports Document Browser” 键值 22 | UIDocumentPickerViewController * controller = [[UIDocumentPickerViewController alloc]initWithDocumentTypes:[@""] inMode:UIDocumentPickerModeOpen]; 23 | controller.delegate = self; 24 | [self presentViewController:controller animated:YES completion:nil]; 25 | 26 | */ 27 | } 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/ECPrivacyCheckTools/ECPrivacyCheckTools-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 2.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/FBSnapshotTestCase/FBSnapshotTestCase-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 2.1.4 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ECPrivacyCheckTools_Tests/Pods-ECPrivacyCheckTools_Tests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ECPrivacyCheckTools_Example/Pods-ECPrivacyCheckTools_Example-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/Core/ECPrivacyCheckHomeKit.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckHomeKit.h 3 | // Expecta 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | /// HomeKit 家庭 8 | /** 9 | * HomeKit家庭权限回调依赖于实际业务(HMHomeManagerDelegate协议回调中处理),回调中error类型可以参考HMError.h 10 | * 建议可以根据实际业务进行封装 11 | * 这里提供使用方法供参考 12 | */ 13 | 14 | #import 15 | #import 16 | 17 | 18 | /// granted:bool 19 | /// manager:HMHomeManager 20 | typedef void(^ECHomeAccessCompletionHandler)(BOOL granted, HMHomeManager * _Nullable manager); 21 | 22 | 23 | NS_ASSUME_NONNULL_BEGIN 24 | 25 | @interface ECPrivacyCheckHomeKit : NSObject 26 | 27 | /// 请求家庭权限 28 | /// @param completionHandler completionHandler 29 | + (void)requestHomeAccessWithCompletionHandler:(ECHomeAccessCompletionHandler)completionHandler; 30 | 31 | /// 请求家庭权限 32 | /// @param completionHandler completionHandler 33 | - (void)requestHomeAccessWithCompletionHandler:(ECHomeAccessCompletionHandler)completionHandler; 34 | 35 | @end 36 | 37 | NS_ASSUME_NONNULL_END 38 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/FBSnapshotTestCase/FBSnapshotTestCase.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FBSnapshotTestCase 2 | ENABLE_BITCODE = NO 3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | LIBRARY_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/usr/lib" 6 | OTHER_LDFLAGS = $(inherited) -framework "Foundation" -framework "QuartzCore" -framework "UIKit" -framework "XCTest" 7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 8 | PODS_BUILD_DIR = ${BUILD_DIR} 9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_ROOT = ${SRCROOT} 11 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/FBSnapshotTestCase 12 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 13 | SKIP_INSTALL = YES 14 | SWIFT_INCLUDE_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/usr/lib" 15 | SYSTEM_FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks" 16 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/FBSnapshotTestCase/FBSnapshotTestCase.release.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FBSnapshotTestCase 2 | ENABLE_BITCODE = NO 3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | LIBRARY_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/usr/lib" 6 | OTHER_LDFLAGS = $(inherited) -framework "Foundation" -framework "QuartzCore" -framework "UIKit" -framework "XCTest" 7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 8 | PODS_BUILD_DIR = ${BUILD_DIR} 9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_ROOT = ${SRCROOT} 11 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/FBSnapshotTestCase 12 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 13 | SKIP_INSTALL = YES 14 | SWIFT_INCLUDE_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/usr/lib" 15 | SYSTEM_FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks" 16 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/ECPrivacyCheckTools/ECPrivacyCheckTools-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | #import "ECPrivacyCheckGatherTool.h" 14 | #import "ECPrivacyCheckHelp.h" 15 | #import "ECPrivacyCheckBluetooth.h" 16 | #import "ECPrivacyCheckCalendars.h" 17 | #import "ECPrivacyCheckCamera.h" 18 | #import "ECPrivacyCheckContacts.h" 19 | #import "ECPrivacyCheckFilesAndFolders.h" 20 | #import "ECPrivacyCheckHealth.h" 21 | #import "ECPrivacyCheckHomeKit.h" 22 | #import "ECPrivacyCheckLocationServices.h" 23 | #import "ECPrivacyCheckMediaAndAppleMusic.h" 24 | #import "ECPrivacyCheckMicrophone.h" 25 | #import "ECPrivacyCheckMotionAndFitness.h" 26 | #import "ECPrivacyCheckPhotos.h" 27 | #import "ECPrivacyCheckReminders.h" 28 | #import "ECPrivacyCheckSpeechRecognition.h" 29 | 30 | FOUNDATION_EXPORT double ECPrivacyCheckToolsVersionNumber; 31 | FOUNDATION_EXPORT const unsigned char ECPrivacyCheckToolsVersionString[]; 32 | 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 EchoZuo 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Example/Pods/FBSnapshotTestCase/FBSnapshotTestCase/Categories/UIApplication+StrictKeyWindow.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #import 12 | 13 | @implementation UIApplication (StrictKeyWindow) 14 | 15 | - (UIWindow *)fb_strictKeyWindow 16 | { 17 | UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow; 18 | if (!keyWindow) { 19 | [NSException raise:@"FBSnapshotTestCaseNilKeyWindowException" 20 | format:@"Snapshot tests must be hosted by an application with a key window. Please ensure your test" 21 | " host sets up a key window at launch (either via storyboards or programmatically) and doesn't" 22 | " do anything to remove it while snapshot tests are running."]; 23 | } 24 | return keyWindow; 25 | } 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/ECPrivacyCheckHelp.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckHelp.h 3 | // ECPrivacyCheckTools 4 | // 5 | // Created by EchoZuo on 2020/4/20. 6 | // 7 | 8 | #ifndef ECPrivacyCheckHelp_h 9 | #define ECPrivacyCheckHelp_h 10 | 11 | /// version:2.0.0 12 | 13 | /** 14 | * ECPrivacyCheckGatherTool 常用隐私权限检测集合工具,包含:定位、照片、相机、通讯录 15 | * 16 | * ECPrivacyCheckLocationServices 定位服务 17 | * ECPrivacyCheckContacts 通讯录 18 | * ECPrivacyCheckCalendars 日历 19 | * ECPrivacyCheckReminders 提醒事项 20 | * ECPrivacyCheckPhotos 照片 21 | * ECPrivacyCheckBluetooth 蓝牙 22 | * ECPrivacyCheckMicrophone 麦克风 23 | * ECPrivacyCheckSpeechRecognition 语音识别 >= iOS 10.0 24 | * ECPrivacyCheckCamera 相机 25 | * ECPrivacyCheckHealth 健康 >= iOS 8.0 26 | * ECPrivacyCheckHomeKit HomeKit >= iOS 8.0 27 | * ECPrivacyCheckMediaAndAppleMusic 媒体与Apple Music >= iOS9.3 28 | * ECPrivacyCheckFilesAndFolders 文件和文件夹 29 | * ECPrivacyCheckMotionAndFitness 运动与健身 30 | * 31 | */ 32 | 33 | #endif /* ECPrivacyCheckHelp_h */ 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ECPrivacyCheckTools_Tests/Pods-ECPrivacyCheckTools_Tests.debug.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks" "${PODS_CONFIGURATION_BUILD_DIR}/ECPrivacyCheckTools" "${PODS_CONFIGURATION_BUILD_DIR}/FBSnapshotTestCase" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/ECPrivacyCheckTools/ECPrivacyCheckTools.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FBSnapshotTestCase/FBSnapshotTestCase.framework/Headers" 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 6 | OTHER_LDFLAGS = $(inherited) -framework "ECPrivacyCheckTools" -framework "FBSnapshotTestCase" -framework "Foundation" -framework "QuartzCore" -framework "UIKit" -framework "XCTest" 7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 8 | PODS_BUILD_DIR = ${BUILD_DIR} 9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 11 | PODS_ROOT = ${SRCROOT}/Pods 12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 13 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ECPrivacyCheckTools_Tests/Pods-ECPrivacyCheckTools_Tests.release.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks" "${PODS_CONFIGURATION_BUILD_DIR}/ECPrivacyCheckTools" "${PODS_CONFIGURATION_BUILD_DIR}/FBSnapshotTestCase" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/ECPrivacyCheckTools/ECPrivacyCheckTools.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FBSnapshotTestCase/FBSnapshotTestCase.framework/Headers" 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 6 | OTHER_LDFLAGS = $(inherited) -framework "ECPrivacyCheckTools" -framework "FBSnapshotTestCase" -framework "Foundation" -framework "QuartzCore" -framework "UIKit" -framework "XCTest" 7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 8 | PODS_BUILD_DIR = ${BUILD_DIR} 9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 11 | PODS_ROOT = ${SRCROOT}/Pods 12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 13 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ECPrivacyCheckTools_Example/Pods-ECPrivacyCheckTools_Example-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## ECPrivacyCheckTools 5 | 6 | Copyright (c) 2020 EchoZuo 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | 26 | Generated by CocoaPods - https://cocoapods.org 27 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/Core/ECPrivacyCheckHealth.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckHealth.h 3 | // Expecta 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | /// 健康 8 | 9 | #import 10 | #import 11 | 12 | 13 | /** 授权状态 14 | * ECHealthAuthorizationStatusUnable:不支持或不可用 15 | * ECHealthAuthorizationStatusNotDetermined:用户从未进行过授权等处理,首次访问相应内容会提示用户进行授权 16 | * ECHealthAuthorizationStatusDenied:用户拒绝 17 | * ECHealthAuthorizationStatusAuthorized:已授权 18 | */ 19 | typedef NS_ENUM(NSInteger, ECHealthAuthorizationStatus) { 20 | ECHealthAuthorizationStatusUnable = -1, 21 | ECHealthAuthorizationStatusNotDetermined = 0, 22 | ECHealthAuthorizationStatusDenied, 23 | ECHealthAuthorizationStatusAuthorized 24 | }; 25 | 26 | 27 | NS_ASSUME_NONNULL_BEGIN 28 | 29 | @interface ECPrivacyCheckHealth : NSObject 30 | 31 | 32 | /// 检查健康权限状态:仅检查权限,不主动请求权限 33 | + (ECHealthAuthorizationStatus)healthAuthorizationStatus; 34 | 35 | /// 检查健康权限状态:仅检查权限,不主动请求权限 36 | - (ECHealthAuthorizationStatus)healthAuthorizationStatus; 37 | 38 | /// 请求健康权限 39 | /// @param completionHandler completionHandler 40 | + (void)requestHealthsAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler; 41 | 42 | /// 请求健康权限 43 | /// @param completionHandler completionHandler 44 | - (void)requestHealthsAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler; 45 | 46 | 47 | @end 48 | 49 | NS_ASSUME_NONNULL_END 50 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/Core/ECPrivacyCheckPhotos.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckPhotos.h 3 | // Expecta 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | /// 照片 8 | 9 | #import 10 | #import 11 | 12 | 13 | /** 授权状态 14 | * ECPhotosAuthorizationStatusUnable:不支持或不可用 15 | * ECPhotosAuthorizationStatusNotDetermined:用户从未进行过授权等处理,首次访问相应内容会提示用户进行授权 16 | * ECPhotosAuthorizationStatusRestricted:应用没有相关权限,且当前用户无法改变这个权限,比如:家长控制 17 | * ECPhotosAuthorizationStatusDenied:用户拒绝 18 | * ECPhotosAuthorizationStatusAuthorized:已授权 19 | */ 20 | typedef NS_ENUM(NSInteger, ECPhotosAuthorizationStatus) { 21 | ECPhotosAuthorizationStatusUnable = -1, 22 | ECPhotosAuthorizationStatusNotDetermined = 0, 23 | ECPhotosAuthorizationStatusRestricted, 24 | ECPhotosAuthorizationStatusDenied, 25 | ECPhotosAuthorizationStatusAuthorized 26 | }; 27 | 28 | 29 | NS_ASSUME_NONNULL_BEGIN 30 | 31 | @interface ECPrivacyCheckPhotos : NSObject 32 | 33 | /// 检查相册权限状态:仅检查权限,不主动请求权限 34 | + (ECPhotosAuthorizationStatus)photosAuthorizationStatus; 35 | 36 | /// 检查相册权限状态:仅检查权限,不主动请求权限 37 | - (ECPhotosAuthorizationStatus)photosAuthorizationStatus; 38 | 39 | /// 请求相册权限 40 | /// @param completionHandler completionHandler 41 | + (void)requestPhotosAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler; 42 | 43 | /// 请求相册权限 44 | /// @param completionHandler completionHandler 45 | - (void)requestPhotosAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler; 46 | 47 | @end 48 | 49 | NS_ASSUME_NONNULL_END 50 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/Core/ECPrivacyCheckCamera.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckCamera.h 3 | // Expecta 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | /// 相机 8 | 9 | #import 10 | #import 11 | 12 | 13 | /** 授权状态 14 | * ECCameraAuthorizationStatusUnable:不支持或不可用 15 | * ECCameraAuthorizationStatusNotDetermined:用户从未进行过授权等处理,首次访问相应内容会提示用户进行授权 16 | * ECCameraAuthorizationStatusRestricted:应用没有相关权限,且当前用户无法改变这个权限,比如:家长控制 17 | * ECCameraAuthorizationStatusDenied:用户拒绝 18 | * ECCameraAuthorizationStatusAuthorized:已授权 19 | */ 20 | typedef NS_ENUM(NSInteger, ECCameraAuthorizationStatus) { 21 | ECCameraAuthorizationStatusUnable = -1, 22 | ECCameraAuthorizationStatusNotDetermined = 0, 23 | ECCameraAuthorizationStatusRestricted, 24 | ECCameraAuthorizationStatusDenied, 25 | ECCameraAuthorizationStatusAuthorized 26 | }; 27 | 28 | NS_ASSUME_NONNULL_BEGIN 29 | 30 | @interface ECPrivacyCheckCamera : NSObject 31 | 32 | /// 检查相机权限状态:仅检查权限,不主动请求权限 33 | + (ECCameraAuthorizationStatus)cameraAuthorizationStatus; 34 | 35 | /// 检查相机权限状态:仅检查权限,不主动请求权限 36 | - (ECCameraAuthorizationStatus)cameraAuthorizationStatus; 37 | 38 | /// 请求相机权限 39 | /// @param completionHandler completionHandler 40 | + (void)requestCameraAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler; 41 | 42 | /// 请求相机权限 43 | /// @param completionHandler completionHandler 44 | - (void)requestCameraAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler; 45 | 46 | 47 | @end 48 | 49 | NS_ASSUME_NONNULL_END 50 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/Core/ECPrivacyCheckCalendars.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckCalendars.h 3 | // Expecta 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | /// 日历 8 | 9 | #import 10 | #import 11 | 12 | 13 | /** 授权状态 14 | * ECCalendarsAuthorizationStatusUnable:不支持或不可用 15 | * ECCalendarsAuthorizationStatusNotDetermined:用户从未进行过授权等处理,首次访问相应内容会提示用户进行授权 16 | * ECCalendarsAuthorizationStatusRestricted:应用没有相关权限,且当前用户无法改变这个权限,比如:家长控制 17 | * ECCalendarsAuthorizationStatusDenied:用户拒绝 18 | * ECCalendarsAuthorizationStatusAuthorized:已授权 19 | */ 20 | typedef NS_ENUM(NSInteger, ECCalendarsAuthorizationStatus) { 21 | ECCalendarsAuthorizationStatusUnable = -1, 22 | ECCalendarsAuthorizationStatusNotDetermined = 0, 23 | ECCalendarsAuthorizationStatusRestricted, 24 | ECCalendarsAuthorizationStatusDenied, 25 | ECCalendarsAuthorizationStatusAuthorized 26 | }; 27 | 28 | 29 | NS_ASSUME_NONNULL_BEGIN 30 | 31 | @interface ECPrivacyCheckCalendars : NSObject 32 | 33 | /// 检查日历权限状态:仅检查权限,不主动请求权限 34 | + (ECCalendarsAuthorizationStatus)calendarsAuthorizationStatus; 35 | 36 | /// 检查日历权限状态:仅检查权限,不主动请求权限 37 | - (ECCalendarsAuthorizationStatus)calendarsAuthorizationStatus; 38 | 39 | /// 请求日历权限 40 | /// @param completionHandler completionHandler 41 | + (void)requestCalendarsAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler; 42 | 43 | /// 请求日历权限 44 | /// @param completionHandler completionHandler 45 | - (void)requestCalendarsAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler; 46 | 47 | @end 48 | 49 | NS_ASSUME_NONNULL_END 50 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/Core/ECPrivacyCheckReminders.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckReminders.h 3 | // Expecta 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | /// 提醒事项 8 | 9 | #import 10 | #import 11 | 12 | 13 | /** 授权状态 14 | * 15 | * ECRemindersAuthorizationStatusUnable:不支持或不可用 16 | * ECRemindersAuthorizationStatusNotDetermined:用户从未进行过授权等处理,首次访问相应内容会提示用户进行授权 17 | * ECRemindersAuthorizationStatusRestricted:应用没有相关权限,且当前用户无法改变这个权限,比如:家长控制 18 | * ECRemindersAuthorizationStatusDenied:用户拒绝 19 | * ECRemindersAuthorizationStatusAuthorized:已授权 20 | */ 21 | typedef NS_ENUM(NSInteger, ECRemindersAuthorizationStatus) { 22 | ECRemindersAuthorizationStatusUnable = -1, 23 | ECRemindersAuthorizationStatusNotDetermined = 0, 24 | ECRemindersAuthorizationStatusRestricted, 25 | ECRemindersAuthorizationStatusDenied, 26 | ECRemindersAuthorizationStatusAuthorized 27 | }; 28 | 29 | 30 | NS_ASSUME_NONNULL_BEGIN 31 | 32 | @interface ECPrivacyCheckReminders : NSObject 33 | 34 | /// 检查日历权限状态:仅检查权限,不主动请求权限 35 | + (ECRemindersAuthorizationStatus)remindersAuthorizationStatus; 36 | 37 | /// 检查日历权限状态:仅检查权限,不主动请求权限 38 | - (ECRemindersAuthorizationStatus)remindersAuthorizationStatus; 39 | 40 | /// 请求日历权限 41 | /// @param completionHandler completionHandler 42 | + (void)requestRemindersAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler; 43 | 44 | /// 请求日历权限 45 | /// @param completionHandler completionHandler 46 | - (void)requestRemindersAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler; 47 | 48 | @end 49 | 50 | NS_ASSUME_NONNULL_END 51 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/Core/ECPrivacyCheckContacts.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckContacts.h 3 | // Expecta 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | /// 通讯录 8 | 9 | #import 10 | #import 11 | #import 12 | 13 | 14 | /** 授权状态 15 | * ECContactsAuthorizationStatusUnable:不支持或不可用 16 | * ECContactsAuthorizationStatusNotDetermined:用户从未进行过授权等处理,首次访问相应内容会提示用户进行授权 17 | * ECContactsAuthorizationStatusRestricted:应用没有相关权限,且当前用户无法改变这个权限,比如:家长控制 18 | * ECContactsAuthorizationStatusDenied:用户拒绝 19 | * ECContactsAuthorizationStatusAuthorized:已授权 20 | */ 21 | typedef NS_ENUM(NSInteger, ECContactsAuthorizationStatus) { 22 | ECContactsAuthorizationStatusUnable = -1, 23 | ECContactsAuthorizationStatusNotDetermined = 0, 24 | ECContactsAuthorizationStatusRestricted, 25 | ECContactsAuthorizationStatusDenied, 26 | ECContactsAuthorizationStatusAuthorized 27 | }; 28 | 29 | 30 | NS_ASSUME_NONNULL_BEGIN 31 | 32 | @interface ECPrivacyCheckContacts : NSObject 33 | 34 | /// 检查通讯录权限状态:仅检查权限,不主动请求权限 35 | + (ECContactsAuthorizationStatus)contactsAuthorizationStatus; 36 | 37 | /// 检查通讯录权限状态:仅检查权限,不主动请求权限 38 | - (ECContactsAuthorizationStatus)contactsAuthorizationStatus; 39 | 40 | /// 请求通讯录权限 41 | /// @param completionHandler completionHandler 42 | + (void)requestContactsAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler; 43 | 44 | /// 请求通讯录权限 45 | /// @param completionHandler completionHandler 46 | - (void)requestContactsAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler; 47 | 48 | @end 49 | 50 | NS_ASSUME_NONNULL_END 51 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/Core/ECPrivacyCheckMicrophone.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckMicrophone.h 3 | // Expecta 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | /// 麦克风 8 | 9 | #import 10 | #import 11 | 12 | 13 | /** 授权状态 14 | * ECMicrophoneAuthorizationStatusUnable:不支持或不可用 15 | * ECMicrophoneAuthorizationStatusNotDetermined:用户从未进行过授权等处理,首次访问相应内容会提示用户进行授权 16 | * ECMicrophoneAuthorizationStatusRestricted:应用没有相关权限,且当前用户无法改变这个权限,比如:家长控制 17 | * ECMicrophoneAuthorizationStatusDenied:用户拒绝 18 | * ECMicrophoneAuthorizationStatusAuthorized:已授权 19 | */ 20 | typedef NS_ENUM(NSInteger, ECMicrophoneAuthorizationStatus) { 21 | ECMicrophoneAuthorizationStatusUnable = -1, 22 | ECMicrophoneAuthorizationStatusNotDetermined = 0, 23 | ECMicrophoneAuthorizationStatusRestricted, 24 | ECMicrophoneAuthorizationStatusDenied, 25 | ECMicrophoneAuthorizationStatusAuthorized 26 | }; 27 | 28 | 29 | NS_ASSUME_NONNULL_BEGIN 30 | 31 | @interface ECPrivacyCheckMicrophone : NSObject 32 | 33 | /// 检查麦克风权限状态:仅检查权限,不主动请求权限 34 | + (ECMicrophoneAuthorizationStatus)microphoneAuthorizationStatus; 35 | 36 | /// 检查麦克风权限状态:仅检查权限,不主动请求权限 37 | - (ECMicrophoneAuthorizationStatus)microphoneAuthorizationStatus; 38 | 39 | /// 请求麦克风权限 40 | /// @param completionHandler completionHandler 41 | + (void)requestMicrophoneAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler; 42 | 43 | /// 请求麦克风权限 44 | /// @param completionHandler completionHandler 45 | - (void)requestMicrophoneAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler; 46 | 47 | @end 48 | 49 | NS_ASSUME_NONNULL_END 50 | -------------------------------------------------------------------------------- /Example/Pods/FBSnapshotTestCase/LICENSE: -------------------------------------------------------------------------------- 1 | BSD License 2 | 3 | For the FBSnapshotTestCase software 4 | 5 | Copyright (c) 2013, Facebook, Inc. 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | * Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | * Neither the name Facebook nor the names of its contributors may be used to 17 | endorse or promote products derived from this software without specific 18 | prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/Core/ECPrivacyCheckBluetooth.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckBluetooth.h 3 | // Expecta 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | /// 蓝牙 8 | /// 9 | /// 注意:这里有一个注意点,CBCentralManager 的创建是异步的。如果初始化完成之前没有被当前创建它的类所持有 10 | /// 就会在下一次RunLoop 迭代的时候释放。当然 CBCentralManager 实例如果不是在 ViewController 中创建的, 11 | /// 那么持有 CBCentralManager 的这个类在初始化之后也必须被 ViewController 持有,否则控制台会有如下的错误输出: 12 | /// [CoreBluetooth] XPC connection invalid 13 | /// ECPrivacyCheckBluetooth 也要使用全局属性定义 14 | 15 | 16 | #import 17 | #import 18 | 19 | /** 蓝牙权限状态 20 | * 21 | * ECCBAuthorizationStateUnknown:未知状态 22 | * ECCBAuthorizationStateResetting:正在重置,与系统服务暂时丢失 23 | * ECCBAuthorizationStateUnsupported:不支持蓝牙 24 | * ECCBAuthorizationStateUnauthorized:未授权 25 | * ECCBAuthorizationStatePoweredOff:关闭 26 | * ECCBAuthorizationStatePoweredOn:开启并可用 27 | */ 28 | typedef NS_ENUM(NSInteger, ECCBAuthorizationState) { 29 | 30 | ECCBAuthorizationStateUnknown = 0, 31 | ECCBAuthorizationStateResetting, 32 | ECCBAuthorizationStateUnsupported, 33 | ECCBAuthorizationStateUnauthorized, 34 | ECCBAuthorizationStatePoweredOff, 35 | ECCBAuthorizationStatePoweredOn 36 | }; 37 | 38 | 39 | NS_ASSUME_NONNULL_BEGIN 40 | 41 | @interface ECPrivacyCheckBluetooth : NSObject 42 | 43 | /// 必须设置为全局属性,否则会报错 44 | @property (nonatomic, strong) CBCentralManager *cbcManager; 45 | 46 | /// 获取蓝牙权限 47 | /// @param completionHandler completionHandler 48 | - (void)requestBluetoothAuthorizationWithCompletionHandler:(void(^)(ECCBAuthorizationState state))completionHandler; 49 | 50 | @end 51 | 52 | NS_ASSUME_NONNULL_END 53 | 54 | 55 | -------------------------------------------------------------------------------- /Example/Pods/FBSnapshotTestCase/FBSnapshotTestCase/Categories/UIImage+Diff.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gabriel Handford on 3/1/09. 3 | // Copyright 2009-2013. All rights reserved. 4 | // Created by John Boiles on 10/20/11. 5 | // Copyright (c) 2011. All rights reserved 6 | // Modified by Felix Schulze on 2/11/13. 7 | // Copyright 2013. All rights reserved. 8 | // 9 | // Permission is hereby granted, free of charge, to any person 10 | // obtaining a copy of this software and associated documentation 11 | // files (the "Software"), to deal in the Software without 12 | // restriction, including without limitation the rights to use, 13 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the 15 | // Software is furnished to do so, subject to the following 16 | // conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be 19 | // included in all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 23 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 25 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 26 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 27 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 28 | // OTHER DEALINGS IN THE SOFTWARE. 29 | // 30 | 31 | #import 32 | 33 | @interface UIImage (Diff) 34 | 35 | - (UIImage *)fb_diffWithImage:(UIImage *)image; 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /Example/Pods/FBSnapshotTestCase/FBSnapshotTestCase/Categories/UIImage+Compare.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gabriel Handford on 3/1/09. 3 | // Copyright 2009-2013. All rights reserved. 4 | // Created by John Boiles on 10/20/11. 5 | // Copyright (c) 2011. All rights reserved 6 | // Modified by Felix Schulze on 2/11/13. 7 | // Copyright 2013. All rights reserved. 8 | // 9 | // Permission is hereby granted, free of charge, to any person 10 | // obtaining a copy of this software and associated documentation 11 | // files (the "Software"), to deal in the Software without 12 | // restriction, including without limitation the rights to use, 13 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the 15 | // Software is furnished to do so, subject to the following 16 | // conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be 19 | // included in all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 23 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 25 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 26 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 27 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 28 | // OTHER DEALINGS IN THE SOFTWARE. 29 | // 30 | 31 | #import 32 | 33 | @interface UIImage (Compare) 34 | 35 | - (BOOL)fb_compareWithImage:(UIImage *)image tolerance:(CGFloat)tolerance; 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /Example/Pods/FBSnapshotTestCase/FBSnapshotTestCase/FBSnapshotTestCasePlatform.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #import 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | /** 18 | Returns a Boolean value that indicates whether the snapshot test is running in 64Bit. 19 | This method is a convenience for creating the suffixes set based on the architecture 20 | that the test is running. 21 | 22 | @returns @c YES if the test is running in 64bit, otherwise @c NO. 23 | */ 24 | BOOL FBSnapshotTestCaseIs64Bit(void); 25 | 26 | /** 27 | Returns a default set of strings that is used to append a suffix based on the architectures. 28 | @warning Do not modify this function, you can create your own and use it with @c FBSnapshotVerifyViewWithOptions() 29 | 30 | @returns An @c NSOrderedSet object containing strings that are appended to the reference images directory. 31 | */ 32 | NSOrderedSet *FBSnapshotTestCaseDefaultSuffixes(void); 33 | 34 | /** 35 | Returns a fully «normalized» file name. 36 | Strips punctuation and spaces and replaces them with @c _. Also appends the device model, running OS and screen size to the file name. 37 | 38 | @returns An @c NSString object containing the passed @c fileName with the device model, OS and screen size appended at the end. 39 | */ 40 | NSString *FBDeviceAgnosticNormalizedFileName(NSString *fileName); 41 | 42 | #ifdef __cplusplus 43 | } 44 | #endif 45 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/Core/ECPrivacyCheckMotionAndFitness.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckMotionAndFitness.h 3 | // Expecta 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | /// 运动与健身 8 | 9 | #import 10 | #import 11 | 12 | 13 | /** 授权状态 14 | * ECMotionAndFitnessAuthorizationStatusUnable:不支持或不可用 15 | * ECMotionAndFitnessAuthorizationStatusNotDetermined:用户从未进行过授权等处理,首次访问相应内容会提示用户进行授权 16 | * ECMotionAndFitnessAuthorizationStatusRestricted:应用没有相关权限,且当前用户无法改变这个权限,比如:家长控制 17 | * ECMotionAndFitnessAuthorizationStatusDenied:用户拒绝 18 | * ECMotionAndFitnessAuthorizationStatusAuthorized:已授权 19 | */ 20 | typedef NS_ENUM(NSInteger, ECMotionAndFitnessAuthorizationStatus) { 21 | ECMotionAndFitnessAuthorizationStatusUnable = -1, 22 | ECMotionAndFitnessAuthorizationStatusNotDetermined = 0, 23 | ECMotionAndFitnessAuthorizationStatusRestricted, 24 | ECMotionAndFitnessAuthorizationStatusDenied, 25 | ECMotionAndFitnessAuthorizationStatusAuthorized 26 | } API_AVAILABLE(ios(11.0), watchos(4.0)); 27 | 28 | 29 | NS_ASSUME_NONNULL_BEGIN 30 | 31 | @interface ECPrivacyCheckMotionAndFitness : NSObject 32 | 33 | /// 检查运动与健身权限状态:仅检查权限,不主动请求权限 34 | + (ECMotionAndFitnessAuthorizationStatus)motionAndFitnessAuthorizationStatus API_AVAILABLE(ios(11.0)); 35 | 36 | /// 检查运动与健身权限状态:仅检查权限,不主动请求权限 37 | - (ECMotionAndFitnessAuthorizationStatus)motionAndFitnessAuthorizationStatus API_AVAILABLE(ios(11.0)); 38 | 39 | /// 请求运动与健身权限 40 | /// @param completionHandler completionHandler 41 | + (void)requestMotionAndFitnessAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler; 42 | 43 | /// 请求运动与健身权限 44 | /// @param completionHandler completionHandler 45 | - (void)requestMotionAndFitnessAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler; 46 | @end 47 | 48 | NS_ASSUME_NONNULL_END 49 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/Core/ECPrivacyCheckSpeechRecognition.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckSpeechRecognition.h 3 | // Expecta 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | /// 语音识别 >= iOS 10.0 8 | 9 | #import 10 | #import 11 | 12 | /** 授权状态 13 | * ECSpeechRecognizerAuthorizationStatusUnable:不支持或不可用 14 | * ECSpeechRecognizerAuthorizationStatusNotDetermined:用户从未进行过授权等处理,首次访问相应内容会提示用户进行授权 15 | * ECSpeechRecognizerAuthorizationStatusRestricted:应用没有相关权限,且当前用户无法改变这个权限,比如:家长控制 16 | * ECSpeechRecognizerAuthorizationStatusDenied:用户拒绝 17 | * ECSpeechRecognizerAuthorizationStatusAuthorized:已授权 18 | */ 19 | typedef NS_ENUM(NSInteger, ECSpeechRecognizerAuthorizationStatus) { 20 | ECSpeechRecognizerAuthorizationStatusUnable = -1, 21 | ECSpeechRecognizerAuthorizationStatusNotDetermined = 0, 22 | ECSpeechRecognizerAuthorizationStatusRestricted, 23 | ECSpeechRecognizerAuthorizationStatusDenied, 24 | ECSpeechRecognizerAuthorizationStatusAuthorized 25 | }; 26 | 27 | NS_ASSUME_NONNULL_BEGIN 28 | 29 | @interface ECPrivacyCheckSpeechRecognition : NSObject 30 | 31 | /// 检查语音识别权限状态:仅检查权限,不主动请求权限 32 | + (ECSpeechRecognizerAuthorizationStatus)speechRecognitionAuthorizationStatus API_AVAILABLE(ios(10.0)); 33 | 34 | /// 检查语音识别权限状态:仅检查权限,不主动请求权限 35 | - (ECSpeechRecognizerAuthorizationStatus)speechRecognitionAuthorizationStatus API_AVAILABLE(ios(10.0)); 36 | 37 | /// 请求语音识别权限 38 | /// @param completionHandler completionHandler 39 | + (void)requestSpeechRecognitionAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler API_AVAILABLE(ios(10.0)); 40 | 41 | /// 请求语音识别权限 42 | /// @param completionHandler completionHandler 43 | - (void)requestSpeechRecognitionAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler API_AVAILABLE(ios(10.0)); 44 | 45 | @end 46 | 47 | NS_ASSUME_NONNULL_END 48 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ECPrivacyCheckTools_Tests/Pods-ECPrivacyCheckTools_Tests-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## FBSnapshotTestCase 5 | 6 | BSD License 7 | 8 | For the FBSnapshotTestCase software 9 | 10 | Copyright (c) 2013, Facebook, Inc. 11 | All rights reserved. 12 | 13 | Redistribution and use in source and binary forms, with or without 14 | modification, are permitted provided that the following conditions are met: 15 | 16 | * Redistributions of source code must retain the above copyright notice, 17 | this list of conditions and the following disclaimer. 18 | * Redistributions in binary form must reproduce the above copyright notice, 19 | this list of conditions and the following disclaimer in the documentation 20 | and/or other materials provided with the distribution. 21 | * Neither the name Facebook nor the names of its contributors may be used to 22 | endorse or promote products derived from this software without specific 23 | prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 29 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | 36 | Generated by CocoaPods - https://cocoapods.org 37 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/Core/ECPrivacyCheckLocationServices.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckLocationServices.h 3 | // Expecta 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | /// 定位服务 8 | 9 | #import 10 | #import 11 | 12 | 13 | /** 定位授权状态 14 | * 15 | * ECLocationAuthorizationStatusUnable:不支持或不可用 16 | * ECLocationAuthorizationStatusNotDetermined:用户从未进行过授权等处理,首次访问相应内容会提示用户进行授权 17 | * ECLocationAuthorizationStatusRestricted:应用没有相关权限,且当前用户无法改变这个权限,比如:家长控制 18 | * ECLocationAuthorizationStatusDenied:用户拒绝 19 | * ECLocationAuthorizationStatusAuthorizedAlways:一直允许获取定位 20 | * ECLocationAuthorizationStatusAuthorizedWhenInUse:在使用时允许定位 21 | * ECLocationAuthorizationStatusAuthorized:已废弃,在iOS2.0~8.0使用,> iOS 8.0 请使用 ECLocationAuthorizationStatusAuthorizedAlways: 一直允许获取定位 22 | */ 23 | typedef NS_ENUM(NSInteger, ECLocationAuthorizationStatus) { 24 | ECLocationAuthorizationStatusUnable = -1, 25 | ECLocationAuthorizationStatusNotDetermined = 0, 26 | ECLocationAuthorizationStatusRestricted, 27 | ECLocationAuthorizationStatusDenied, 28 | ECLocationAuthorizationStatusAuthorizedAlways, 29 | ECLocationAuthorizationStatusAuthorizedWhenInUse, 30 | ECLocationAuthorizationStatusAuthorized API_DEPRECATED("Use ECLocationAuthorizationStatusAuthorizedAlways", ios(2.0, 8.0)) = ECLocationAuthorizationStatusAuthorizedAlways 31 | }; 32 | 33 | 34 | NS_ASSUME_NONNULL_BEGIN 35 | 36 | @interface ECPrivacyCheckLocationServices : NSObject 37 | 38 | /// 检查定位权限状态:仅检查权限,不主动请求权限 39 | + (ECLocationAuthorizationStatus)locationAuthorizationStatus; 40 | 41 | /// 检查定位权限状态:仅检查权限,不主动请求权限 42 | - (ECLocationAuthorizationStatus)locationAuthorizationStatus; 43 | 44 | /// 请求定位权限 45 | /// @param completionHandler completionHandler 46 | - (void)requestLocationAuthorizationWithCompletionHandler:(void(^)(ECLocationAuthorizationStatus status))completionHandler; 47 | 48 | @end 49 | 50 | NS_ASSUME_NONNULL_END 51 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/Core/ECPrivacyCheckMediaAndAppleMusic.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckMediaAndAppleMusic.h 3 | // Expecta 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | /// 媒体与Apple Music >= iOS9.3 8 | 9 | #import 10 | #import 11 | 12 | 13 | /** 授权状态 14 | * ECMediaAndAppleMusicAuthorizationStatusUnable:不支持或不可用 15 | * ECMediaAndAppleMusicAuthorizationStatusNotDetermined:用户从未进行过授权等处理,首次访问相应内容会提示用户进行授权 16 | * ECMediaAndAppleMusicAuthorizationStatusRestricted:应用没有相关权限,且当前用户无法改变这个权限,比如:家长控制 17 | * ECMediaAndAppleMusicAuthorizationStatusDenied:用户拒绝 18 | * ECMediaAndAppleMusicAuthorizationStatusAuthorized:已授权 19 | */ 20 | typedef NS_ENUM(NSInteger, ECMediaAndAppleMusicAuthorizationStatus) { 21 | ECMediaAndAppleMusicAuthorizationStatusUnable = -1, 22 | ECMediaAndAppleMusicAuthorizationStatusNotDetermined = 0, 23 | ECMediaAndAppleMusicAuthorizationStatusRestricted, 24 | ECMediaAndAppleMusicAuthorizationStatusDenied, 25 | ECMediaAndAppleMusicAuthorizationStatusAuthorized 26 | }; 27 | 28 | 29 | NS_ASSUME_NONNULL_BEGIN 30 | 31 | @interface ECPrivacyCheckMediaAndAppleMusic : NSObject 32 | 33 | /// 检查 媒体与Apple Music 权限状态:仅检查权限,不主动请求权限 34 | + (ECMediaAndAppleMusicAuthorizationStatus)mediaAndAppleMusicAuthorizationStatus API_AVAILABLE(ios(9.3)); 35 | 36 | /// 检查 媒体与Apple Music 权限状态:仅检查权限,不主动请求权限 37 | - (ECMediaAndAppleMusicAuthorizationStatus)mediaAndAppleMusicAuthorizationStatus API_AVAILABLE(ios(9.3)); 38 | 39 | /// 请求 媒体与Apple Music 权限 40 | /// @param completionHandler completionHandler 41 | + (void)requestMediaAndAppleMusicAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler API_AVAILABLE(ios(9.3)); 42 | 43 | /// 请求 媒体与Apple Music 权限 44 | /// @param completionHandler completionHandler 45 | - (void)requestMediaAndAppleMusicAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler API_AVAILABLE(ios(9.3)); 46 | 47 | 48 | @end 49 | 50 | NS_ASSUME_NONNULL_END 51 | -------------------------------------------------------------------------------- /Example/Pods/FBSnapshotTestCase/FBSnapshotTestCase/FBSnapshotTestCasePlatform.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #import 12 | #import 13 | #import 14 | 15 | BOOL FBSnapshotTestCaseIs64Bit(void) 16 | { 17 | #if __LP64__ 18 | return YES; 19 | #else 20 | return NO; 21 | #endif 22 | } 23 | 24 | NSOrderedSet *FBSnapshotTestCaseDefaultSuffixes(void) 25 | { 26 | NSMutableOrderedSet *suffixesSet = [[NSMutableOrderedSet alloc] init]; 27 | [suffixesSet addObject:@"_32"]; 28 | [suffixesSet addObject:@"_64"]; 29 | if (FBSnapshotTestCaseIs64Bit()) { 30 | return [suffixesSet reversedOrderedSet]; 31 | } 32 | return [suffixesSet copy]; 33 | } 34 | 35 | NSString *FBDeviceAgnosticNormalizedFileName(NSString *fileName) 36 | { 37 | UIDevice *device = [UIDevice currentDevice]; 38 | UIWindow *keyWindow = [[UIApplication sharedApplication] fb_strictKeyWindow]; 39 | CGSize screenSize = keyWindow.bounds.size; 40 | NSString *os = device.systemVersion; 41 | 42 | fileName = [NSString stringWithFormat:@"%@_%@%@_%.0fx%.0f", fileName, device.model, os, screenSize.width, screenSize.height]; 43 | 44 | NSMutableCharacterSet *invalidCharacters = [NSMutableCharacterSet new]; 45 | [invalidCharacters formUnionWithCharacterSet:[NSCharacterSet whitespaceCharacterSet]]; 46 | [invalidCharacters formUnionWithCharacterSet:[NSCharacterSet punctuationCharacterSet]]; 47 | NSArray *validComponents = [fileName componentsSeparatedByCharactersInSet:invalidCharacters]; 48 | fileName = [validComponents componentsJoinedByString:@"_"]; 49 | 50 | return fileName; 51 | } -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/Core/ECPrivacyCheckMicrophone.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckMicrophone.m 3 | // Expecta 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | 8 | #import "ECPrivacyCheckMicrophone.h" 9 | 10 | @implementation ECPrivacyCheckMicrophone 11 | 12 | + (void)callbackOnMainQueue:(dispatch_block_t)block { 13 | dispatch_async(dispatch_get_main_queue(), block); 14 | } 15 | 16 | + (ECMicrophoneAuthorizationStatus)microphoneAuthorizationStatus { 17 | AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio]; 18 | 19 | if (status == AVAuthorizationStatusNotDetermined) { 20 | return ECMicrophoneAuthorizationStatusNotDetermined; 21 | } else if (status == AVAuthorizationStatusRestricted){ 22 | return ECMicrophoneAuthorizationStatusRestricted; 23 | } else if (status == AVAuthorizationStatusDenied) { 24 | return ECMicrophoneAuthorizationStatusDenied; 25 | } else { 26 | return ECMicrophoneAuthorizationStatusAuthorized; 27 | } 28 | } 29 | 30 | - (ECMicrophoneAuthorizationStatus)microphoneAuthorizationStatus { 31 | return [[self class] microphoneAuthorizationStatus]; 32 | } 33 | 34 | + (void)requestMicrophoneAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler { 35 | ECMicrophoneAuthorizationStatus status = [[self class] microphoneAuthorizationStatus]; 36 | 37 | if (status == ECMicrophoneAuthorizationStatusNotDetermined) { 38 | [AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio completionHandler:^(BOOL granted) { 39 | [self callbackOnMainQueue:^{ 40 | if (completionHandler) { 41 | completionHandler(granted); 42 | } 43 | }]; 44 | }]; 45 | } else { 46 | [self callbackOnMainQueue:^{ 47 | if (completionHandler) { 48 | completionHandler(status == ECMicrophoneAuthorizationStatusAuthorized); 49 | } 50 | }]; 51 | } 52 | } 53 | 54 | - (void)requestMicrophoneAuthorizationWithCompletionHandler:(void (^)(BOOL))completionHandler { 55 | [[self class] requestMicrophoneAuthorizationWithCompletionHandler:completionHandler]; 56 | } 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod lib lint ECPrivacyCheckTools.podspec' to ensure this is a 3 | # valid spec before submitting. 4 | # 5 | # Any lines starting with a # are optional, but their use is encouraged 6 | # To learn more about a Podspec see https://guides.cocoapods.org/syntax/podspec.html 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | s.name = 'ECPrivacyCheckTools' 11 | s.version = '2.0.0' 12 | s.summary = 'iOS 系统隐私权限检测工具。iOS system privacy permission check tools.' 13 | 14 | # This description is used to generate tags and improve search results. 15 | # * Think: What does it do? Why did you write it? What is the focus? 16 | # * Try to keep it short, snappy and to the point. 17 | # * Write the description between the DESC delimiters below. 18 | # * Finally, don't worry about the indent, CocoaPods strips it! 19 | 20 | s.description = <<-DESC 21 | iOS 系统隐私权限检测工具. 22 | 支持 iOS 8.0+ 23 | iOS system privacy permission check tools. 24 | Support iOS 8.0+ 25 | DESC 26 | 27 | s.homepage = 'https://github.com/EchoZuo/ECPrivacyCheckTools' 28 | # s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2' 29 | s.license = { :type => 'MIT', :file => 'LICENSE' } 30 | s.author = { 'EchoZuo' => 'zuoqianheng@foxmail.com' } 31 | s.source = { :git => 'https://github.com/EchoZuo/ECPrivacyCheckTools.git', :tag => s.version.to_s } 32 | # s.social_media_url = 'https://twitter.com/' 33 | 34 | s.ios.deployment_target = '8.0' 35 | s.requires_arc = true 36 | # s.module_name = 'ECPrivacyCheckTools' 37 | 38 | s.source_files = 'ECPrivacyCheckTools/Classes/*.{h,m}', 'ECPrivacyCheckTools/Classes/Core/*.{h,m}' 39 | # s.source_files = 'ECPrivacyCheckTools/Classes/**/*', 'ECPrivacyCheckTools/Classes/Core/*' 40 | # s.source_files = 'ECPrivacyCheckTools/Classes/**/*' 41 | # s.public_header_files = 'ECPrivacyCheckTools/Classes/**/*.h' 42 | 43 | # s.resource_bundles = { 44 | # 'ECPrivacyCheckTools' => ['ECPrivacyCheckTools/Assets/*.png'] 45 | # } 46 | 47 | # s.frameworks = 'UIKit', 'MapKit' 48 | # s.dependency 'AFNetworking', '~> 2.3' 49 | end 50 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/Core/ECPrivacyCheckReminders.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckReminders.m 3 | // Expecta 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | 8 | #import "ECPrivacyCheckReminders.h" 9 | 10 | @implementation ECPrivacyCheckReminders 11 | 12 | + (void)callbackOnMainQueue:(dispatch_block_t)block { 13 | dispatch_async(dispatch_get_main_queue(), block); 14 | } 15 | 16 | + (ECRemindersAuthorizationStatus)remindersAuthorizationStatus { 17 | EKAuthorizationStatus status = [EKEventStore authorizationStatusForEntityType:EKEntityTypeReminder]; 18 | if (status == EKAuthorizationStatusNotDetermined) { 19 | return ECRemindersAuthorizationStatusNotDetermined; 20 | } else if (status == EKAuthorizationStatusRestricted) { 21 | return ECRemindersAuthorizationStatusRestricted; 22 | } else if (status == EKAuthorizationStatusDenied) { 23 | return ECRemindersAuthorizationStatusDenied; 24 | } else { 25 | return ECRemindersAuthorizationStatusAuthorized; 26 | } 27 | } 28 | 29 | - (ECRemindersAuthorizationStatus)remindersAuthorizationStatus { 30 | return [[self class] remindersAuthorizationStatus]; 31 | } 32 | 33 | + (void)requestRemindersAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler { 34 | ECRemindersAuthorizationStatus status = [[self class] remindersAuthorizationStatus]; 35 | 36 | if (status == ECRemindersAuthorizationStatusNotDetermined) { 37 | EKEventStore *store = [[EKEventStore alloc] init]; 38 | [store requestAccessToEntityType:EKEntityTypeReminder completion:^(BOOL granted, NSError * _Nullable error) { 39 | [self callbackOnMainQueue:^{ 40 | if (completionHandler) { 41 | completionHandler(granted); 42 | } 43 | }]; 44 | }]; 45 | } else { 46 | [self callbackOnMainQueue:^{ 47 | if (completionHandler) { 48 | completionHandler(status == ECRemindersAuthorizationStatusAuthorized); 49 | } 50 | }]; 51 | } 52 | } 53 | 54 | - (void)requestRemindersAuthorizationWithCompletionHandler:(void (^)(BOOL))completionHandler { 55 | [[self class] requestRemindersAuthorizationWithCompletionHandler:completionHandler]; 56 | } 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/Core/ECPrivacyCheckCalendars.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckCalendars.m 3 | // Expecta 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | 8 | #import "ECPrivacyCheckCalendars.h" 9 | 10 | @implementation ECPrivacyCheckCalendars 11 | 12 | + (void)callbackOnMainQueue:(dispatch_block_t)block { 13 | dispatch_async(dispatch_get_main_queue(), block); 14 | } 15 | 16 | + (ECCalendarsAuthorizationStatus)calendarsAuthorizationStatus { 17 | EKAuthorizationStatus status = [EKEventStore authorizationStatusForEntityType:EKEntityTypeEvent]; 18 | if (status == EKAuthorizationStatusNotDetermined) { 19 | return ECCalendarsAuthorizationStatusNotDetermined; 20 | } else if (status == EKAuthorizationStatusRestricted) { 21 | return ECCalendarsAuthorizationStatusRestricted; 22 | } else if (status == EKAuthorizationStatusDenied) { 23 | return ECCalendarsAuthorizationStatusDenied; 24 | } else { 25 | return ECCalendarsAuthorizationStatusAuthorized; 26 | } 27 | } 28 | 29 | - (ECCalendarsAuthorizationStatus)calendarsAuthorizationStatus { 30 | return [[self class] calendarsAuthorizationStatus]; 31 | } 32 | 33 | + (void)requestCalendarsAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler { 34 | ECCalendarsAuthorizationStatus status = [[self class] calendarsAuthorizationStatus]; 35 | 36 | if (status == ECCalendarsAuthorizationStatusNotDetermined) { 37 | EKEventStore *store = [[EKEventStore alloc] init]; 38 | [store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError * _Nullable error) { 39 | [self callbackOnMainQueue:^{ 40 | if (completionHandler) { 41 | completionHandler(granted); 42 | } 43 | }]; 44 | }]; 45 | } else { 46 | [self callbackOnMainQueue:^{ 47 | if (completionHandler) { 48 | completionHandler(status == ECCalendarsAuthorizationStatusAuthorized); 49 | } 50 | }]; 51 | } 52 | } 53 | 54 | - (void)requestCalendarsAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler { 55 | [[self class] requestCalendarsAuthorizationWithCompletionHandler:completionHandler]; 56 | } 57 | 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/ECMacros.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECMacros.h 3 | // ECPrivacyCheckTools_Example 4 | // 5 | // Created by EchoZuo on 2020/5/26. 6 | // Copyright © 2020 EchoZuo. All rights reserved. 7 | // 8 | 9 | #ifndef ECMacros_h 10 | #define ECMacros_h 11 | 12 | @import UIKit; 13 | @import Foundation; 14 | 15 | 16 | #define EC_SCREEN_SIZE ([UIScreen mainScreen].bounds.size) // 屏幕size 17 | #define EC_SCREEN_WIDTH ([UIScreen mainScreen].bounds.size.width) // 屏幕宽度 18 | #define EC_SCREEN_HEIGHT ([UIScreen mainScreen].bounds.size.height) // 屏幕高度 19 | 20 | #define EC_STATUSBAR_HEIGHT ([UIApplication sharedApplication].statusBarFrame.size.height) // iPhoneX 44.0,一般20.0 21 | #define EC_NAVBAR_HEIGHT (44.0f) //导航栏高度 22 | #define EC_HEADERBAR_HEIGHT (EC_STATUSBAR_HEIGHT + EC_NAVBAR_HEIGHT) // 导航栏 + 状态栏高度 23 | 24 | #define EC_HOMEBAR_HEIGHT ((EC_IS_IPHONE_X_SERIES) ? (34.0f) : (0.0f)) // 虚拟条高度 25 | #define EC_TABBAR_HEIGHT (49.0f) //TabBar高度 26 | #define EC_FOOTERBAR_HEIGHT (EC_HOMEBAR_HEIGHT + EC_TABBAR_HEIGHT) // 虚拟条 + TabBar高度 27 | 28 | // iPhoneX系列 29 | #define EC_CONTENTAREA_WIDTH (EC_SCREEN_WIDTH) 30 | #define EC_CONTENTAREA_HEIGHT (EC_SCREEN_HEIGHT - EC_STATUSBAR_HEIGHT - EC_HOMEBAR_HEIGHT) 31 | 32 | 33 | // 通过尺寸区分设备 34 | #define EC_IS_IPHONE_4 (CGSizeEqualToSize(CGSizeMake(320, 480), [UIScreen mainScreen].bounds.size)) // 4、4S 35 | #define EC_IS_IPHONE_5 (CGSizeEqualToSize(CGSizeMake(320, 568), [UIScreen mainScreen].bounds.size)) // 5、5S、SE 36 | #define EC_IS_IPHONE_6 (CGSizeEqualToSize(CGSizeMake(375, 667), [UIScreen mainScreen].bounds.size)) // 6、6S、7、8、SE2 37 | #define EC_IS_IPHONE_PLUS (CGSizeEqualToSize(CGSizeMake(414, 736), [UIScreen mainScreen].bounds.size)) // 6SP、7P、8P 38 | #define EC_IS_IPHONE_X (CGSizeEqualToSize(CGSizeMake(375, 812), [UIScreen mainScreen].bounds.size)) // iPhoneX、iPhoneXS、iPhone11Pro 39 | #define EC_IS_IPHONE_XR (CGSizeEqualToSize(CGSizeMake(414, 896), [UIScreen mainScreen].bounds.size)) // iPhoneXR、iPhoneXS MAX、iPhone11、iPhone11Pro Max 40 | 41 | // 是否为iPhoneX系列 iPhoneX、iPhoneXS、iPhoneXR、iPhoneXS MAX、iPhone11、iPhone11Pro、iPhone11Pro Max 42 | #define EC_IS_IPHONE_X_SERIES ((CGSizeEqualToSize(CGSizeMake(375, 812), [UIScreen mainScreen].bounds.size)) || (CGSizeEqualToSize(CGSizeMake(414, 896), [UIScreen mainScreen].bounds.size))) 43 | 44 | #endif /* ECMacros_h */ 45 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/Core/ECPrivacyCheckPhotos.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckPhotos.m 3 | // Expecta 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | 8 | #import "ECPrivacyCheckPhotos.h" 9 | 10 | @implementation ECPrivacyCheckPhotos 11 | 12 | + (void)callbackOnMainQueue:(dispatch_block_t)block { 13 | dispatch_async(dispatch_get_main_queue(), block); 14 | } 15 | 16 | + (ECPhotosAuthorizationStatus)photosAuthorizationStatus { 17 | if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) { 18 | 19 | PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus]; 20 | if (status == PHAuthorizationStatusNotDetermined) { 21 | return ECPhotosAuthorizationStatusNotDetermined; 22 | } else if (status == PHAuthorizationStatusRestricted) { 23 | return ECPhotosAuthorizationStatusRestricted; 24 | } else if (status == PHAuthorizationStatusDenied) { 25 | return ECPhotosAuthorizationStatusDenied; 26 | } else { 27 | return ECPhotosAuthorizationStatusAuthorized; 28 | } 29 | } else { 30 | return ECPhotosAuthorizationStatusUnable; 31 | } 32 | } 33 | 34 | - (ECPhotosAuthorizationStatus)photosAuthorizationStatus { 35 | return [[self class] photosAuthorizationStatus]; 36 | } 37 | 38 | + (void)requestPhotosAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler { 39 | ECPhotosAuthorizationStatus status = [[self class] photosAuthorizationStatus]; 40 | if (status == ECPhotosAuthorizationStatusNotDetermined) { 41 | 42 | [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { 43 | [self callbackOnMainQueue:^{ 44 | if (completionHandler) { 45 | completionHandler(status == PHAuthorizationStatusAuthorized); 46 | } 47 | }]; 48 | }]; 49 | } else { 50 | [self callbackOnMainQueue:^{ 51 | if (completionHandler) { 52 | completionHandler(status == ECPhotosAuthorizationStatusAuthorized); 53 | } 54 | }]; 55 | } 56 | } 57 | 58 | - (void)requestPhotosAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler { 59 | [[self class] requestPhotosAuthorizationWithCompletionHandler:completionHandler]; 60 | } 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /Example/Pods/Pods.xcodeproj/xcuserdata/EchoZuo.xcuserdatad/xcschemes/Pods-ECPrivacyCheckTools_Tests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Example/Pods/Pods.xcodeproj/xcuserdata/EchoZuo.xcuserdatad/xcschemes/Pods-ECPrivacyCheckTools_Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/Core/ECPrivacyCheckCamera.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckCamera.m 3 | // Expecta 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | 8 | #import "ECPrivacyCheckCamera.h" 9 | 10 | @implementation ECPrivacyCheckCamera 11 | 12 | + (void)callbackOnMainQueue:(dispatch_block_t)block { 13 | dispatch_async(dispatch_get_main_queue(), block); 14 | } 15 | 16 | + (ECCameraAuthorizationStatus)cameraAuthorizationStatus { 17 | if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { 18 | AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; 19 | 20 | if (status == AVAuthorizationStatusNotDetermined) { 21 | return ECCameraAuthorizationStatusNotDetermined; 22 | } else if (status == AVAuthorizationStatusRestricted){ 23 | return ECCameraAuthorizationStatusRestricted; 24 | } else if (status == AVAuthorizationStatusDenied) { 25 | return ECCameraAuthorizationStatusDenied; 26 | } else { 27 | return ECCameraAuthorizationStatusAuthorized; 28 | } 29 | 30 | } else { 31 | return ECCameraAuthorizationStatusUnable; 32 | } 33 | } 34 | 35 | - (ECCameraAuthorizationStatus)cameraAuthorizationStatus { 36 | return [[self class] cameraAuthorizationStatus]; 37 | } 38 | 39 | 40 | + (void)requestCameraAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler { 41 | ECCameraAuthorizationStatus status = [[self class] cameraAuthorizationStatus]; 42 | 43 | if (status == ECCameraAuthorizationStatusNotDetermined) { 44 | [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) { 45 | [self callbackOnMainQueue:^{ 46 | if (completionHandler) { 47 | completionHandler(granted); 48 | } 49 | }]; 50 | }]; 51 | } else { 52 | [self callbackOnMainQueue:^{ 53 | if (completionHandler) { 54 | completionHandler(status == ECCameraAuthorizationStatusAuthorized); 55 | } 56 | }]; 57 | } 58 | } 59 | 60 | - (void)requestCameraAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler { 61 | [[self class] requestCameraAuthorizationWithCompletionHandler:completionHandler]; 62 | } 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /Example/Pods/Pods.xcodeproj/xcuserdata/EchoZuo.xcuserdatad/xcschemes/FBSnapshotTestCase.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 45 | 46 | 52 | 53 | 55 | 56 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /Example/Pods/Pods.xcodeproj/xcuserdata/EchoZuo.xcuserdatad/xcschemes/ECPrivacyCheckTools.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 45 | 46 | 52 | 53 | 55 | 56 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ECPrivacyCheckTools_Example/Pods-ECPrivacyCheckTools_Example-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Copyright (c) 2020 EchoZuo <zuoqianheng@foxmail.com> 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy 20 | of this software and associated documentation files (the "Software"), to deal 21 | in the Software without restriction, including without limitation the rights 22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 23 | copies of the Software, and to permit persons to whom the Software is 24 | furnished to do so, subject to the following conditions: 25 | 26 | The above copyright notice and this permission notice shall be included in 27 | all copies or substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 35 | THE SOFTWARE. 36 | 37 | License 38 | MIT 39 | Title 40 | ECPrivacyCheckTools 41 | Type 42 | PSGroupSpecifier 43 | 44 | 45 | FooterText 46 | Generated by CocoaPods - https://cocoapods.org 47 | Title 48 | 49 | Type 50 | PSGroupSpecifier 51 | 52 | 53 | StringsTable 54 | Acknowledgements 55 | Title 56 | Acknowledgements 57 | 58 | 59 | -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/utils/ECAlert.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECAlert.h 3 | // ECPrivacyCheckTools_Example 4 | // 5 | // Created by EchoZuo on 2020/5/27. 6 | // Copyright © 2020 EchoZuo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface ECAlert : NSObject 13 | 14 | /** 15 | 显示Alert 16 | 17 | @param title 标题 18 | @param message 信息 19 | @param completion 回调 20 | @param cancelButtonTitle 取消按钮文字 21 | @param otherButtonTitleArray 其他按钮文字数组 22 | */ 23 | + (void)showWithTitle:(NSString *)title 24 | message:(NSString *)message 25 | completion:(void(^)(NSInteger buttonIndex))completion 26 | cancelButtonTitle:(NSString *)cancelButtonTitle 27 | otherButtonTitleArray:(NSArray *)otherButtonTitleArray; 28 | 29 | /** 30 | 显示Alert 31 | 32 | @param title 标题 33 | @param message 信息 34 | @param completion 回调 35 | @param cancelButtonTitle 取消按钮文字 36 | @param otherButtonTitles 其他按钮文字 37 | */ 38 | + (void)showWithTitle:(NSString *)title 39 | message:(NSString *)message 40 | completion:(void(^)(NSInteger buttonIndex))completion 41 | cancelButtonTitle:(NSString *)cancelButtonTitle 42 | otherButtonTitles:(NSString *)otherButtonTitles, ... NS_REQUIRES_NIL_TERMINATION; 43 | 44 | /** 45 | 显示Alert,按钮:取消、确定 46 | 47 | @param message 信息 48 | @param completion 回调 49 | */ 50 | + (void)showWithMessage:(NSString *)message completion:(void(^)(NSInteger buttonIndex))completion; 51 | 52 | /** 53 | 显示Alert,按钮:确定 54 | 55 | @param message 信息 56 | @param completion 回调 57 | */ 58 | + (void)showConfirmAlertWithMessage:(NSString *)message completion:(void(^)(NSInteger buttonIndex))completion; 59 | 60 | /** 61 | 显示Alert,按钮:取消 62 | 63 | @param message 信息 64 | @param completion 回调 65 | */ 66 | + (void)showCancelAlertWithMessage:(NSString *)message completion:(void(^)(NSInteger buttonIndex))completion; 67 | 68 | @end 69 | 70 | /** 71 | 显示Alert 72 | 73 | @param title 标题 74 | @param message 信息 75 | @param buttonTitle 按钮文字 76 | @param completion 回调 77 | */ 78 | static inline void ECAlertShow(NSString *title, NSString *message, NSString *buttonTitle, void(^completion)(void)) { 79 | 80 | if (buttonTitle == nil) { 81 | buttonTitle = @"确定"; 82 | } 83 | 84 | [ECAlert showWithTitle:title message:message completion:^(NSInteger buttonIndex) { 85 | 86 | if (completion) { 87 | completion(); 88 | } 89 | 90 | } cancelButtonTitle:nil otherButtonTitles:buttonTitle, nil]; 91 | } 92 | 93 | 94 | -------------------------------------------------------------------------------- /Example/Pods/FBSnapshotTestCase/FBSnapshotTestCase/Categories/UIImage+Snapshot.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #import 12 | #import 13 | 14 | @implementation UIImage (Snapshot) 15 | 16 | + (UIImage *)fb_imageForLayer:(CALayer *)layer 17 | { 18 | CGRect bounds = layer.bounds; 19 | NSAssert1(CGRectGetWidth(bounds), @"Zero width for layer %@", layer); 20 | NSAssert1(CGRectGetHeight(bounds), @"Zero height for layer %@", layer); 21 | 22 | UIGraphicsBeginImageContextWithOptions(bounds.size, NO, 0); 23 | CGContextRef context = UIGraphicsGetCurrentContext(); 24 | NSAssert1(context, @"Could not generate context for layer %@", layer); 25 | CGContextSaveGState(context); 26 | [layer layoutIfNeeded]; 27 | [layer renderInContext:context]; 28 | CGContextRestoreGState(context); 29 | 30 | UIImage *snapshot = UIGraphicsGetImageFromCurrentImageContext(); 31 | UIGraphicsEndImageContext(); 32 | return snapshot; 33 | } 34 | 35 | + (UIImage *)fb_imageForViewLayer:(UIView *)view 36 | { 37 | [view layoutIfNeeded]; 38 | return [self fb_imageForLayer:view.layer]; 39 | } 40 | 41 | + (UIImage *)fb_imageForView:(UIView *)view 42 | { 43 | CGRect bounds = view.bounds; 44 | NSAssert1(CGRectGetWidth(bounds), @"Zero width for view %@", view); 45 | NSAssert1(CGRectGetHeight(bounds), @"Zero height for view %@", view); 46 | 47 | // If the input view is already a UIWindow, then just use that. Otherwise wrap in a window. 48 | UIWindow *window = [view isKindOfClass:[UIWindow class]] ? (UIWindow *)view : view.window; 49 | BOOL removeFromSuperview = NO; 50 | if (!window) { 51 | window = [[UIApplication sharedApplication] fb_strictKeyWindow]; 52 | } 53 | 54 | if (!view.window && view != window) { 55 | [window addSubview:view]; 56 | removeFromSuperview = YES; 57 | } 58 | 59 | UIGraphicsBeginImageContextWithOptions(bounds.size, NO, 0); 60 | [view layoutIfNeeded]; 61 | [view drawViewHierarchyInRect:view.bounds afterScreenUpdates:YES]; 62 | 63 | UIImage *snapshot = UIGraphicsGetImageFromCurrentImageContext(); 64 | UIGraphicsEndImageContext(); 65 | 66 | if (removeFromSuperview) { 67 | [view removeFromSuperview]; 68 | } 69 | 70 | return snapshot; 71 | } 72 | 73 | @end 74 | -------------------------------------------------------------------------------- /Example/Pods/FBSnapshotTestCase/FBSnapshotTestCase/Categories/UIImage+Diff.m: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gabriel Handford on 3/1/09. 3 | // Copyright 2009-2013. All rights reserved. 4 | // Created by John Boiles on 10/20/11. 5 | // Copyright (c) 2011. All rights reserved 6 | // Modified by Felix Schulze on 2/11/13. 7 | // Copyright 2013. All rights reserved. 8 | // 9 | // Permission is hereby granted, free of charge, to any person 10 | // obtaining a copy of this software and associated documentation 11 | // files (the "Software"), to deal in the Software without 12 | // restriction, including without limitation the rights to use, 13 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the 15 | // Software is furnished to do so, subject to the following 16 | // conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be 19 | // included in all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 23 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 25 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 26 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 27 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 28 | // OTHER DEALINGS IN THE SOFTWARE. 29 | // 30 | 31 | #import 32 | 33 | @implementation UIImage (Diff) 34 | 35 | - (UIImage *)fb_diffWithImage:(UIImage *)image 36 | { 37 | if (!image) { 38 | return nil; 39 | } 40 | CGSize imageSize = CGSizeMake(MAX(self.size.width, image.size.width), MAX(self.size.height, image.size.height)); 41 | UIGraphicsBeginImageContextWithOptions(imageSize, YES, 0); 42 | CGContextRef context = UIGraphicsGetCurrentContext(); 43 | [self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)]; 44 | CGContextSetAlpha(context, 0.5); 45 | CGContextBeginTransparencyLayer(context, NULL); 46 | [image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)]; 47 | CGContextSetBlendMode(context, kCGBlendModeDifference); 48 | CGContextSetFillColorWithColor(context,[UIColor whiteColor].CGColor); 49 | CGContextFillRect(context, CGRectMake(0, 0, self.size.width, self.size.height)); 50 | CGContextEndTransparencyLayer(context); 51 | UIImage *returnImage = UIGraphicsGetImageFromCurrentImageContext(); 52 | UIGraphicsEndImageContext(); 53 | return returnImage; 54 | } 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/ECAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECAppDelegate.m 3 | // ECPrivacyCheckTools 4 | // 5 | // Created by EchoZuo on 05/22/2020. 6 | // Copyright (c) 2020 EchoZuo. All rights reserved. 7 | // 8 | 9 | #import "ECAppDelegate.h" 10 | #import "ECViewController.h" 11 | 12 | @implementation ECAppDelegate 13 | 14 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 15 | { 16 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 17 | self.window.backgroundColor = [UIColor whiteColor]; 18 | 19 | [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent; 20 | 21 | ECViewController *ecVC = [[ECViewController alloc] init]; 22 | UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:ecVC]; 23 | self.window.rootViewController = nav; 24 | 25 | [self.window makeKeyAndVisible]; 26 | 27 | // Override point for customization after application launch. 28 | return YES; 29 | } 30 | 31 | - (void)applicationWillResignActive:(UIApplication *)application 32 | { 33 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 34 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 35 | } 36 | 37 | - (void)applicationDidEnterBackground:(UIApplication *)application 38 | { 39 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 40 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 41 | } 42 | 43 | - (void)applicationWillEnterForeground:(UIApplication *)application 44 | { 45 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 46 | } 47 | 48 | - (void)applicationDidBecomeActive:(UIApplication *)application 49 | { 50 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 51 | } 52 | 53 | - (void)applicationWillTerminate:(UIApplication *)application 54 | { 55 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 56 | } 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/Core/ECPrivacyCheckHealth.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckHealth.m 3 | // Expecta 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | 8 | #import "ECPrivacyCheckHealth.h" 9 | 10 | @implementation ECPrivacyCheckHealth 11 | 12 | + (void)callbackOnMainQueue:(dispatch_block_t)block { 13 | dispatch_async(dispatch_get_main_queue(), block); 14 | } 15 | 16 | + (ECHealthAuthorizationStatus)healthAuthorizationStatus { 17 | if ([HKHealthStore isHealthDataAvailable]) { 18 | // 以心率 HKQuantityTypeIdentifierHeartRate 为例 19 | HKQuantityType *heartRateType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate]; 20 | HKHealthStore *store = [[HKHealthStore alloc] init]; 21 | HKAuthorizationStatus status = [store authorizationStatusForType:heartRateType]; 22 | 23 | if (status == HKAuthorizationStatusNotDetermined) { 24 | return ECHealthAuthorizationStatusNotDetermined; 25 | } else if (status == HKAuthorizationStatusSharingDenied) { 26 | return ECHealthAuthorizationStatusDenied; 27 | } else { 28 | return ECHealthAuthorizationStatusAuthorized; 29 | } 30 | } else { 31 | return ECHealthAuthorizationStatusUnable; 32 | } 33 | } 34 | 35 | - (ECHealthAuthorizationStatus)healthAuthorizationStatus { 36 | return [[self class] healthAuthorizationStatus]; 37 | } 38 | 39 | + (void)requestHealthsAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler { 40 | ECHealthAuthorizationStatus status = [[self class] healthAuthorizationStatus]; 41 | 42 | if (status == ECHealthAuthorizationStatusNotDetermined) { 43 | // 以心率 HKQuantityTypeIdentifierHeartRate 为例 44 | HKQuantityType *heartRateType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate]; 45 | HKHealthStore *store = [[HKHealthStore alloc] init]; 46 | NSSet *typeSet = [NSSet setWithObject:heartRateType]; 47 | 48 | [store requestAuthorizationToShareTypes:typeSet readTypes:typeSet completion:^(BOOL success, NSError * _Nullable error) { 49 | [self callbackOnMainQueue:^{ 50 | if (completionHandler) { 51 | completionHandler(success); 52 | } 53 | }]; 54 | }]; 55 | 56 | } else { 57 | [self callbackOnMainQueue:^{ 58 | if (completionHandler) { 59 | completionHandler(status == ECHealthAuthorizationStatusAuthorized); 60 | } 61 | }]; 62 | } 63 | } 64 | 65 | - (void)requestHealthsAuthorizationWithCompletionHandler:(void (^)(BOOL))completionHandler { 66 | [[self class] requestHealthsAuthorizationWithCompletionHandler:completionHandler]; 67 | } 68 | 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ECPrivacyCheckTools_Tests/Pods-ECPrivacyCheckTools_Tests-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | BSD License 18 | 19 | For the FBSnapshotTestCase software 20 | 21 | Copyright (c) 2013, Facebook, Inc. 22 | All rights reserved. 23 | 24 | Redistribution and use in source and binary forms, with or without 25 | modification, are permitted provided that the following conditions are met: 26 | 27 | * Redistributions of source code must retain the above copyright notice, 28 | this list of conditions and the following disclaimer. 29 | * Redistributions in binary form must reproduce the above copyright notice, 30 | this list of conditions and the following disclaimer in the documentation 31 | and/or other materials provided with the distribution. 32 | * Neither the name Facebook nor the names of its contributors may be used to 33 | endorse or promote products derived from this software without specific 34 | prior written permission. 35 | 36 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 37 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 38 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 39 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 40 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 41 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 42 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 43 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 44 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 45 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 46 | 47 | License 48 | BSD 49 | Title 50 | FBSnapshotTestCase 51 | Type 52 | PSGroupSpecifier 53 | 54 | 55 | FooterText 56 | Generated by CocoaPods - https://cocoapods.org 57 | Title 58 | 59 | Type 60 | PSGroupSpecifier 61 | 62 | 63 | StringsTable 64 | Acknowledgements 65 | Title 66 | Acknowledgements 67 | 68 | 69 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/Core/ECPrivacyCheckMediaAndAppleMusic.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckMediaAndAppleMusic.m 3 | // ; 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | 8 | #import "ECPrivacyCheckMediaAndAppleMusic.h" 9 | 10 | @implementation ECPrivacyCheckMediaAndAppleMusic 11 | 12 | + (void)callbackOnMainQueue:(dispatch_block_t)block { 13 | dispatch_async(dispatch_get_main_queue(), block); 14 | } 15 | 16 | + (ECMediaAndAppleMusicAuthorizationStatus)mediaAndAppleMusicAuthorizationStatus { 17 | if (@available(iOS 9.3, *)) { 18 | SKCloudServiceAuthorizationStatus status = [SKCloudServiceController authorizationStatus]; 19 | 20 | if (status == SKCloudServiceAuthorizationStatusNotDetermined) { 21 | return ECMediaAndAppleMusicAuthorizationStatusNotDetermined; 22 | } else if (status == SKCloudServiceAuthorizationStatusRestricted) { 23 | return ECMediaAndAppleMusicAuthorizationStatusRestricted; 24 | } else if (status == SKCloudServiceAuthorizationStatusDenied) { 25 | return ECMediaAndAppleMusicAuthorizationStatusDenied; 26 | } else { 27 | return ECMediaAndAppleMusicAuthorizationStatusAuthorized; 28 | } 29 | } else { 30 | // Fallback on earlier versions 31 | // iOS 9.3 以下不支持 32 | return ECMediaAndAppleMusicAuthorizationStatusUnable; 33 | } 34 | } 35 | 36 | - (ECMediaAndAppleMusicAuthorizationStatus)mediaAndAppleMusicAuthorizationStatus { 37 | return [[self class] mediaAndAppleMusicAuthorizationStatus]; 38 | } 39 | 40 | + (void)requestMediaAndAppleMusicAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler { 41 | ECMediaAndAppleMusicAuthorizationStatus status = [[self class] mediaAndAppleMusicAuthorizationStatus]; 42 | 43 | if (status == ECMediaAndAppleMusicAuthorizationStatusNotDetermined) { 44 | 45 | if (@available(iOS 9.3, *)) { 46 | [SKCloudServiceController requestAuthorization:^(SKCloudServiceAuthorizationStatus status) { 47 | [self callbackOnMainQueue:^{ 48 | if (completionHandler) { 49 | completionHandler(status == SKCloudServiceAuthorizationStatusAuthorized); 50 | } 51 | }]; 52 | }]; 53 | } else { 54 | // Fallback on earlier versions 55 | [self callbackOnMainQueue:^{ 56 | if (completionHandler) { 57 | completionHandler(NO); 58 | } 59 | }]; 60 | } 61 | } else { 62 | [self callbackOnMainQueue:^{ 63 | if (completionHandler) { 64 | completionHandler(status == ECMediaAndAppleMusicAuthorizationStatusAuthorized); 65 | } 66 | }]; 67 | } 68 | } 69 | 70 | - (void)requestMediaAndAppleMusicAuthorizationWithCompletionHandler:(void (^)(BOOL))completionHandler { 71 | [[self class] requestMediaAndAppleMusicAuthorizationWithCompletionHandler:completionHandler]; 72 | } 73 | 74 | @end 75 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/Core/ECPrivacyCheckSpeechRecognition.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckSpeechRecognition.m 3 | // Expecta 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | 8 | #import "ECPrivacyCheckSpeechRecognition.h" 9 | 10 | @implementation ECPrivacyCheckSpeechRecognition 11 | 12 | + (void)callbackOnMainQueue:(dispatch_block_t)block { 13 | dispatch_async(dispatch_get_main_queue(), block); 14 | } 15 | 16 | + (ECSpeechRecognizerAuthorizationStatus)speechRecognitionAuthorizationStatus { 17 | if (@available(iOS 10.0, *)) { 18 | SFSpeechRecognizerAuthorizationStatus status = [SFSpeechRecognizer authorizationStatus]; 19 | 20 | if (status == SFSpeechRecognizerAuthorizationStatusNotDetermined) { 21 | return ECSpeechRecognizerAuthorizationStatusNotDetermined; 22 | } else if (status == SFSpeechRecognizerAuthorizationStatusDenied){ 23 | return ECSpeechRecognizerAuthorizationStatusDenied; 24 | } else if (status == SFSpeechRecognizerAuthorizationStatusRestricted) { 25 | return ECSpeechRecognizerAuthorizationStatusRestricted; 26 | } else { 27 | return ECSpeechRecognizerAuthorizationStatusAuthorized; 28 | } 29 | 30 | } else { 31 | // Fallback on earlier versions 32 | // iOS 10以下不支持 33 | return ECSpeechRecognizerAuthorizationStatusUnable; 34 | } 35 | } 36 | 37 | - (ECSpeechRecognizerAuthorizationStatus)speechRecognitionAuthorizationStatus { 38 | return [[self class] speechRecognitionAuthorizationStatus]; 39 | } 40 | 41 | + (void)requestSpeechRecognitionAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler { 42 | ECSpeechRecognizerAuthorizationStatus status = [[self class] speechRecognitionAuthorizationStatus]; 43 | 44 | if (status == ECSpeechRecognizerAuthorizationStatusNotDetermined) { 45 | 46 | if (@available(iOS 10.0, *)) { 47 | [SFSpeechRecognizer requestAuthorization:^(SFSpeechRecognizerAuthorizationStatus status) { 48 | [self callbackOnMainQueue:^{ 49 | if (completionHandler) { 50 | completionHandler(status == SFSpeechRecognizerAuthorizationStatusAuthorized); 51 | } 52 | }]; 53 | }]; 54 | } else { 55 | // Fallback on earlier versions 56 | [self callbackOnMainQueue:^{ 57 | if (completionHandler) { 58 | completionHandler(NO); 59 | } 60 | }]; 61 | } 62 | 63 | } else { 64 | [self callbackOnMainQueue:^{ 65 | if (completionHandler) { 66 | completionHandler(status == ECSpeechRecognizerAuthorizationStatusAuthorized); 67 | } 68 | }]; 69 | } 70 | } 71 | 72 | - (void)requestSpeechRecognitionAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler { 73 | [[self class] requestSpeechRecognitionAuthorizationWithCompletionHandler:completionHandler]; 74 | } 75 | 76 | 77 | @end 78 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/Core/ECPrivacyCheckHomeKit.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckHomeKit.m 3 | // Expecta 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | 8 | #import "ECPrivacyCheckHomeKit.h" 9 | 10 | 11 | @interface ECPrivacyCheckHomeKit () 12 | 13 | @property (nonatomic, strong) HMHomeManager *homeManager; 14 | 15 | @property (nonatomic, copy) ECHomeAccessCompletionHandler completionHandler; 16 | 17 | 18 | @end 19 | 20 | @implementation ECPrivacyCheckHomeKit 21 | 22 | + (void)callbackOnMainQueue:(dispatch_block_t)block { 23 | dispatch_async(dispatch_get_main_queue(), block); 24 | } 25 | 26 | - (void)callbackOnMainQueue:(dispatch_block_t)block { 27 | dispatch_async(dispatch_get_main_queue(), block); 28 | } 29 | 30 | + (void)requestHomeAccessWithCompletionHandler:(ECHomeAccessCompletionHandler)completionHandler { 31 | ECPrivacyCheckHomeKit *objc =[[ECPrivacyCheckHomeKit alloc] init]; 32 | [objc requestHomeAccessWithCompletionHandler:completionHandler]; 33 | } 34 | 35 | - (void)requestHomeAccessWithCompletionHandler:(ECHomeAccessCompletionHandler)completionHandler { 36 | self.completionHandler = completionHandler; 37 | 38 | HMHomeManager *homeManager = [[HMHomeManager alloc] init]; 39 | homeManager.delegate = self; 40 | } 41 | 42 | 43 | // MARK: - HMHomeManagerDelegate 44 | - (void)homeManagerDidUpdateHomes:(HMHomeManager *)manager { 45 | 46 | if (self.completionHandler) { 47 | if (manager.homes.count > 0) { 48 | 49 | NSLog(@"a home exists, so we have access."); 50 | self.completionHandler(YES, manager); 51 | } else { 52 | __weak HMHomeManager *weakHomeManager = manager; 53 | [manager addHomeWithName:@"Test Home" completionHandler:^(HMHome * _Nullable home, NSError * _Nullable error) { 54 | if (!error) { 55 | NSLog(@"we have access for home."); 56 | self.completionHandler(YES, weakHomeManager); 57 | } else { 58 | // consult HMError.h 59 | if (error.code == HMErrorCodeHomeAccessNotAuthorized) { 60 | // user denied permission 61 | NSLog(@"用户拒绝 ser denied permission"); 62 | self.completionHandler(NO, weakHomeManager); 63 | } else { 64 | NSLog(@"HOME_ERROR:%ld,%@",(long)error.code, error.localizedDescription); 65 | self.completionHandler(YES, weakHomeManager); 66 | } 67 | } 68 | 69 | if (home) { 70 | [weakHomeManager removeHome:home completionHandler:^(NSError * _Nullable error) { 71 | // do something with the result of removing the home... 72 | }]; 73 | } 74 | }]; 75 | } 76 | } else { 77 | NSAssert(self.completionHandler == nil, @"please check completionHandler is not nil."); 78 | } 79 | } 80 | 81 | 82 | @end 83 | -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "iPad Notifications-20@2x.png", 5 | "idiom" : "iphone", 6 | "scale" : "2x", 7 | "size" : "20x20" 8 | }, 9 | { 10 | "filename" : "iPhone Notification-20@3x.png", 11 | "idiom" : "iphone", 12 | "scale" : "3x", 13 | "size" : "20x20" 14 | }, 15 | { 16 | "filename" : "iPhone Settings-29@2x.png", 17 | "idiom" : "iphone", 18 | "scale" : "2x", 19 | "size" : "29x29" 20 | }, 21 | { 22 | "filename" : "iPhone Settings-29@3x.png", 23 | "idiom" : "iphone", 24 | "scale" : "3x", 25 | "size" : "29x29" 26 | }, 27 | { 28 | "filename" : "iPhone Spotlight-40@2x.png", 29 | "idiom" : "iphone", 30 | "scale" : "2x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "filename" : "iPhone Spotlight-40@3x.png", 35 | "idiom" : "iphone", 36 | "scale" : "3x", 37 | "size" : "40x40" 38 | }, 39 | { 40 | "filename" : "iPhone App-60@2x.png", 41 | "idiom" : "iphone", 42 | "scale" : "2x", 43 | "size" : "60x60" 44 | }, 45 | { 46 | "filename" : "iPhone App-60@3x.png", 47 | "idiom" : "iphone", 48 | "scale" : "3x", 49 | "size" : "60x60" 50 | }, 51 | { 52 | "filename" : "iPad Notifications-20.png", 53 | "idiom" : "ipad", 54 | "scale" : "1x", 55 | "size" : "20x20" 56 | }, 57 | { 58 | "filename" : "iPad Notifications-20@2x-1.png", 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "20x20" 62 | }, 63 | { 64 | "filename" : "iPad Settings-29.png", 65 | "idiom" : "ipad", 66 | "scale" : "1x", 67 | "size" : "29x29" 68 | }, 69 | { 70 | "filename" : "iPad Settings-29@2x.png", 71 | "idiom" : "ipad", 72 | "scale" : "2x", 73 | "size" : "29x29" 74 | }, 75 | { 76 | "filename" : "iPad Spotlight-40.png", 77 | "idiom" : "ipad", 78 | "scale" : "1x", 79 | "size" : "40x40" 80 | }, 81 | { 82 | "filename" : "iPad Spotlight-40@2x.png", 83 | "idiom" : "ipad", 84 | "scale" : "2x", 85 | "size" : "40x40" 86 | }, 87 | { 88 | "filename" : "iPad App-76.png", 89 | "idiom" : "ipad", 90 | "scale" : "1x", 91 | "size" : "76x76" 92 | }, 93 | { 94 | "filename" : "iPad App-76@2x.png", 95 | "idiom" : "ipad", 96 | "scale" : "2x", 97 | "size" : "76x76" 98 | }, 99 | { 100 | "filename" : "iPad Pro App-83.5@2x.png", 101 | "idiom" : "ipad", 102 | "scale" : "2x", 103 | "size" : "83.5x83.5" 104 | }, 105 | { 106 | "filename" : "App Store-1025.png", 107 | "idiom" : "ios-marketing", 108 | "scale" : "1x", 109 | "size" : "1024x1024" 110 | } 111 | ], 112 | "info" : { 113 | "author" : "xcode", 114 | "version" : 1 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/utils/ECAlert.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECAlert.m 3 | // ECPrivacyCheckTools_Example 4 | // 5 | // Created by EchoZuo on 2020/5/27. 6 | // Copyright © 2020 EchoZuo. All rights reserved. 7 | // 8 | 9 | #import "ECAlert.h" 10 | 11 | @implementation ECAlert 12 | 13 | + (void)showWithTitle:(NSString *)title message:(NSString *)message completion:(void(^)(NSInteger buttonIndex))completion cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitleArray:(NSArray *)otherButtonTitleArray { 14 | 15 | 16 | UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert]; 17 | 18 | int index = 0; 19 | 20 | if (cancelButtonTitle) { 21 | UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:cancelButtonTitle style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { 22 | if (completion) { 23 | completion(index); 24 | } 25 | }]; 26 | 27 | [alertController addAction:cancelAction]; 28 | 29 | index ++; 30 | } 31 | 32 | for (int i = 0; i < otherButtonTitleArray.count; i ++) { 33 | NSString *string = otherButtonTitleArray[i]; 34 | UIAlertAction *otherAction = [UIAlertAction actionWithTitle:string style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 35 | if (completion) { 36 | completion(i + index); 37 | } 38 | }]; 39 | [alertController addAction:otherAction]; 40 | } 41 | 42 | dispatch_async(dispatch_get_main_queue(), ^{ 43 | [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:alertController animated:YES completion:nil]; 44 | }); 45 | } 46 | 47 | 48 | + (void)showWithTitle:(NSString *)title message:(NSString *)message completion:(void(^)(NSInteger buttonIndex))completion cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSString *)otherButtonTitles, ... NS_REQUIRES_NIL_TERMINATION { 49 | 50 | NSMutableArray *array = [[NSMutableArray alloc] init]; 51 | va_list args; 52 | va_start(args, otherButtonTitles); 53 | for (NSString *str = otherButtonTitles; str != nil; str = va_arg(args, NSString*)) { 54 | [array addObject:str]; 55 | } 56 | va_end(args); 57 | 58 | [[self class] showWithTitle:title message:message completion:completion cancelButtonTitle:cancelButtonTitle otherButtonTitleArray:array]; 59 | } 60 | 61 | //按钮:取消、确定 62 | + (void)showWithMessage:(NSString *)message completion:(void(^)(NSInteger buttonIndex))completion { 63 | [self showWithTitle:@"" message:message completion:completion cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil]; 64 | } 65 | 66 | //按钮:确定 67 | + (void)showConfirmAlertWithMessage:(NSString *)message completion:(void(^)(NSInteger buttonIndex))completion { 68 | [self showWithTitle:@"" message:message completion:completion cancelButtonTitle:@"确定" otherButtonTitles:nil]; 69 | } 70 | 71 | //按钮:取消 72 | + (void)showCancelAlertWithMessage:(NSString *)message completion:(void(^)(NSInteger buttonIndex))completion { 73 | [self showWithTitle:@"" message:message completion:completion cancelButtonTitle:@"取消" otherButtonTitles:nil]; 74 | } 75 | 76 | @end 77 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/Core/ECPrivacyCheckMotionAndFitness.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckMotionAndFitness.m 3 | // Expecta 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | 8 | #import "ECPrivacyCheckMotionAndFitness.h" 9 | 10 | @implementation ECPrivacyCheckMotionAndFitness 11 | 12 | + (void)callbackOnMainQueue:(dispatch_block_t)block { 13 | dispatch_async(dispatch_get_main_queue(), block); 14 | } 15 | 16 | + (ECMotionAndFitnessAuthorizationStatus)motionAndFitnessAuthorizationStatus { 17 | if ([CMMotionActivityManager isActivityAvailable]) { 18 | CMAuthorizationStatus status = [CMMotionActivityManager authorizationStatus]; 19 | if (status == CMAuthorizationStatusNotDetermined) { 20 | return ECMotionAndFitnessAuthorizationStatusNotDetermined; 21 | } else if (status == CMAuthorizationStatusRestricted) { 22 | return ECMotionAndFitnessAuthorizationStatusRestricted; 23 | } else if (status == CMAuthorizationStatusDenied) { 24 | return ECMotionAndFitnessAuthorizationStatusDenied; 25 | } else { 26 | return ECMotionAndFitnessAuthorizationStatusAuthorized; 27 | } 28 | } else { 29 | return ECMotionAndFitnessAuthorizationStatusUnable; 30 | } 31 | } 32 | 33 | - (ECMotionAndFitnessAuthorizationStatus)motionAndFitnessAuthorizationStatus { 34 | return [[self class] motionAndFitnessAuthorizationStatus]; 35 | } 36 | 37 | + (void)requestMotionAndFitnessAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler { 38 | if (@available(iOS 11.0, *)) { 39 | ECMotionAndFitnessAuthorizationStatus status = [[self class] motionAndFitnessAuthorizationStatus]; 40 | if (status == ECMotionAndFitnessAuthorizationStatusNotDetermined) { 41 | __block CMMotionActivityManager *cmManager = [[CMMotionActivityManager alloc] init]; 42 | NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 43 | 44 | [cmManager startActivityUpdatesToQueue:queue withHandler:^(CMMotionActivity * _Nullable activity) { 45 | [cmManager stopActivityUpdates]; 46 | [self callbackOnMainQueue:^{ 47 | if (completionHandler) { 48 | completionHandler(YES); 49 | } 50 | }]; 51 | }]; 52 | } else { 53 | [self callbackOnMainQueue:^{ 54 | if (completionHandler) { 55 | completionHandler(status == ECMotionAndFitnessAuthorizationStatusAuthorized); 56 | } 57 | }]; 58 | } 59 | } else { 60 | // Fallback on earlier versions 61 | __block CMMotionActivityManager *cmManager = [[CMMotionActivityManager alloc] init]; 62 | NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 63 | 64 | [cmManager startActivityUpdatesToQueue:queue withHandler:^(CMMotionActivity * _Nullable activity) { 65 | [self callbackOnMainQueue:^{ 66 | if (completionHandler) { 67 | completionHandler(YES); 68 | } 69 | }]; 70 | }]; 71 | } 72 | } 73 | 74 | - (void)requestMotionAndFitnessAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler { 75 | [[self class] requestMotionAndFitnessAuthorizationWithCompletionHandler:completionHandler]; 76 | } 77 | 78 | 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools/ECPrivacyCheckTools-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | 隐私权限 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIcons 12 | 13 | CFBundleIcons~ipad 14 | 15 | CFBundleIdentifier 16 | $(PRODUCT_BUNDLE_IDENTIFIER) 17 | CFBundleInfoDictionaryVersion 18 | 6.0 19 | CFBundleName 20 | ${PRODUCT_NAME} 21 | CFBundlePackageType 22 | APPL 23 | CFBundleShortVersionString 24 | 1.0 25 | CFBundleSignature 26 | ???? 27 | CFBundleVersion 28 | 1.0 29 | LSRequiresIPhoneOS 30 | 31 | UILaunchStoryboardName 32 | LaunchScreen 33 | UIRequiredDeviceCapabilities 34 | 35 | armv7 36 | 37 | UISupportedInterfaceOrientations 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationLandscapeLeft 41 | UIInterfaceOrientationLandscapeRight 42 | 43 | UISupportedInterfaceOrientations~ipad 44 | 45 | UIInterfaceOrientationPortrait 46 | UIInterfaceOrientationPortraitUpsideDown 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | NSAppleMusicUsageDescription 51 | Add tracks to your music library. 52 | NSBluetoothPeripheralUsageDescription 53 | 若不允许,你将无法使用联机服务 54 | NSBluetoothAlwaysUsageDescription 55 | 若不允许,你将无法使用联机服务 56 | NSCalendarsUsageDescription 57 | 若不允许,你将无法使用添加日历功能 58 | NSCameraUsageDescription 59 | 若不允许,你将无法使用图片上传和识别功能 60 | NSContactsUsageDescription 61 | 通讯录信息仅用于查找联系人,并会得到严格保密 62 | NSHealthShareUsageDescription 63 | 若不允许,你将无法参与运动排行榜活动 64 | NSHealthUpdateUsageDescription 65 | 若不允许,你将无法参与运动排行榜活动 66 | NSHomeKitUsageDescription 67 | 若不允许,你将无法使用智能家居服务 68 | NSLocationAlwaysAndWhenInUseUsageDescription 69 | 我们需要获取你的定位权限以供完成查找附近商户功能 70 | NSLocationWhenInUseUsageDescription 71 | 我们需要获取你的定位权限以供完成查找附近商户功能 72 | NSMicrophoneUsageDescription 73 | 我们需要获取你的麦克风权限以供完成语音搜索功能 74 | NSMotionUsageDescription 75 | 我们需要获取你的运动权限以完成运动挑战赛功能 76 | NSPhotoLibraryAddUsageDescription 77 | 我们需要获取你的相册权限以完成图片上传和识别功能 78 | NSPhotoLibraryUsageDescription 79 | 我们需要获取你的相册权限以完成图片上传和识别功能 80 | NSRemindersUsageDescription 81 | 我们需要获取你的提醒事项权限以供添加提醒事项 82 | NSSiriUsageDescription 83 | 我们需要获取你的Siri权限以方便完成Siri建议功能 84 | NSSpeechRecognitionUsageDescription 85 | 我们需要获取你的语音识别功能已完成键盘语音识别输入功能 86 | NSVideoSubscriberAccountUsageDescription 87 | 我们需要获取你的TV权限 88 | 89 | 90 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/Core/ECPrivacyCheckBluetooth.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckBluetooth.m 3 | // Expecta 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | 8 | #import "ECPrivacyCheckBluetooth.h" 9 | 10 | @interface ECPrivacyCheckBluetooth () 11 | { 12 | dispatch_queue_t _bluetoothQueue; 13 | } 14 | 15 | @property (nonatomic,copy) void (^completionHandler)(ECCBAuthorizationState state); 16 | 17 | @end 18 | 19 | @implementation ECPrivacyCheckBluetooth 20 | 21 | - (void)callbackOnMainQueue:(dispatch_block_t)block { 22 | dispatch_async(dispatch_get_main_queue(), block); 23 | } 24 | 25 | - (void)requestBluetoothAuthorizationWithCompletionHandler:(void(^)(ECCBAuthorizationState state))completionHandler { 26 | self.completionHandler = completionHandler; 27 | // CBCentralManagerOptionShowPowerAlertKey:提示蓝牙开关未打开时会弹出警告框 28 | // CBCentralManagerOptionRestoreIdentifierKey:一个指定中央管理器的uid(和蓝牙程序进入后台有关) 29 | _bluetoothQueue = dispatch_queue_create("ECPrivacyCheckBluetooth Queue", DISPATCH_QUEUE_SERIAL); 30 | self.cbcManager = [[CBCentralManager alloc] initWithDelegate:self queue:_bluetoothQueue options:@{CBCentralManagerOptionShowPowerAlertKey:@true}]; 31 | } 32 | 33 | // MARK: - CBCentralManagerDelegate 34 | - (void)centralManagerDidUpdateState:(CBCentralManager *)central { 35 | [self callbackOnMainQueue:^{ 36 | if (self.completionHandler) { 37 | if (@available(iOS 10.0, *)) { 38 | if (central.state == CBManagerStateResetting) { 39 | self.completionHandler(ECCBAuthorizationStateResetting); 40 | 41 | } else if (central.state == CBManagerStateUnsupported) { 42 | self.completionHandler(ECCBAuthorizationStateUnsupported); 43 | 44 | } else if (central.state == CBManagerStateUnauthorized) { 45 | self.completionHandler(ECCBAuthorizationStateUnsupported); 46 | 47 | } else if (central.state == CBManagerStatePoweredOff) { 48 | self.completionHandler(ECCBAuthorizationStatePoweredOff); 49 | 50 | } else if (central.state == CBManagerStatePoweredOn) { 51 | self.completionHandler(ECCBAuthorizationStatePoweredOn); 52 | 53 | } else { 54 | // CBManagerStateUnknown 55 | self.completionHandler(ECCBAuthorizationStateUnknown); 56 | } 57 | } else { 58 | // Fallback on earlier versions 59 | if (central.state == CBCentralManagerStateUnknown) { 60 | self.completionHandler(ECCBAuthorizationStateResetting); 61 | 62 | } else if (central.state == CBCentralManagerStateUnsupported) { 63 | self.completionHandler(ECCBAuthorizationStateUnsupported); 64 | 65 | } else if (central.state == CBCentralManagerStateUnauthorized) { 66 | self.completionHandler(ECCBAuthorizationStateUnsupported); 67 | 68 | } else if (central.state == CBCentralManagerStatePoweredOff) { 69 | self.completionHandler(ECCBAuthorizationStatePoweredOff); 70 | 71 | } else if (central.state == CBCentralManagerStatePoweredOn) { 72 | self.completionHandler(ECCBAuthorizationStatePoweredOn); 73 | 74 | } else { 75 | // CBCentralManagerStateUnknown 76 | self.completionHandler(ECCBAuthorizationStateUnknown); 77 | } 78 | } 79 | } 80 | }]; 81 | } 82 | 83 | @end 84 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/Core/ECPrivacyCheckContacts.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckContacts.m 3 | // Expecta 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | 8 | #import "ECPrivacyCheckContacts.h" 9 | 10 | @implementation ECPrivacyCheckContacts 11 | 12 | 13 | + (void)callbackOnMainQueue:(dispatch_block_t)block { 14 | dispatch_async(dispatch_get_main_queue(), block); 15 | } 16 | 17 | + (ECContactsAuthorizationStatus)contactsAuthorizationStatus { 18 | if (@available(iOS 9.0, *)) { 19 | CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts]; 20 | switch (status) { 21 | case CNAuthorizationStatusNotDetermined: { 22 | return ECContactsAuthorizationStatusNotDetermined; 23 | } 24 | break; 25 | case CNAuthorizationStatusRestricted: { 26 | return ECContactsAuthorizationStatusRestricted; 27 | } 28 | break; 29 | case CNAuthorizationStatusDenied: { 30 | return ECContactsAuthorizationStatusDenied; 31 | } 32 | break; 33 | case CNAuthorizationStatusAuthorized: { 34 | return ECContactsAuthorizationStatusAuthorized; 35 | } 36 | default: 37 | break; 38 | } 39 | } else { 40 | // Fallback on earlier versions 41 | ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus(); 42 | switch (status) { 43 | case kABAuthorizationStatusNotDetermined: { 44 | return ECContactsAuthorizationStatusNotDetermined; 45 | } 46 | break; 47 | case kABAuthorizationStatusRestricted: { 48 | return ECContactsAuthorizationStatusRestricted; 49 | } 50 | break; 51 | case kABAuthorizationStatusDenied: { 52 | return ECContactsAuthorizationStatusDenied; 53 | } 54 | break; 55 | case kABAuthorizationStatusAuthorized: { 56 | return ECContactsAuthorizationStatusAuthorized; 57 | } 58 | default: 59 | break; 60 | } 61 | } 62 | } 63 | 64 | - (ECContactsAuthorizationStatus)contactsAuthorizationStatus { 65 | return [[self class] contactsAuthorizationStatus]; 66 | } 67 | 68 | + (void)requestContactsAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler { 69 | ECContactsAuthorizationStatus status = [[self class] contactsAuthorizationStatus]; 70 | if (status == ECContactsAuthorizationStatusNotDetermined) { 71 | if (@available(iOS 9.0, *)) { 72 | CNContactStore *contactStore = [[CNContactStore alloc] init]; 73 | [contactStore requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) { 74 | [self callbackOnMainQueue:^{ 75 | if (completionHandler) { 76 | completionHandler(granted); 77 | } 78 | }]; 79 | }]; 80 | } else { 81 | // Fallback on earlier versions 82 | ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL); 83 | ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) { 84 | [self callbackOnMainQueue:^{ 85 | if (completionHandler) { 86 | completionHandler(granted); 87 | } 88 | }]; 89 | }); 90 | } 91 | 92 | } else { 93 | [self callbackOnMainQueue:^{ 94 | if (completionHandler) { 95 | completionHandler(status == ECContactsAuthorizationStatusAuthorized); 96 | } 97 | }]; 98 | } 99 | } 100 | 101 | - (void)requestContactsAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler { 102 | [[self class] requestContactsAuthorizationWithCompletionHandler:completionHandler]; 103 | } 104 | 105 | 106 | @end 107 | -------------------------------------------------------------------------------- /Example/Pods/FBSnapshotTestCase/README.md: -------------------------------------------------------------------------------- 1 | FBSnapshotTestCase 2 | ====================== 3 | 4 | [![Build Status](https://travis-ci.org/facebook/ios-snapshot-test-case.svg)](https://travis-ci.org/facebook/ios-snapshot-test-case) [![Cocoa Pod Version](https://cocoapod-badges.herokuapp.com/v/FBSnapshotTestCase/badge.svg)](http://cocoadocs.org/docsets/FBSnapshotTestCase/) 5 | 6 | What it does 7 | ------------ 8 | 9 | A "snapshot test case" takes a configured `UIView` or `CALayer` and uses the 10 | `renderInContext:` method to get an image snapshot of its contents. It 11 | compares this snapshot to a "reference image" stored in your source code 12 | repository and fails the test if the two images don't match. 13 | 14 | Why? 15 | ---- 16 | 17 | At Facebook we write a lot of UI code. As you might imagine, each type of 18 | feed story is rendered using a subclass of `UIView`. There are a lot of edge 19 | cases that we want to handle correctly: 20 | 21 | - What if there is more text than can fit in the space available? 22 | - What if an image doesn't match the size of an image view? 23 | - What should the highlighted state look like? 24 | 25 | It's straightforward to test logic code, but less obvious how you should test 26 | views. You can do a lot of rectangle asserts, but these are hard to understand 27 | or visualize. Looking at an image diff shows you exactly what changed and how 28 | it will look to users. 29 | 30 | We developed `FBSnapshotTestCase` to make snapshot tests easy. 31 | 32 | Installation with CocoaPods 33 | --------------------------- 34 | 35 | 1. Add the following lines to your Podfile: 36 | 37 | ``` 38 | target "Tests" do 39 | pod 'FBSnapshotTestCase' 40 | end 41 | ``` 42 | 43 | If you support iOS 7 use `FBSnapshotTestCase/Core` instead, which doesn't contain Swift support. 44 | 45 | Replace "Tests" with the name of your test project. 46 | 47 | 2. There are [three ways](https://github.com/facebook/ios-snapshot-test-case/blob/master/FBSnapshotTestCase/FBSnapshotTestCase.h#L19-L29) of setting reference image directories, the recommended one is to define `FB_REFERENCE_IMAGE_DIR` in your scheme. This should point to the directory where you want reference images to be stored. At Facebook, we normally use this: 48 | 49 | |Name|Value| 50 | |:---|:----| 51 | |`FB_REFERENCE_IMAGE_DIR`|`$(SOURCE_ROOT)/$(PROJECT_NAME)Tests/ReferenceImages`| 52 | 53 | 54 | ![](FBSnapshotTestCaseDemo/Scheme_FB_REFERENCE_IMAGE_DIR.png) 55 | 56 | Creating a snapshot test 57 | ------------------------ 58 | 59 | 1. Subclass `FBSnapshotTestCase` instead of `XCTestCase`. 60 | 2. From within your test, use `FBSnapshotVerifyView`. 61 | 3. Run the test once with `self.recordMode = YES;` in the test's `-setUp` 62 | method. (This creates the reference images on disk.) 63 | 4. Remove the line enabling record mode and run the test. 64 | 65 | Features 66 | -------- 67 | 68 | - Automatically names reference images on disk according to test class and 69 | selector. 70 | - Prints a descriptive error message to the console on failure. (Bonus: 71 | failure message includes a one-line command to see an image diff if 72 | you have [Kaleidoscope](http://www.kaleidoscopeapp.com) installed.) 73 | - Supply an optional "identifier" if you want to perform multiple snapshots 74 | in a single test method. 75 | - Support for `CALayer` via `FBSnapshotVerifyLayer`. 76 | - `usesDrawViewHierarchyInRect` to handle cases like `UIVisualEffect`, `UIAppearance` and Size Classes. 77 | - `isDeviceAgnostic` to allow appending the device model (`iPhone`, `iPad`, `iPod Touch`, etc), OS version and screen size to the images (allowing to have multiple tests for the same «snapshot» for different `OS`s and devices). 78 | 79 | Notes 80 | ----- 81 | 82 | Your unit test must be an "application test", not a "logic test." (That is, it 83 | must be run within the Simulator so that it has access to UIKit.) In Xcode 5 84 | and later new projects only offer application tests, but older projects will 85 | have separate targets for the two types. 86 | 87 | Authors 88 | ------- 89 | 90 | `FBSnapshotTestCase` was written at Facebook by 91 | [Jonathan Dann](https://facebook.com/j.p.dann) with significant contributions by 92 | [Todd Krabach](https://facebook.com/toddkrabach). 93 | 94 | License 95 | ------- 96 | 97 | `FBSnapshotTestCase` is BSD-licensed. See `LICENSE`. 98 | -------------------------------------------------------------------------------- /Example/ECPrivacyCheckTools.xcodeproj/xcshareddata/xcschemes/ECPrivacyCheckTools-Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 42 | 48 | 49 | 50 | 51 | 52 | 62 | 64 | 70 | 71 | 72 | 73 | 79 | 81 | 87 | 88 | 89 | 90 | 92 | 93 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/Core/ECPrivacyCheckLocationServices.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckLocationServices.m 3 | // Expecta 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | 8 | #import "ECPrivacyCheckLocationServices.h" 9 | 10 | @interface ECPrivacyCheckLocationServices () 11 | 12 | @property (nonatomic, strong) CLLocationManager *locationManager; 13 | @property (nonatomic,copy) void (^kCLCallBackBlock)(CLAuthorizationStatus status); 14 | 15 | 16 | @end 17 | 18 | @implementation ECPrivacyCheckLocationServices 19 | 20 | - (void)callbackOnMainQueue:(dispatch_block_t)block { 21 | dispatch_async(dispatch_get_main_queue(), block); 22 | } 23 | 24 | + (ECLocationAuthorizationStatus)locationAuthorizationStatus { 25 | if (![CLLocationManager locationServicesEnabled]) { 26 | return ECLocationAuthorizationStatusUnable; 27 | } 28 | 29 | CLAuthorizationStatus status = [CLLocationManager authorizationStatus]; 30 | switch (status) { 31 | case kCLAuthorizationStatusNotDetermined: { 32 | return ECLocationAuthorizationStatusNotDetermined; 33 | } 34 | break; 35 | case kCLAuthorizationStatusRestricted: { 36 | return ECLocationAuthorizationStatusRestricted; 37 | } 38 | break; 39 | case kCLAuthorizationStatusDenied: { 40 | return ECLocationAuthorizationStatusDenied; 41 | } 42 | break; 43 | case kCLAuthorizationStatusAuthorizedAlways: { 44 | return ECLocationAuthorizationStatusAuthorizedAlways; 45 | } 46 | break; 47 | case kCLAuthorizationStatusAuthorizedWhenInUse: { 48 | return ECLocationAuthorizationStatusAuthorizedWhenInUse; 49 | } 50 | default: 51 | break; 52 | } 53 | } 54 | 55 | - (ECLocationAuthorizationStatus)locationAuthorizationStatus { 56 | return [[self class] locationAuthorizationStatus]; 57 | } 58 | 59 | - (void)requestLocationAuthorizationWithCompletionHandler:(void (^)(ECLocationAuthorizationStatus))completionHandler { 60 | __block ECLocationAuthorizationStatus lbsStatus = [[self class] locationAuthorizationStatus]; 61 | if (lbsStatus == ECLocationAuthorizationStatusNotDetermined) { 62 | self.locationManager = [[CLLocationManager alloc] init]; 63 | self.locationManager.delegate = self; 64 | [self.locationManager requestAlwaysAuthorization]; 65 | 66 | __weak typeof (self)weakSelf = self; 67 | [self setKCLCallBackBlock:^(CLAuthorizationStatus status) { 68 | [weakSelf callbackOnMainQueue:^{ 69 | switch (status) { 70 | case kCLAuthorizationStatusNotDetermined: { 71 | lbsStatus = ECLocationAuthorizationStatusNotDetermined; 72 | } 73 | break; 74 | case kCLAuthorizationStatusRestricted: { 75 | lbsStatus = ECLocationAuthorizationStatusRestricted; 76 | } 77 | break; 78 | case kCLAuthorizationStatusDenied: { 79 | lbsStatus = ECLocationAuthorizationStatusDenied; 80 | } 81 | break; 82 | case kCLAuthorizationStatusAuthorizedAlways: { 83 | lbsStatus = ECLocationAuthorizationStatusAuthorizedAlways; 84 | } 85 | break; 86 | case kCLAuthorizationStatusAuthorizedWhenInUse: { 87 | lbsStatus = ECLocationAuthorizationStatusAuthorizedWhenInUse; 88 | } 89 | default: 90 | break; 91 | } 92 | 93 | if (completionHandler) { 94 | completionHandler(lbsStatus); 95 | } 96 | }]; 97 | }]; 98 | 99 | } else { 100 | [self callbackOnMainQueue:^{ 101 | if (completionHandler) { 102 | completionHandler(lbsStatus); 103 | } 104 | }]; 105 | } 106 | } 107 | 108 | // MARK: - CLLocationManagerDelegate 109 | - (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status { 110 | if (self.kCLCallBackBlock) { 111 | self.kCLCallBackBlock(status); 112 | } 113 | } 114 | 115 | 116 | @end 117 | -------------------------------------------------------------------------------- /ECPrivacyCheckTools/Classes/ECPrivacyCheckGatherTool.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECPrivacyCheckGatherTool.h 3 | // Pods 4 | // 5 | // Created by EchoZuo on 2020/4/26. 6 | // 7 | // 8 | /// 9 | /// 常用隐私权限检测集合工具,可以直接导入项目中使用。包含:定位服务、照片、相机、通讯录 10 | /// 支持 iOS 8.0+ 11 | /// 12 | /// Common privacy permission check collection tools, include LocationServices,Photos,Camera,Contacts 13 | /// Support iOS 8.0+ 14 | 15 | 16 | #import 17 | #import 18 | #import 19 | #import 20 | #import 21 | #import 22 | 23 | 24 | /** 授权状态 25 | * ECAuthorizationStatusUnable:不支持或不可用 26 | * ECAuthorizationStatusNotDetermined:用户从未进行过授权等处理,首次访问相应内容会提示用户进行授权 27 | * ECAuthorizationStatusRestricted:应用没有相关权限,且当前用户无法改变这个权限,比如:家长控制 28 | * ECAuthorizationStatusDenied:用户拒绝 29 | * ECAuthorizationStatusAuthorized:已授权 30 | */ 31 | typedef NS_ENUM(NSInteger, ECAuthorizationStatus) { 32 | ECAuthorizationStatusUnable = -1, 33 | ECAuthorizationStatusNotDetermined = 0, 34 | ECAuthorizationStatusRestricted, 35 | ECAuthorizationStatusDenied, 36 | ECAuthorizationStatusAuthorized 37 | }; 38 | 39 | /** 定位授权状态 40 | * 41 | * ECLBSAuthorizationStatusUnable:不支持或不可用 42 | * ECLBSAuthorizationStatusNotDetermined:用户从未进行过授权等处理,首次访问相应内容会提示用户进行授权 43 | * ECLBSAuthorizationStatusRestricted:应用没有相关权限,且当前用户无法改变这个权限,比如:家长控制 44 | * ECLBSAuthorizationStatusDenied:用户拒绝 45 | * ECLBSAuthorizationStatusAuthorizedAlways:一直允许获取定位 46 | * ECLBSAuthorizationStatusAuthorizedWhenInUse:在使用时允许定位 47 | * ECLBSAuthorizationStatusAuthorized:已废弃,在iOS2.0~8.0使用,> iOS 8.0 请使用 ECLBSAuthorizationStatusAuthorizedAlways: 一直允许获取定位 48 | */ 49 | typedef NS_ENUM(NSInteger, ECLBSAuthorizationStatus) { 50 | ECLBSAuthorizationStatusUnable = -1, 51 | ECLBSAuthorizationStatusNotDetermined = 0, 52 | ECLBSAuthorizationStatusRestricted, 53 | ECLBSAuthorizationStatusDenied, 54 | ECLBSAuthorizationStatusAuthorizedAlways, 55 | ECLBSAuthorizationStatusAuthorizedWhenInUse, 56 | ECLBSAuthorizationStatusAuthorized API_DEPRECATED("Use ECLBSAuthorizationStatusAuthorizedAlways", ios(2.0, 8.0)) = ECLBSAuthorizationStatusAuthorizedAlways 57 | }; 58 | 59 | 60 | 61 | NS_ASSUME_NONNULL_BEGIN 62 | 63 | @interface ECPrivacyCheckGatherTool : NSObject 64 | 65 | // MARK: - 定位服务 LocationServices 66 | 67 | /// 检查定位权限状态:仅检查权限,不主动请求权限 68 | + (ECLBSAuthorizationStatus)locationAuthorizationStatus; 69 | 70 | /// 检查定位权限状态:仅检查权限,不主动请求权限 71 | - (ECLBSAuthorizationStatus)locationAuthorizationStatus; 72 | 73 | /// 请求定位权限 74 | /// @param completionHandler completionHandler 75 | - (void)requestLocationAuthorizationWithCompletionHandler:(void(^)(ECLBSAuthorizationStatus status))completionHandler; 76 | 77 | 78 | // MARK: - 照片 Photos 79 | 80 | /// 检查相册权限状态:仅检查权限,不主动请求权限 81 | + (ECAuthorizationStatus)photosAuthorizationStatus; 82 | 83 | /// 检查相册权限状态:仅检查权限,不主动请求权限 84 | - (ECAuthorizationStatus)photosAuthorizationStatus; 85 | 86 | /// 请求相册权限 87 | /// @param completionHandler completionHandler 88 | + (void)requestPhotosAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler; 89 | 90 | /// 请求相册权限 91 | /// @param completionHandler completionHandler 92 | - (void)requestPhotosAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler; 93 | 94 | 95 | // MARK: - 相机 Camera 96 | 97 | /// 检查相机权限状态:仅检查权限,不主动请求权限 98 | + (ECAuthorizationStatus)cameraAuthorizationStatus; 99 | 100 | /// 检查相机权限状态:仅检查权限,不主动请求权限 101 | - (ECAuthorizationStatus)cameraAuthorizationStatus; 102 | 103 | /// 请求相机权限 104 | /// @param completionHandler completionHandler 105 | + (void)requestCameraAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler; 106 | 107 | /// 请求相机权限 108 | /// @param completionHandler completionHandler 109 | - (void)requestCameraAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler; 110 | 111 | 112 | // MARK: - 通讯录 Contacts 113 | 114 | /// 检查通讯录权限状态:仅检查权限,不主动请求权限 115 | + (ECAuthorizationStatus)contactsAuthorizationStatus; 116 | 117 | /// 检查通讯录权限状态:仅检查权限,不主动请求权限 118 | - (ECAuthorizationStatus)contactsAuthorizationStatus; 119 | 120 | /// 请求通讯录权限 121 | /// @param completionHandler completionHandler 122 | + (void)requestContactsAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler; 123 | 124 | /// 请求通讯录权限 125 | /// @param completionHandler completionHandler 126 | - (void)requestContactsAuthorizationWithCompletionHandler:(void(^)(BOOL granted))completionHandler; 127 | 128 | @end 129 | 130 | NS_ASSUME_NONNULL_END 131 | -------------------------------------------------------------------------------- /Example/Pods/FBSnapshotTestCase/FBSnapshotTestCase/Categories/UIImage+Compare.m: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gabriel Handford on 3/1/09. 3 | // Copyright 2009-2013. All rights reserved. 4 | // Created by John Boiles on 10/20/11. 5 | // Copyright (c) 2011. All rights reserved 6 | // Modified by Felix Schulze on 2/11/13. 7 | // Copyright 2013. All rights reserved. 8 | // 9 | // Permission is hereby granted, free of charge, to any person 10 | // obtaining a copy of this software and associated documentation 11 | // files (the "Software"), to deal in the Software without 12 | // restriction, including without limitation the rights to use, 13 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the 15 | // Software is furnished to do so, subject to the following 16 | // conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be 19 | // included in all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 23 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 25 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 26 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 27 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 28 | // OTHER DEALINGS IN THE SOFTWARE. 29 | // 30 | 31 | #import 32 | 33 | // This makes debugging much more fun 34 | typedef union { 35 | uint32_t raw; 36 | unsigned char bytes[4]; 37 | struct { 38 | char red; 39 | char green; 40 | char blue; 41 | char alpha; 42 | } __attribute__ ((packed)) pixels; 43 | } FBComparePixel; 44 | 45 | @implementation UIImage (Compare) 46 | 47 | - (BOOL)fb_compareWithImage:(UIImage *)image tolerance:(CGFloat)tolerance 48 | { 49 | NSAssert(CGSizeEqualToSize(self.size, image.size), @"Images must be same size."); 50 | 51 | CGSize referenceImageSize = CGSizeMake(CGImageGetWidth(self.CGImage), CGImageGetHeight(self.CGImage)); 52 | CGSize imageSize = CGSizeMake(CGImageGetWidth(image.CGImage), CGImageGetHeight(image.CGImage)); 53 | 54 | // The images have the equal size, so we could use the smallest amount of bytes because of byte padding 55 | size_t minBytesPerRow = MIN(CGImageGetBytesPerRow(self.CGImage), CGImageGetBytesPerRow(image.CGImage)); 56 | size_t referenceImageSizeBytes = referenceImageSize.height * minBytesPerRow; 57 | void *referenceImagePixels = calloc(1, referenceImageSizeBytes); 58 | void *imagePixels = calloc(1, referenceImageSizeBytes); 59 | 60 | if (!referenceImagePixels || !imagePixels) { 61 | free(referenceImagePixels); 62 | free(imagePixels); 63 | return NO; 64 | } 65 | 66 | CGContextRef referenceImageContext = CGBitmapContextCreate(referenceImagePixels, 67 | referenceImageSize.width, 68 | referenceImageSize.height, 69 | CGImageGetBitsPerComponent(self.CGImage), 70 | minBytesPerRow, 71 | CGImageGetColorSpace(self.CGImage), 72 | (CGBitmapInfo)kCGImageAlphaPremultipliedLast 73 | ); 74 | CGContextRef imageContext = CGBitmapContextCreate(imagePixels, 75 | imageSize.width, 76 | imageSize.height, 77 | CGImageGetBitsPerComponent(image.CGImage), 78 | minBytesPerRow, 79 | CGImageGetColorSpace(image.CGImage), 80 | (CGBitmapInfo)kCGImageAlphaPremultipliedLast 81 | ); 82 | 83 | if (!referenceImageContext || !imageContext) { 84 | CGContextRelease(referenceImageContext); 85 | CGContextRelease(imageContext); 86 | free(referenceImagePixels); 87 | free(imagePixels); 88 | return NO; 89 | } 90 | 91 | CGContextDrawImage(referenceImageContext, CGRectMake(0, 0, referenceImageSize.width, referenceImageSize.height), self.CGImage); 92 | CGContextDrawImage(imageContext, CGRectMake(0, 0, imageSize.width, imageSize.height), image.CGImage); 93 | 94 | CGContextRelease(referenceImageContext); 95 | CGContextRelease(imageContext); 96 | 97 | BOOL imageEqual = YES; 98 | 99 | // Do a fast compare if we can 100 | if (tolerance == 0) { 101 | imageEqual = (memcmp(referenceImagePixels, imagePixels, referenceImageSizeBytes) == 0); 102 | } else { 103 | // Go through each pixel in turn and see if it is different 104 | const NSInteger pixelCount = referenceImageSize.width * referenceImageSize.height; 105 | 106 | FBComparePixel *p1 = referenceImagePixels; 107 | FBComparePixel *p2 = imagePixels; 108 | 109 | NSInteger numDiffPixels = 0; 110 | for (int n = 0; n < pixelCount; ++n) { 111 | // If this pixel is different, increment the pixel diff count and see 112 | // if we have hit our limit. 113 | if (p1->raw != p2->raw) { 114 | numDiffPixels ++; 115 | 116 | CGFloat percent = (CGFloat)numDiffPixels / pixelCount; 117 | if (percent > tolerance) { 118 | imageEqual = NO; 119 | break; 120 | } 121 | } 122 | 123 | p1++; 124 | p2++; 125 | } 126 | } 127 | 128 | free(referenceImagePixels); 129 | free(imagePixels); 130 | 131 | return imageEqual; 132 | } 133 | 134 | @end 135 | -------------------------------------------------------------------------------- /Example/Pods/FBSnapshotTestCase/FBSnapshotTestCase/SwiftSupport.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #if swift(>=3) 12 | public extension FBSnapshotTestCase { 13 | public func FBSnapshotVerifyView(_ view: UIView, identifier: String = "", suffixes: NSOrderedSet = FBSnapshotTestCaseDefaultSuffixes(), tolerance: CGFloat = 0, file: StaticString = #file, line: UInt = #line) { 14 | FBSnapshotVerifyViewOrLayer(view, identifier: identifier, suffixes: suffixes, tolerance: tolerance, file: file, line: line) 15 | } 16 | 17 | public func FBSnapshotVerifyLayer(_ layer: CALayer, identifier: String = "", suffixes: NSOrderedSet = FBSnapshotTestCaseDefaultSuffixes(), tolerance: CGFloat = 0, file: StaticString = #file, line: UInt = #line) { 18 | FBSnapshotVerifyViewOrLayer(layer, identifier: identifier, suffixes: suffixes, tolerance: tolerance, file: file, line: line) 19 | } 20 | 21 | private func FBSnapshotVerifyViewOrLayer(_ viewOrLayer: AnyObject, identifier: String = "", suffixes: NSOrderedSet = FBSnapshotTestCaseDefaultSuffixes(), tolerance: CGFloat = 0, file: StaticString = #file, line: UInt = #line) { 22 | let envReferenceImageDirectory = self.getReferenceImageDirectory(withDefault: FB_REFERENCE_IMAGE_DIR) 23 | var error: NSError? 24 | var comparisonSuccess = false 25 | 26 | if let envReferenceImageDirectory = envReferenceImageDirectory { 27 | for suffix in suffixes { 28 | let referenceImagesDirectory = "\(envReferenceImageDirectory)\(suffix)" 29 | if viewOrLayer.isKind(of: UIView.self) { 30 | do { 31 | try compareSnapshot(of: viewOrLayer as! UIView, referenceImagesDirectory: referenceImagesDirectory, identifier: identifier, tolerance: tolerance) 32 | comparisonSuccess = true 33 | } catch let error1 as NSError { 34 | error = error1 35 | comparisonSuccess = false 36 | } 37 | } else if viewOrLayer.isKind(of: CALayer.self) { 38 | do { 39 | try compareSnapshot(of: viewOrLayer as! CALayer, referenceImagesDirectory: referenceImagesDirectory, identifier: identifier, tolerance: tolerance) 40 | comparisonSuccess = true 41 | } catch let error1 as NSError { 42 | error = error1 43 | comparisonSuccess = false 44 | } 45 | } else { 46 | assertionFailure("Only UIView and CALayer classes can be snapshotted") 47 | } 48 | 49 | assert(recordMode == false, message: "Test ran in record mode. Reference image is now saved. Disable record mode to perform an actual snapshot comparison!", file: file, line: line) 50 | 51 | if comparisonSuccess || recordMode { 52 | break 53 | } 54 | 55 | assert(comparisonSuccess, message: "Snapshot comparison failed: \(error)", file: file, line: line) 56 | } 57 | } else { 58 | XCTFail("Missing value for referenceImagesDirectory - Set FB_REFERENCE_IMAGE_DIR as Environment variable in your scheme.") 59 | } 60 | } 61 | 62 | func assert(_ assertion: Bool, message: String, file: StaticString, line: UInt) { 63 | if !assertion { 64 | XCTFail(message, file: file, line: line) 65 | } 66 | } 67 | } 68 | #else 69 | public extension FBSnapshotTestCase { 70 | public func FBSnapshotVerifyView(view: UIView, identifier: String = "", suffixes: NSOrderedSet = FBSnapshotTestCaseDefaultSuffixes(), tolerance: CGFloat = 0, file: StaticString = #file, line: UInt = #line) { 71 | FBSnapshotVerifyViewOrLayer(view, identifier: identifier, suffixes: suffixes, tolerance: tolerance, file: file, line: line) 72 | } 73 | 74 | public func FBSnapshotVerifyLayer(layer: CALayer, identifier: String = "", suffixes: NSOrderedSet = FBSnapshotTestCaseDefaultSuffixes(), tolerance: CGFloat = 0, file: StaticString = #file, line: UInt = #line) { 75 | FBSnapshotVerifyViewOrLayer(layer, identifier: identifier, suffixes: suffixes, tolerance: tolerance, file: file, line: line) 76 | } 77 | 78 | private func FBSnapshotVerifyViewOrLayer(viewOrLayer: AnyObject, identifier: String = "", suffixes: NSOrderedSet = FBSnapshotTestCaseDefaultSuffixes(), tolerance: CGFloat = 0, file: StaticString = #file, line: UInt = #line) { 79 | let envReferenceImageDirectory = self.getReferenceImageDirectoryWithDefault(FB_REFERENCE_IMAGE_DIR) 80 | var error: NSError? 81 | var comparisonSuccess = false 82 | 83 | if let envReferenceImageDirectory = envReferenceImageDirectory { 84 | for suffix in suffixes { 85 | let referenceImagesDirectory = "\(envReferenceImageDirectory)\(suffix)" 86 | if viewOrLayer.isKindOfClass(UIView) { 87 | do { 88 | try compareSnapshotOfView(viewOrLayer as! UIView, referenceImagesDirectory: referenceImagesDirectory, identifier: identifier, tolerance: tolerance) 89 | comparisonSuccess = true 90 | } catch let error1 as NSError { 91 | error = error1 92 | comparisonSuccess = false 93 | } 94 | } else if viewOrLayer.isKindOfClass(CALayer) { 95 | do { 96 | try compareSnapshotOfLayer(viewOrLayer as! CALayer, referenceImagesDirectory: referenceImagesDirectory, identifier: identifier, tolerance: tolerance) 97 | comparisonSuccess = true 98 | } catch let error1 as NSError { 99 | error = error1 100 | comparisonSuccess = false 101 | } 102 | } else { 103 | assertionFailure("Only UIView and CALayer classes can be snapshotted") 104 | } 105 | 106 | assert(recordMode == false, message: "Test ran in record mode. Reference image is now saved. Disable record mode to perform an actual snapshot comparison!", file: file, line: line) 107 | 108 | if comparisonSuccess || recordMode { 109 | break 110 | } 111 | 112 | assert(comparisonSuccess, message: "Snapshot comparison failed: \(error)", file: file, line: line) 113 | } 114 | } else { 115 | XCTFail("Missing value for referenceImagesDirectory - Set FB_REFERENCE_IMAGE_DIR as Environment variable in your scheme.") 116 | } 117 | } 118 | 119 | func assert(assertion: Bool, message: String, file: StaticString, line: UInt) { 120 | if !assertion { 121 | XCTFail(message, file: file, line: line) 122 | } 123 | } 124 | } 125 | #endif 126 | -------------------------------------------------------------------------------- /Example/Pods/FBSnapshotTestCase/FBSnapshotTestCase/FBSnapshotTestController.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #import 12 | #import 13 | 14 | typedef NS_ENUM(NSInteger, FBSnapshotTestControllerErrorCode) { 15 | FBSnapshotTestControllerErrorCodeUnknown, 16 | FBSnapshotTestControllerErrorCodeNeedsRecord, 17 | FBSnapshotTestControllerErrorCodePNGCreationFailed, 18 | FBSnapshotTestControllerErrorCodeImagesDifferentSizes, 19 | FBSnapshotTestControllerErrorCodeImagesDifferent, 20 | }; 21 | /** 22 | Errors returned by the methods of FBSnapshotTestController use this domain. 23 | */ 24 | extern NSString *const FBSnapshotTestControllerErrorDomain; 25 | 26 | /** 27 | Errors returned by the methods of FBSnapshotTestController sometimes contain this key in the `userInfo` dictionary. 28 | */ 29 | extern NSString *const FBReferenceImageFilePathKey; 30 | 31 | /** 32 | Errors returned by the methods of FBSnapshotTestController sometimes contain this key in the `userInfo` dictionary. 33 | */ 34 | extern NSString *const FBReferenceImageKey; 35 | 36 | /** 37 | Errors returned by the methods of FBSnapshotTestController sometimes contain this key in the `userInfo` dictionary. 38 | */ 39 | extern NSString *const FBCapturedImageKey; 40 | 41 | /** 42 | Errors returned by the methods of FBSnapshotTestController sometimes contain this key in the `userInfo` dictionary. 43 | */ 44 | extern NSString *const FBDiffedImageKey; 45 | 46 | /** 47 | Provides the heavy-lifting for FBSnapshotTestCase. It loads and saves images, along with performing the actual pixel- 48 | by-pixel comparison of images. 49 | Instances are initialized with the test class, and directories to read and write to. 50 | */ 51 | @interface FBSnapshotTestController : NSObject 52 | 53 | /** 54 | Record snapshots. 55 | */ 56 | @property (readwrite, nonatomic, assign) BOOL recordMode; 57 | 58 | /** 59 | When @c YES appends the name of the device model and OS to the snapshot file name. 60 | The default value is @c NO. 61 | */ 62 | @property (readwrite, nonatomic, assign, getter=isDeviceAgnostic) BOOL deviceAgnostic; 63 | 64 | /** 65 | Uses drawViewHierarchyInRect:afterScreenUpdates: to draw the image instead of renderInContext: 66 | */ 67 | @property (readwrite, nonatomic, assign) BOOL usesDrawViewHierarchyInRect; 68 | 69 | /** 70 | The directory in which referfence images are stored. 71 | */ 72 | @property (readwrite, nonatomic, copy) NSString *referenceImagesDirectory; 73 | 74 | /** 75 | @param testClass The subclass of FBSnapshotTestCase that is using this controller. 76 | @returns An instance of FBSnapshotTestController. 77 | */ 78 | - (instancetype)initWithTestClass:(Class)testClass; 79 | 80 | /** 81 | Designated initializer. 82 | @param testName The name of the tests. 83 | @returns An instance of FBSnapshotTestController. 84 | */ 85 | - (instancetype)initWithTestName:(NSString *)testName; 86 | 87 | /** 88 | Performs the comparison of the layer. 89 | @param layer The Layer to snapshot. 90 | @param selector The test method being run. 91 | @param identifier An optional identifier, used is there are muliptle snapshot tests in a given -test method. 92 | @param error An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc). 93 | @returns YES if the comparison (or saving of the reference image) succeeded. 94 | */ 95 | - (BOOL)compareSnapshotOfLayer:(CALayer *)layer 96 | selector:(SEL)selector 97 | identifier:(NSString *)identifier 98 | error:(NSError **)errorPtr; 99 | 100 | /** 101 | Performs the comparison of the view. 102 | @param view The view to snapshot. 103 | @param selector The test method being run. 104 | @param identifier An optional identifier, used is there are muliptle snapshot tests in a given -test method. 105 | @param error An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc). 106 | @returns YES if the comparison (or saving of the reference image) succeeded. 107 | */ 108 | - (BOOL)compareSnapshotOfView:(UIView *)view 109 | selector:(SEL)selector 110 | identifier:(NSString *)identifier 111 | error:(NSError **)errorPtr; 112 | 113 | /** 114 | Performs the comparison of a view or layer. 115 | @param view The view or layer to snapshot. 116 | @param selector The test method being run. 117 | @param identifier An optional identifier, used is there are muliptle snapshot tests in a given -test method. 118 | @param tolerance The percentage of pixels that can differ and still be considered 'identical' 119 | @param error An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc). 120 | @returns YES if the comparison (or saving of the reference image) succeeded. 121 | */ 122 | - (BOOL)compareSnapshotOfViewOrLayer:(id)viewOrLayer 123 | selector:(SEL)selector 124 | identifier:(NSString *)identifier 125 | tolerance:(CGFloat)tolerance 126 | error:(NSError **)errorPtr; 127 | 128 | /** 129 | Loads a reference image. 130 | @param selector The test method being run. 131 | @param identifier The optional identifier, used when multiple images are tested in a single -test method. 132 | @param errorPtr An error, if this methods returns nil, the error will be something useful. 133 | @returns An image. 134 | */ 135 | - (UIImage *)referenceImageForSelector:(SEL)selector 136 | identifier:(NSString *)identifier 137 | error:(NSError **)errorPtr; 138 | 139 | /** 140 | Performs a pixel-by-pixel comparison of the two images with an allowable margin of error. 141 | @param referenceImage The reference (correct) image. 142 | @param image The image to test against the reference. 143 | @param tolerance The percentage of pixels that can differ and still be considered 'identical' 144 | @param errorPtr An error that indicates why the comparison failed if it does. 145 | @returns YES if the comparison succeeded and the images are the same(ish). 146 | */ 147 | - (BOOL)compareReferenceImage:(UIImage *)referenceImage 148 | toImage:(UIImage *)image 149 | tolerance:(CGFloat)tolerance 150 | error:(NSError **)errorPtr; 151 | 152 | /** 153 | Saves the reference image and the test image to `failedOutputDirectory`. 154 | @param referenceImage The reference (correct) image. 155 | @param testImage The image to test against the reference. 156 | @param selector The test method being run. 157 | @param identifier The optional identifier, used when multiple images are tested in a single -test method. 158 | @param errorPtr An error that indicates why the comparison failed if it does. 159 | @returns YES if the save succeeded. 160 | */ 161 | - (BOOL)saveFailedReferenceImage:(UIImage *)referenceImage 162 | testImage:(UIImage *)testImage 163 | selector:(SEL)selector 164 | identifier:(NSString *)identifier 165 | error:(NSError **)errorPtr; 166 | @end 167 | -------------------------------------------------------------------------------- /Example/Pods/FBSnapshotTestCase/FBSnapshotTestCase/FBSnapshotTestCase.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #import 12 | #import 13 | 14 | @implementation FBSnapshotTestCase 15 | { 16 | FBSnapshotTestController *_snapshotController; 17 | } 18 | 19 | #pragma mark - Overrides 20 | 21 | - (void)setUp 22 | { 23 | [super setUp]; 24 | _snapshotController = [[FBSnapshotTestController alloc] initWithTestName:NSStringFromClass([self class])]; 25 | } 26 | 27 | - (void)tearDown 28 | { 29 | _snapshotController = nil; 30 | [super tearDown]; 31 | } 32 | 33 | - (BOOL)recordMode 34 | { 35 | return _snapshotController.recordMode; 36 | } 37 | 38 | - (void)setRecordMode:(BOOL)recordMode 39 | { 40 | NSAssert1(_snapshotController, @"%s cannot be called before [super setUp]", __FUNCTION__); 41 | _snapshotController.recordMode = recordMode; 42 | } 43 | 44 | - (BOOL)isDeviceAgnostic 45 | { 46 | return _snapshotController.deviceAgnostic; 47 | } 48 | 49 | - (void)setDeviceAgnostic:(BOOL)deviceAgnostic 50 | { 51 | NSAssert1(_snapshotController, @"%s cannot be called before [super setUp]", __FUNCTION__); 52 | _snapshotController.deviceAgnostic = deviceAgnostic; 53 | } 54 | 55 | - (BOOL)usesDrawViewHierarchyInRect 56 | { 57 | return _snapshotController.usesDrawViewHierarchyInRect; 58 | } 59 | 60 | - (void)setUsesDrawViewHierarchyInRect:(BOOL)usesDrawViewHierarchyInRect 61 | { 62 | NSAssert1(_snapshotController, @"%s cannot be called before [super setUp]", __FUNCTION__); 63 | _snapshotController.usesDrawViewHierarchyInRect = usesDrawViewHierarchyInRect; 64 | } 65 | 66 | #pragma mark - Public API 67 | 68 | - (NSString *)snapshotVerifyViewOrLayer:(id)viewOrLayer 69 | identifier:(NSString *)identifier 70 | suffixes:(NSOrderedSet *)suffixes 71 | tolerance:(CGFloat)tolerance 72 | { 73 | if (nil == viewOrLayer) { 74 | return @"Object to be snapshotted must not be nil"; 75 | } 76 | NSString *referenceImageDirectory = [self getReferenceImageDirectoryWithDefault:(@ FB_REFERENCE_IMAGE_DIR)]; 77 | if (referenceImageDirectory == nil) { 78 | return @"Missing value for referenceImagesDirectory - Set FB_REFERENCE_IMAGE_DIR as Environment variable in your scheme."; 79 | } 80 | if (suffixes.count == 0) { 81 | return [NSString stringWithFormat:@"Suffixes set cannot be empty %@", suffixes]; 82 | } 83 | 84 | BOOL testSuccess = NO; 85 | NSError *error = nil; 86 | NSMutableArray *errors = [NSMutableArray array]; 87 | 88 | if (self.recordMode) { 89 | NSString *referenceImagesDirectory = [NSString stringWithFormat:@"%@%@", referenceImageDirectory, suffixes.firstObject]; 90 | BOOL referenceImageSaved = [self _compareSnapshotOfViewOrLayer:viewOrLayer referenceImagesDirectory:referenceImagesDirectory identifier:(identifier) tolerance:tolerance error:&error]; 91 | if (!referenceImageSaved) { 92 | [errors addObject:error]; 93 | } 94 | } else { 95 | for (NSString *suffix in suffixes) { 96 | NSString *referenceImagesDirectory = [NSString stringWithFormat:@"%@%@", referenceImageDirectory, suffix]; 97 | BOOL referenceImageAvailable = [self referenceImageRecordedInDirectory:referenceImagesDirectory identifier:(identifier) error:&error]; 98 | 99 | if (referenceImageAvailable) { 100 | BOOL comparisonSuccess = [self _compareSnapshotOfViewOrLayer:viewOrLayer referenceImagesDirectory:referenceImagesDirectory identifier:identifier tolerance:tolerance error:&error]; 101 | [errors removeAllObjects]; 102 | if (comparisonSuccess) { 103 | testSuccess = YES; 104 | break; 105 | } else { 106 | [errors addObject:error]; 107 | } 108 | } else { 109 | [errors addObject:error]; 110 | } 111 | } 112 | } 113 | 114 | if (!testSuccess) { 115 | return [NSString stringWithFormat:@"Snapshot comparison failed: %@", errors.firstObject]; 116 | } 117 | if (self.recordMode) { 118 | return @"Test ran in record mode. Reference image is now saved. Disable record mode to perform an actual snapshot comparison!"; 119 | } 120 | 121 | return nil; 122 | } 123 | 124 | - (BOOL)compareSnapshotOfLayer:(CALayer *)layer 125 | referenceImagesDirectory:(NSString *)referenceImagesDirectory 126 | identifier:(NSString *)identifier 127 | tolerance:(CGFloat)tolerance 128 | error:(NSError **)errorPtr 129 | { 130 | return [self _compareSnapshotOfViewOrLayer:layer 131 | referenceImagesDirectory:referenceImagesDirectory 132 | identifier:identifier 133 | tolerance:tolerance 134 | error:errorPtr]; 135 | } 136 | 137 | - (BOOL)compareSnapshotOfView:(UIView *)view 138 | referenceImagesDirectory:(NSString *)referenceImagesDirectory 139 | identifier:(NSString *)identifier 140 | tolerance:(CGFloat)tolerance 141 | error:(NSError **)errorPtr 142 | { 143 | return [self _compareSnapshotOfViewOrLayer:view 144 | referenceImagesDirectory:referenceImagesDirectory 145 | identifier:identifier 146 | tolerance:tolerance 147 | error:errorPtr]; 148 | } 149 | 150 | - (BOOL)referenceImageRecordedInDirectory:(NSString *)referenceImagesDirectory 151 | identifier:(NSString *)identifier 152 | error:(NSError **)errorPtr 153 | { 154 | NSAssert1(_snapshotController, @"%s cannot be called before [super setUp]", __FUNCTION__); 155 | _snapshotController.referenceImagesDirectory = referenceImagesDirectory; 156 | UIImage *referenceImage = [_snapshotController referenceImageForSelector:self.invocation.selector 157 | identifier:identifier 158 | error:errorPtr]; 159 | 160 | return (referenceImage != nil); 161 | } 162 | 163 | - (NSString *)getReferenceImageDirectoryWithDefault:(NSString *)dir 164 | { 165 | NSString *envReferenceImageDirectory = [NSProcessInfo processInfo].environment[@"FB_REFERENCE_IMAGE_DIR"]; 166 | if (envReferenceImageDirectory) { 167 | return envReferenceImageDirectory; 168 | } 169 | if (dir && dir.length > 0) { 170 | return dir; 171 | } 172 | return [[NSBundle bundleForClass:self.class].resourcePath stringByAppendingPathComponent:@"ReferenceImages"]; 173 | } 174 | 175 | 176 | #pragma mark - Private API 177 | 178 | - (BOOL)_compareSnapshotOfViewOrLayer:(id)viewOrLayer 179 | referenceImagesDirectory:(NSString *)referenceImagesDirectory 180 | identifier:(NSString *)identifier 181 | tolerance:(CGFloat)tolerance 182 | error:(NSError **)errorPtr 183 | { 184 | _snapshotController.referenceImagesDirectory = referenceImagesDirectory; 185 | return [_snapshotController compareSnapshotOfViewOrLayer:viewOrLayer 186 | selector:self.invocation.selector 187 | identifier:identifier 188 | tolerance:tolerance 189 | error:errorPtr]; 190 | } 191 | 192 | @end 193 | -------------------------------------------------------------------------------- /Example/Pods/FBSnapshotTestCase/FBSnapshotTestCase/FBSnapshotTestCase.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #import 12 | #import 13 | 14 | #import 15 | 16 | #import 17 | 18 | #import 19 | 20 | /* 21 | There are three ways of setting reference image directories. 22 | 23 | 1. Set the preprocessor macro FB_REFERENCE_IMAGE_DIR to a double quoted 24 | c-string with the path. 25 | 2. Set an environment variable named FB_REFERENCE_IMAGE_DIR with the path. This 26 | takes precedence over the preprocessor macro to allow for run-time override. 27 | 3. Keep everything unset, which will cause the reference images to be looked up 28 | inside the bundle holding the current test, in the 29 | Resources/ReferenceImages_* directories. 30 | */ 31 | #ifndef FB_REFERENCE_IMAGE_DIR 32 | #define FB_REFERENCE_IMAGE_DIR "" 33 | #endif 34 | 35 | /** 36 | Similar to our much-loved XCTAssert() macros. Use this to perform your test. No need to write an explanation, though. 37 | @param view The view to snapshot 38 | @param identifier An optional identifier, used if there are multiple snapshot tests in a given -test method. 39 | @param suffixes An NSOrderedSet of strings for the different suffixes 40 | @param tolerance The percentage of pixels that can differ and still count as an 'identical' view 41 | */ 42 | #define FBSnapshotVerifyViewWithOptions(view__, identifier__, suffixes__, tolerance__) \ 43 | FBSnapshotVerifyViewOrLayerWithOptions(View, view__, identifier__, suffixes__, tolerance__) 44 | 45 | #define FBSnapshotVerifyView(view__, identifier__) \ 46 | FBSnapshotVerifyViewWithOptions(view__, identifier__, FBSnapshotTestCaseDefaultSuffixes(), 0) 47 | 48 | 49 | /** 50 | Similar to our much-loved XCTAssert() macros. Use this to perform your test. No need to write an explanation, though. 51 | @param layer The layer to snapshot 52 | @param identifier An optional identifier, used if there are multiple snapshot tests in a given -test method. 53 | @param suffixes An NSOrderedSet of strings for the different suffixes 54 | @param tolerance The percentage of pixels that can differ and still count as an 'identical' layer 55 | */ 56 | #define FBSnapshotVerifyLayerWithOptions(layer__, identifier__, suffixes__, tolerance__) \ 57 | FBSnapshotVerifyViewOrLayerWithOptions(Layer, layer__, identifier__, suffixes__, tolerance__) 58 | 59 | #define FBSnapshotVerifyLayer(layer__, identifier__) \ 60 | FBSnapshotVerifyLayerWithOptions(layer__, identifier__, FBSnapshotTestCaseDefaultSuffixes(), 0) 61 | 62 | 63 | #define FBSnapshotVerifyViewOrLayerWithOptions(what__, viewOrLayer__, identifier__, suffixes__, tolerance__) \ 64 | { \ 65 | NSString *errorDescription = [self snapshotVerifyViewOrLayer:viewOrLayer__ identifier:identifier__ suffixes:suffixes__ tolerance:tolerance__]; \ 66 | BOOL noErrors = (errorDescription == nil); \ 67 | XCTAssertTrue(noErrors, @"%@", errorDescription); \ 68 | } 69 | 70 | 71 | /** 72 | The base class of view snapshotting tests. If you have small UI component, it's often easier to configure it in a test 73 | and compare an image of the view to a reference image that write lots of complex layout-code tests. 74 | 75 | In order to flip the tests in your subclass to record the reference images set @c recordMode to @c YES. 76 | 77 | @attention When recording, the reference image directory should be explicitly 78 | set, otherwise the images may be written to somewhere inside the 79 | simulator directory. 80 | 81 | For example: 82 | @code 83 | - (void)setUp 84 | { 85 | [super setUp]; 86 | self.recordMode = YES; 87 | } 88 | @endcode 89 | */ 90 | @interface FBSnapshotTestCase : XCTestCase 91 | 92 | /** 93 | When YES, the test macros will save reference images, rather than performing an actual test. 94 | */ 95 | @property (readwrite, nonatomic, assign) BOOL recordMode; 96 | 97 | /** 98 | When @c YES appends the name of the device model and OS to the snapshot file name. 99 | The default value is @c NO. 100 | */ 101 | @property (readwrite, nonatomic, assign, getter=isDeviceAgnostic) BOOL deviceAgnostic; 102 | 103 | /** 104 | When YES, renders a snapshot of the complete view hierarchy as visible onscreen. 105 | There are several things that do not work if renderInContext: is used. 106 | - UIVisualEffect #70 107 | - UIAppearance #91 108 | - Size Classes #92 109 | 110 | @attention If the view does't belong to a UIWindow, it will create one and add the view as a subview. 111 | */ 112 | @property (readwrite, nonatomic, assign) BOOL usesDrawViewHierarchyInRect; 113 | 114 | - (void)setUp NS_REQUIRES_SUPER; 115 | - (void)tearDown NS_REQUIRES_SUPER; 116 | 117 | /** 118 | Performs the comparison or records a snapshot of the layer if recordMode is YES. 119 | @param viewOrLayer The UIView or CALayer to snapshot 120 | @param identifier An optional identifier, used if there are multiple snapshot tests in a given -test method. 121 | @param suffixes An NSOrderedSet of strings for the different suffixes 122 | @param tolerance The percentage difference to still count as identical - 0 mean pixel perfect, 1 means I don't care 123 | @returns nil if the comparison (or saving of the reference image) succeeded. Otherwise it contains an error description. 124 | */ 125 | - (NSString *)snapshotVerifyViewOrLayer:(id)viewOrLayer 126 | identifier:(NSString *)identifier 127 | suffixes:(NSOrderedSet *)suffixes 128 | tolerance:(CGFloat)tolerance; 129 | 130 | /** 131 | Performs the comparison or records a snapshot of the layer if recordMode is YES. 132 | @param layer The Layer to snapshot 133 | @param referenceImagesDirectory The directory in which reference images are stored. 134 | @param identifier An optional identifier, used if there are multiple snapshot tests in a given -test method. 135 | @param tolerance The percentage difference to still count as identical - 0 mean pixel perfect, 1 means I don't care 136 | @param errorPtr An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc). 137 | @returns YES if the comparison (or saving of the reference image) succeeded. 138 | */ 139 | - (BOOL)compareSnapshotOfLayer:(CALayer *)layer 140 | referenceImagesDirectory:(NSString *)referenceImagesDirectory 141 | identifier:(NSString *)identifier 142 | tolerance:(CGFloat)tolerance 143 | error:(NSError **)errorPtr; 144 | 145 | /** 146 | Performs the comparison or records a snapshot of the view if recordMode is YES. 147 | @param view The view to snapshot 148 | @param referenceImagesDirectory The directory in which reference images are stored. 149 | @param identifier An optional identifier, used if there are multiple snapshot tests in a given -test method. 150 | @param tolerance The percentage difference to still count as identical - 0 mean pixel perfect, 1 means I don't care 151 | @param errorPtr An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc). 152 | @returns YES if the comparison (or saving of the reference image) succeeded. 153 | */ 154 | - (BOOL)compareSnapshotOfView:(UIView *)view 155 | referenceImagesDirectory:(NSString *)referenceImagesDirectory 156 | identifier:(NSString *)identifier 157 | tolerance:(CGFloat)tolerance 158 | error:(NSError **)errorPtr; 159 | 160 | /** 161 | Checks if reference image with identifier based name exists in the reference images directory. 162 | @param referenceImagesDirectory The directory in which reference images are stored. 163 | @param identifier An optional identifier, used if there are multiple snapshot tests in a given -test method. 164 | @param errorPtr An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc). 165 | @returns YES if reference image exists. 166 | */ 167 | - (BOOL)referenceImageRecordedInDirectory:(NSString *)referenceImagesDirectory 168 | identifier:(NSString *)identifier 169 | error:(NSError **)errorPtr; 170 | 171 | /** 172 | Returns the reference image directory. 173 | 174 | Helper function used to implement the assert macros. 175 | 176 | @param dir directory to use if environment variable not specified. Ignored if null or empty. 177 | */ 178 | - (NSString *)getReferenceImageDirectoryWithDefault:(NSString *)dir; 179 | 180 | @end 181 | --------------------------------------------------------------------------------