├── .clang-format ├── .github ├── ISSUE_TEMPLATE │ ├── config.yml │ └── issue_report.md └── workflows │ ├── check.yml │ ├── google-utilities.yml │ └── test_coverage.yml ├── .gitignore ├── .ruby-version ├── .swiftformat ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Gemfile ├── Gemfile.lock ├── GoogleUtilities.podspec ├── GoogleUtilities ├── AppDelegateSwizzler │ ├── GULAppDelegateSwizzler.m │ ├── GULSceneDelegateSwizzler.m │ ├── Internal │ │ ├── GULAppDelegateSwizzler_Private.h │ │ └── GULSceneDelegateSwizzler_Private.h │ ├── Public │ │ └── GoogleUtilities │ │ │ ├── GULAppDelegateSwizzler.h │ │ │ ├── GULApplication.h │ │ │ └── GULSceneDelegateSwizzler.h │ ├── README.md │ └── Resources │ │ └── PrivacyInfo.xcprivacy ├── Common │ └── GULLoggerCodes.h ├── Environment │ ├── GULAppEnvironmentUtil.m │ ├── NetworkInfo │ │ └── GULNetworkInfo.m │ ├── Public │ │ └── GoogleUtilities │ │ │ ├── GULAppEnvironmentUtil.h │ │ │ ├── GULKeychainStorage.h │ │ │ ├── GULKeychainUtils.h │ │ │ └── GULNetworkInfo.h │ ├── Resources │ │ └── PrivacyInfo.xcprivacy │ └── SecureStorage │ │ ├── GULKeychainStorage.m │ │ └── GULKeychainUtils.m ├── Logger │ ├── GULLogger.m │ ├── Public │ │ └── GoogleUtilities │ │ │ ├── GULLogger.h │ │ │ └── GULLoggerLevel.h │ └── Resources │ │ └── PrivacyInfo.xcprivacy ├── MethodSwizzler │ ├── GULSwizzler.m │ ├── Public │ │ └── GoogleUtilities │ │ │ ├── GULOriginalIMPConvenienceMacros.h │ │ │ └── GULSwizzler.h │ └── Resources │ │ └── PrivacyInfo.xcprivacy ├── NSData+zlib │ ├── GULNSData+zlib.m │ ├── Public │ │ └── GoogleUtilities │ │ │ └── GULNSData+zlib.h │ └── Resources │ │ └── PrivacyInfo.xcprivacy ├── Network │ ├── GULMutableDictionary.m │ ├── GULNetwork.m │ ├── GULNetworkConstants.m │ ├── GULNetworkInternal.h │ ├── GULNetworkURLSession.m │ ├── Public │ │ └── GoogleUtilities │ │ │ ├── GULMutableDictionary.h │ │ │ ├── GULNetwork.h │ │ │ ├── GULNetworkConstants.h │ │ │ ├── GULNetworkLoggerProtocol.h │ │ │ ├── GULNetworkMessageCode.h │ │ │ └── GULNetworkURLSession.h │ └── Resources │ │ └── PrivacyInfo.xcprivacy ├── Privacy │ ├── Empty.swift │ └── Resources │ │ └── PrivacyInfo.xcprivacy ├── Reachability │ ├── GULReachabilityChecker+Internal.h │ ├── GULReachabilityChecker.m │ ├── GULReachabilityMessageCode.h │ ├── Public │ │ └── GoogleUtilities │ │ │ └── GULReachabilityChecker.h │ └── Resources │ │ └── PrivacyInfo.xcprivacy ├── SwizzlerTestHelpers │ ├── GULRuntimeClassDiff.h │ ├── GULRuntimeClassDiff.m │ ├── GULRuntimeClassSnapshot.h │ ├── GULRuntimeClassSnapshot.m │ ├── GULRuntimeDiff.h │ ├── GULRuntimeDiff.m │ ├── GULRuntimeSnapshot.h │ ├── GULRuntimeSnapshot.m │ ├── GULRuntimeStateHelper.h │ ├── GULRuntimeStateHelper.m │ ├── GULSwizzler+Unswizzle.m │ ├── GULSwizzlingCache.h │ ├── GULSwizzlingCache.m │ ├── GULSwizzlingCache_Private.h │ └── Public │ │ └── GoogleUtilities │ │ └── GULSwizzler+Unswizzle.h ├── Tests │ ├── SwiftUnit │ │ └── GULAppEnvironmentUtilTest.swift │ └── Unit │ │ ├── Environment │ │ ├── GULAppEnvironmentUtilTest.m │ │ └── GULKeychainStorageTests.m │ │ ├── Logger │ │ └── GULLoggerTest.m │ │ ├── Network │ │ ├── GULMutableDictionaryTest.m │ │ ├── GULNetworkTest.m │ │ └── third_party │ │ │ ├── GTMHTTPServer.h │ │ │ ├── GTMHTTPServer.m │ │ │ └── LICENSE │ │ ├── Reachability │ │ └── GULReachabilityCheckerTest.m │ │ ├── Shared │ │ └── URLSession │ │ │ ├── FIRURLSessionOCMockStub.h │ │ │ └── FIRURLSessionOCMockStub.m │ │ ├── Swizzler │ │ ├── GULAppDelegateSwizzlerTest.m │ │ ├── GULRuntimeClassDiffTests.m │ │ ├── GULRuntimeClassSnapshotTests.m │ │ ├── GULRuntimeDiffTests.m │ │ ├── GULRuntimeSnapshotTests.m │ │ ├── GULRuntimeStateHelperTests.m │ │ ├── GULSceneDelegateSwizzlerTest.m │ │ ├── GULSwizzlerInheritedMethodsSwizzlingTest.m │ │ ├── GULSwizzlerTest.m │ │ └── GULSwizzlingCacheTest.m │ │ ├── UserDefaults │ │ └── GULUserDefaultsTests.m │ │ └── Utils │ │ ├── GULTestKeychain.h │ │ └── GULTestKeychain.m └── UserDefaults │ ├── GULUserDefaults.m │ ├── Public │ └── GoogleUtilities │ │ └── GULUserDefaults.h │ └── Resources │ └── PrivacyInfo.xcprivacy ├── LICENSE ├── Mintfile ├── Package.swift ├── README.md ├── SwiftPMTests ├── objc-import-test │ ├── objc-header.m │ └── objc-module.m └── swift-test │ └── main.swift ├── setup-scripts.sh └── third_party └── IsAppEncrypted ├── IsAppEncrypted.m ├── LICENSE └── Public └── IsAppEncrypted.h /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Google 2 | ColumnLimit: 100 3 | BinPackParameters: false 4 | AllowAllParametersOfDeclarationOnNextLine: true 5 | ObjCSpaceBeforeProtocolList: true 6 | SpacesInContainerLiterals: true 7 | PointerAlignment: Right 8 | AllowShortFunctionsOnASingleLine: None 9 | IncludeBlocks: Preserve 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Google Utilities 4 | url: https://github.com/firebase/firebase-ios-sdk/issues/new/choose 5 | about: Google Utilities is not supported for direct usage. Please file with the product library that depends on Google Utilities. 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🐞 Internal Issue 3 | about: Googlers may file issues here or to track with [Firebase](https://github.com/firebase/firebase-ios-sdk/issues/new/choose) 4 | --- 5 | 9 | -------------------------------------------------------------------------------- /.github/workflows/check.yml: -------------------------------------------------------------------------------- 1 | name: check 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: main 7 | 8 | concurrency: 9 | group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} 10 | cancel-in-progress: true 11 | 12 | jobs: 13 | check: 14 | runs-on: macos-latest 15 | env: 16 | MINT_PATH: ${{ github.workspace }}/mint 17 | steps: 18 | - uses: actions/checkout@v4 19 | 20 | - uses: actions/setup-python@v2 21 | with: 22 | python-version: '3.10' 23 | 24 | - name: Cache Mint packages 25 | uses: actions/cache@v4 26 | with: 27 | path: ${{ env.MINT_PATH }} 28 | key: ${{ runner.os }}-mint-${{ hashFiles('**/Mintfile') }} 29 | restore-keys: ${{ runner.os }}-mint- 30 | 31 | - name: Setup Scripts Directory 32 | run: ./setup-scripts.sh 33 | 34 | - name: Setup check 35 | run: scripts/setup_check.sh 36 | 37 | - name: Style 38 | run: scripts/style.sh test-only 39 | 40 | - name: Whitespace 41 | run: scripts/check_whitespace.sh 42 | 43 | - name: Filename spaces 44 | run: scripts/check_filename_spaces.sh 45 | 46 | - name: Copyrights 47 | run: scripts/check_copyright.sh 48 | 49 | - name: Imports 50 | run: scripts/check_imports.swift 51 | -------------------------------------------------------------------------------- /.github/workflows/google-utilities.yml: -------------------------------------------------------------------------------- 1 | name: google-utilities 2 | 3 | on: 4 | pull_request: 5 | schedule: 6 | # Run every day at 11pm (PST) - cron uses UTC times 7 | - cron: '0 7 * * *' 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | changed_today: 15 | runs-on: ubuntu-latest 16 | name: Check if the repo was updated today 17 | outputs: 18 | WAS_CHANGED: ${{ steps.check_changed.outputs.WAS_CHANGED }} 19 | steps: 20 | - uses: actions/checkout@v4 21 | - id: check_changed 22 | name: Check 23 | if: ${{ github.event_name == 'schedule' }} 24 | run: echo '::set-output name=WAS_CHANGED::'$(test -n "$(git log --format=%H --since='24 hours ago')" && echo 'true' || echo 'false') 25 | 26 | pod-lib-lint: 27 | needs: changed_today 28 | if: ${{ github.event_name == 'pull_request' || needs.changed_today.outputs.WAS_CHANGED == 'true' }} 29 | 30 | runs-on: macOS-latest 31 | strategy: 32 | matrix: 33 | target: [ios, tvos, macos] 34 | steps: 35 | - uses: ruby/setup-ruby@v1 36 | with: 37 | ruby-version: "2.7" 38 | - uses: actions/checkout@v3 39 | - name: Setup Scripts Directory 40 | run: ./setup-scripts.sh 41 | - name: Setup Bundler 42 | run: scripts/setup_bundler.sh 43 | - name: Build and test 44 | run: | 45 | scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb GoogleUtilities.podspec \ 46 | --platforms=${{ matrix.target }} --analyze 47 | 48 | catalyst: 49 | needs: changed_today 50 | if: ${{ github.event_name == 'pull_request' || needs.changed_today.outputs.WAS_CHANGED == 'true' }} 51 | 52 | runs-on: macOS-latest 53 | steps: 54 | - uses: ruby/setup-ruby@v1 55 | with: 56 | ruby-version: "2.7" 57 | - uses: actions/checkout@v3 58 | - name: Setup Scripts Directory 59 | run: ./setup-scripts.sh 60 | - name: Setup Bundler 61 | run: scripts/setup_bundler.sh 62 | - name: Setup project and Build for Catalyst 63 | run: | 64 | scripts/third_party/travis/retry.sh scripts/test_catalyst.sh GoogleUtilities test \ 65 | GoogleUtilities-Unit-unit 66 | 67 | spm: 68 | needs: changed_today 69 | if: ${{ github.event_name == 'pull_request' || needs.changed_today.outputs.WAS_CHANGED == 'true' }} 70 | 71 | runs-on: macOS-latest 72 | strategy: 73 | matrix: 74 | target: [iOS, tvOS, macOS, catalyst] 75 | steps: 76 | - uses: actions/checkout@v3 77 | - name: Setup Scripts Directory 78 | run: ./setup-scripts.sh 79 | - name: Initialize xcodebuild 80 | run: | 81 | sudo xcode-select -s '/Applications/Xcode_16.2.app/Contents/Developer' 82 | xcodebuild -list 83 | - name: iOS Unit Tests 84 | run: scripts/third_party/travis/retry.sh scripts/build.sh GoogleUtilities-Package ${{ matrix.target }} spm 85 | 86 | utilities-cocoapods-option-matrix: 87 | needs: pod-lib-lint 88 | runs-on: macos-latest 89 | strategy: 90 | matrix: 91 | target: [ios, tvos, macos] 92 | flags: [ 93 | '--use-static-frameworks', 94 | '--use-libraries --skip-tests' 95 | ] 96 | steps: 97 | - uses: ruby/setup-ruby@v1 98 | with: 99 | ruby-version: "2.7" 100 | - uses: actions/checkout@v3 101 | - name: Setup Scripts Directory 102 | run: ./setup-scripts.sh 103 | - name: Setup Bundler 104 | run: scripts/setup_bundler.sh 105 | - name: PodLibLint GoogleUtilities Cron 106 | run: | 107 | scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb \ 108 | GoogleUtilities.podspec --platforms=${{ matrix.target }} ${{ matrix.flags }} --analyze 109 | -------------------------------------------------------------------------------- /.github/workflows/test_coverage.yml: -------------------------------------------------------------------------------- 1 | name: test_coverage 2 | 3 | on: 4 | pull_request: 5 | # open will be triggered when a pull request is created. 6 | # synchronize will be triggered when a pull request has new commits. 7 | # closed will be triggered when a pull request is closed. 8 | types: [opened, synchronize, closed] 9 | 10 | env: 11 | METRICS_SERVICE_SECRET: ${{ secrets.GHASecretsGPGPassphrase1 }} 12 | 13 | concurrency: 14 | group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} 15 | cancel-in-progress: true 16 | 17 | jobs: 18 | pod_lib_lint: 19 | if: github.repository == 'google/GoogleUtilities' && (github.event.action == 'synchronize' || github.event.action == 'opened' || github.event.pull_request.merged) 20 | runs-on: macos-latest 21 | strategy: 22 | matrix: 23 | target: [ios] 24 | steps: 25 | - uses: ruby/setup-ruby@v1 26 | with: 27 | ruby-version: "2.7" 28 | - uses: actions/checkout@v4 29 | - name: Setup Scripts Directory 30 | run: ./setup-scripts.sh 31 | - name: Setup Bundler 32 | run: ./scripts/setup_bundler.sh 33 | - name: PodLibLint DataTransport 34 | run: | 35 | scripts/health_metrics/pod_test_code_coverage_report.sh --sdk=GoogleUtilities --platform=${{ matrix.target }} --test_spec=unit,unit-swift --output_path="/Users/runner/GoogleUtilities-ios-unit.xcresult" 36 | - uses: actions/upload-artifact@v4 37 | with: 38 | name: codecoverage 39 | path: /Users/runner/*.xcresult 40 | manage_test_results: 41 | if: github.repository == 'google/GoogleUtilities' && (github.event.action == 'synchronize' || github.event.action == 'opened' || github.event.pull_request.merged) 42 | needs: pod_lib_lint 43 | runs-on: macOS-latest 44 | steps: 45 | - uses: actions/checkout@v4 46 | with: 47 | fetch-depth: 0 48 | - uses: actions/download-artifact@v4.1.7 49 | id: download 50 | with: 51 | path: /Users/runner/test 52 | - name: Setup Scripts Directory 53 | run: ./setup-scripts.sh 54 | - name: Access to Metrics Service 55 | if: ${{ env.METRICS_SERVICE_SECRET }} 56 | run: | 57 | # Install gcloud sdk 58 | curl https://sdk.cloud.google.com > install.sh 59 | bash install.sh --disable-prompts 60 | echo "${HOME}/google-cloud-sdk/bin/" >> $GITHUB_PATH 61 | export PATH="${HOME}/google-cloud-sdk/bin/:${PATH}" 62 | 63 | # Activate the service account for Metrics Service. 64 | scripts/decrypt_gha_secret.sh scripts/gha-encrypted/metrics_service_access.json.gpg \ 65 | metrics-access.json "${{ env.METRICS_SERVICE_SECRET }}" 66 | gcloud auth activate-service-account --key-file metrics-access.json 67 | - name: Build code coverage tool 68 | run: swift build --package-path firebase-ios-sdk/scripts/health_metrics/generate_code_coverage_report/ 69 | - name: Generate report 70 | if: github.event.pull_request.merged != true && env.METRICS_SERVICE_SECRET 71 | env: 72 | pr_branch: ${{ github.event.pull_request.head.ref }} 73 | run: | 74 | common_commit=$(git merge-base remotes/origin/${pr_branch} remotes/origin/main) 75 | GITHUB_SHA=$(cat $GITHUB_EVENT_PATH | jq -r .pull_request.head.sha) 76 | if [ -d "${{steps.download.outputs.download-path}}" ]; then 77 | firebase-ios-sdk/scripts/health_metrics/generate_code_coverage_report/.build/debug/CoverageReportGenerator --presubmit "google/GoogleUtilities" --head-commit "${GITHUB_SHA}" --token $(gcloud auth print-identity-token) --xcresult-dir "${{steps.download.outputs.download-path}}/codecoverage" --log-link "https://github.com/google/GoogleUtilities/actions/runs/${GITHUB_RUN_ID}" --pull-request-num ${{github.event.pull_request.number}} --base-commit "$common_commit" 78 | fi 79 | - name: Update New Coverage Data 80 | if: github.event.pull_request.merged == true && env.METRICS_SERVICE_SECRET 81 | run: | 82 | if [ -d "${{steps.download.outputs.download-path}}" ]; then 83 | firebase-ios-sdk/scripts/health_metrics/generate_code_coverage_report/.build/debug/CoverageReportGenerator --merge "google/GoogleUtilities" --head-commit "${GITHUB_SHA}" --token $(gcloud auth print-identity-token) --xcresult-dir "${{steps.download.outputs.download-path}}/codecoverage" --log-link "https://github.com/google/GoogleUtilities/actions/runs/${GITHUB_RUN_ID}" --source-branch "${{ github.base_ref }}" 84 | fi 85 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | 4 | # Xcode 5 | build/ 6 | *.pbxuser 7 | !default.pbxuser 8 | *.mode1v3 9 | !default.mode1v3 10 | *.mode2v3 11 | !default.mode2v3 12 | *.perspectivev3 13 | !default.perspectivev3 14 | xcuserdata/ 15 | *.xccheckout 16 | profile 17 | *.moved-aside 18 | DerivedData 19 | *.hmap 20 | *.ipa 21 | 22 | # Swift Package Manager 23 | */.build 24 | Package.resolved 25 | 26 | # Mint package manager 27 | Mint 28 | 29 | # IntelliJ 30 | .idea 31 | 32 | # Vim 33 | *.swo 34 | *.swp 35 | *~ 36 | 37 | # Bundler 38 | /.bundle 39 | /vendor 40 | 41 | # Pods 42 | Pods/ 43 | Podfile.lock 44 | *.xcworkspace 45 | 46 | # CocoaPods generate 47 | gen/ 48 | 49 | #firebase-ios-sdk clone 50 | firebase-ios-sdk/ 51 | 52 | #scripts link 53 | scripts 54 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | ruby-2.7 2 | -------------------------------------------------------------------------------- /.swiftformat: -------------------------------------------------------------------------------- 1 | # Formatting Options - Mimic Google style 2 | --indent 2 3 | --maxwidth 100 4 | --wrapparameters afterfirst 5 | 6 | # Disabled Rules 7 | 8 | # Too many of our swift files have simplistic examples. While technically 9 | # it's correct to remove the unused argument labels, it makes our examples 10 | # look wrong. 11 | --disable unusedArguments 12 | 13 | # We prefer trailing braces. 14 | --disable wrapMultilineStatementBraces 15 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | We'd love to accept your patches and contributions to this project. There are 4 | just a few small guidelines you need to follow. 5 | 6 | ## Contributor License Agreement 7 | 8 | Contributions to this project must be accompanied by a Contributor License 9 | Agreement. You (or your employer) retain the copyright to your contribution, 10 | this simply gives us permission to use and redistribute your contributions as 11 | part of the project. Head over to to see 12 | your current agreements on file or to sign a new one. 13 | 14 | You generally only need to submit a CLA once, so if you've already submitted one 15 | (even if it was for a different project), you probably don't need to do it 16 | again. 17 | 18 | ## Code reviews 19 | 20 | All submissions, including submissions by project members, require review. We 21 | use GitHub pull requests for this purpose. Consult [GitHub Help] for more 22 | information on using pull requests. 23 | 24 | [GitHub Help]: https://help.github.com/articles/about-pull-requests/ 25 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # To update, change version below, run bundle install, test, 2 | # commit Gemfile and Gemfile.lock. 3 | source 'https://rubygems.org' 4 | 5 | gem 'cocoapods', '1.15.2' 6 | gem 'cocoapods-generate', '2.0.1' 7 | gem 'danger', '8.4.5' 8 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | CFPropertyList (3.0.7) 5 | base64 6 | nkf 7 | rexml 8 | activesupport (7.1.3.2) 9 | base64 10 | bigdecimal 11 | concurrent-ruby (~> 1.0, >= 1.0.2) 12 | connection_pool (>= 2.2.5) 13 | drb 14 | i18n (>= 1.6, < 2) 15 | minitest (>= 5.1) 16 | mutex_m 17 | tzinfo (~> 2.0) 18 | addressable (2.8.4) 19 | public_suffix (>= 2.0.2, < 6.0) 20 | algoliasearch (1.27.5) 21 | httpclient (~> 2.8, >= 2.8.3) 22 | json (>= 1.5.1) 23 | atomos (0.1.3) 24 | base64 (0.2.0) 25 | bigdecimal (3.1.7) 26 | claide (1.1.0) 27 | claide-plugins (0.9.2) 28 | cork 29 | nap 30 | open4 (~> 1.3) 31 | cocoapods (1.15.2) 32 | addressable (~> 2.8) 33 | claide (>= 1.0.2, < 2.0) 34 | cocoapods-core (= 1.15.2) 35 | cocoapods-deintegrate (>= 1.0.3, < 2.0) 36 | cocoapods-downloader (>= 2.1, < 3.0) 37 | cocoapods-plugins (>= 1.0.0, < 2.0) 38 | cocoapods-search (>= 1.0.0, < 2.0) 39 | cocoapods-trunk (>= 1.6.0, < 2.0) 40 | cocoapods-try (>= 1.1.0, < 2.0) 41 | colored2 (~> 3.1) 42 | escape (~> 0.0.4) 43 | fourflusher (>= 2.3.0, < 3.0) 44 | gh_inspector (~> 1.0) 45 | molinillo (~> 0.8.0) 46 | nap (~> 1.0) 47 | ruby-macho (>= 2.3.0, < 3.0) 48 | xcodeproj (>= 1.23.0, < 2.0) 49 | cocoapods-core (1.15.2) 50 | activesupport (>= 5.0, < 8) 51 | addressable (~> 2.8) 52 | algoliasearch (~> 1.0) 53 | concurrent-ruby (~> 1.1) 54 | fuzzy_match (~> 2.0.4) 55 | nap (~> 1.0) 56 | netrc (~> 0.11) 57 | public_suffix (~> 4.0) 58 | typhoeus (~> 1.0) 59 | cocoapods-deintegrate (1.0.5) 60 | cocoapods-disable-podfile-validations (0.1.1) 61 | cocoapods-downloader (2.1) 62 | cocoapods-generate (2.0.1) 63 | cocoapods-disable-podfile-validations (~> 0.1.1) 64 | cocoapods-plugins (1.0.0) 65 | nap 66 | cocoapods-search (1.0.1) 67 | cocoapods-trunk (1.6.0) 68 | nap (>= 0.8, < 2.0) 69 | netrc (~> 0.11) 70 | cocoapods-try (1.2.0) 71 | colored2 (3.1.2) 72 | concurrent-ruby (1.2.3) 73 | connection_pool (2.4.1) 74 | cork (0.3.0) 75 | colored2 (~> 3.1) 76 | danger (8.4.5) 77 | claide (~> 1.0) 78 | claide-plugins (>= 0.9.2) 79 | colored2 (~> 3.1) 80 | cork (~> 0.1) 81 | faraday (>= 0.9.0, < 2.0) 82 | faraday-http-cache (~> 2.0) 83 | git (~> 1.7) 84 | kramdown (~> 2.3) 85 | kramdown-parser-gfm (~> 1.0) 86 | no_proxy_fix 87 | octokit (~> 4.7) 88 | terminal-table (>= 1, < 4) 89 | drb (2.2.1) 90 | escape (0.0.4) 91 | ethon (0.16.0) 92 | ffi (>= 1.15.0) 93 | faraday (1.10.2) 94 | faraday-em_http (~> 1.0) 95 | faraday-em_synchrony (~> 1.0) 96 | faraday-excon (~> 1.1) 97 | faraday-httpclient (~> 1.0) 98 | faraday-multipart (~> 1.0) 99 | faraday-net_http (~> 1.0) 100 | faraday-net_http_persistent (~> 1.0) 101 | faraday-patron (~> 1.0) 102 | faraday-rack (~> 1.0) 103 | faraday-retry (~> 1.0) 104 | ruby2_keywords (>= 0.0.4) 105 | faraday-em_http (1.0.0) 106 | faraday-em_synchrony (1.0.0) 107 | faraday-excon (1.1.0) 108 | faraday-http-cache (2.4.1) 109 | faraday (>= 0.8) 110 | faraday-httpclient (1.0.1) 111 | faraday-multipart (1.0.4) 112 | multipart-post (~> 2) 113 | faraday-net_http (1.0.1) 114 | faraday-net_http_persistent (1.2.0) 115 | faraday-patron (1.0.0) 116 | faraday-rack (1.0.0) 117 | faraday-retry (1.0.3) 118 | ffi (1.16.3) 119 | fourflusher (2.3.1) 120 | fuzzy_match (2.0.4) 121 | gh_inspector (1.1.3) 122 | git (1.18.0) 123 | addressable (~> 2.8) 124 | rchardet (~> 1.8) 125 | httpclient (2.8.3) 126 | i18n (1.14.4) 127 | concurrent-ruby (~> 1.0) 128 | json (2.7.2) 129 | kramdown (2.4.0) 130 | rexml 131 | kramdown-parser-gfm (1.1.0) 132 | kramdown (~> 2.0) 133 | minitest (5.22.3) 134 | molinillo (0.8.0) 135 | multipart-post (2.2.3) 136 | mutex_m (0.2.0) 137 | nanaimo (0.3.0) 138 | nap (1.1.0) 139 | netrc (0.11.0) 140 | nkf (0.2.0) 141 | no_proxy_fix (0.1.2) 142 | octokit (4.25.1) 143 | faraday (>= 1, < 3) 144 | sawyer (~> 0.9) 145 | open4 (1.3.4) 146 | public_suffix (4.0.7) 147 | rchardet (1.8.0) 148 | rexml (3.3.9) 149 | ruby-macho (2.5.1) 150 | ruby2_keywords (0.0.5) 151 | sawyer (0.9.2) 152 | addressable (>= 2.3.5) 153 | faraday (>= 0.17.3, < 3) 154 | terminal-table (3.0.2) 155 | unicode-display_width (>= 1.1.1, < 3) 156 | typhoeus (1.4.1) 157 | ethon (>= 0.9.0) 158 | tzinfo (2.0.6) 159 | concurrent-ruby (~> 1.0) 160 | unicode-display_width (2.3.0) 161 | xcodeproj (1.25.0) 162 | CFPropertyList (>= 2.3.3, < 4.0) 163 | atomos (~> 0.1.3) 164 | claide (>= 1.0.2, < 2.0) 165 | colored2 (~> 3.1) 166 | nanaimo (~> 0.3.0) 167 | rexml (>= 3.3.2, < 4.0) 168 | 169 | PLATFORMS 170 | ruby 171 | 172 | DEPENDENCIES 173 | cocoapods (= 1.15.2) 174 | cocoapods-generate (= 2.0.1) 175 | danger (= 8.4.5) 176 | 177 | BUNDLED WITH 178 | 2.1.4 179 | -------------------------------------------------------------------------------- /GoogleUtilities.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'GoogleUtilities' 3 | s.version = '8.1.0' 4 | s.summary = 'Google Utilities for Apple platform SDKs' 5 | 6 | s.description = <<-DESC 7 | Internal Google Utilities including Network, Reachability Environment, Logger and Swizzling for 8 | other Google CocoaPods. They're not intended for direct public usage. 9 | DESC 10 | 11 | s.homepage = 'https://github.com/google/GoogleUtilities' 12 | s.license = { :type => 'Apache-2.0', :file => 'LICENSE' } 13 | s.authors = 'Google, Inc.' 14 | 15 | s.source = { 16 | :git => 'https://github.com/google/GoogleUtilities.git', 17 | :tag => 'CocoaPods-' + s.version.to_s 18 | } 19 | 20 | ios_deployment_target = '12.0' 21 | osx_deployment_target = '10.15' 22 | tvos_deployment_target = '13.0' 23 | watchos_deployment_target = '7.0' 24 | 25 | s.ios.deployment_target = ios_deployment_target 26 | s.osx.deployment_target = osx_deployment_target 27 | s.tvos.deployment_target = tvos_deployment_target 28 | s.watchos.deployment_target = watchos_deployment_target 29 | 30 | s.cocoapods_version = '>= 1.4.0' 31 | s.prefix_header_file = false 32 | 33 | s.pod_target_xcconfig = { 34 | 'GCC_C_LANGUAGE_STANDARD' => 'c99', 35 | 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"', 36 | } 37 | 38 | s.subspec 'Privacy' do |cs| 39 | cs.resource_bundles = { 40 | "GoogleUtilities_Privacy" => 'GoogleUtilities/Privacy/Resources/PrivacyInfo.xcprivacy' 41 | } 42 | end 43 | 44 | s.subspec 'Environment' do |es| 45 | es.source_files = [ 46 | 'GoogleUtilities/Environment/**/*.[mh]', 47 | 'third_party/IsAppEncrypted/**/*.[mh]' 48 | ] 49 | es.public_header_files = 'GoogleUtilities/Environment/Public/GoogleUtilities/*.h' 50 | es.dependency 'GoogleUtilities/Privacy' 51 | es.frameworks = [ 52 | 'Security' 53 | ] 54 | end 55 | 56 | s.subspec 'Logger' do |ls| 57 | ls.source_files = 'GoogleUtilities/Logger/**/*.[mh]' 58 | ls.public_header_files = 'GoogleUtilities/Logger/Public/GoogleUtilities/*.h' 59 | ls.dependency 'GoogleUtilities/Environment' 60 | ls.dependency 'GoogleUtilities/Privacy' 61 | end 62 | 63 | 64 | s.subspec 'Network' do |ns| 65 | ns.source_files = 'GoogleUtilities/Network/**/*.[mh]' 66 | ns.public_header_files = 'GoogleUtilities/Network/Public/GoogleUtilities/*.h' 67 | ns.dependency 'GoogleUtilities/NSData+zlib' 68 | ns.dependency 'GoogleUtilities/Logger' 69 | ns.dependency 'GoogleUtilities/Reachability' 70 | ns.dependency 'GoogleUtilities/Privacy' 71 | ns.frameworks = [ 72 | 'Security' 73 | ] 74 | end 75 | 76 | s.subspec 'NSData+zlib' do |ns| 77 | ns.source_files = 'GoogleUtilities/NSData+zlib/**/*.[mh]' 78 | ns.public_header_files = 'GoogleUtilities/NSData+zlib/Public/GoogleUtilities/*.h' 79 | ns.dependency 'GoogleUtilities/Privacy' 80 | ns.libraries = [ 81 | 'z' 82 | ] 83 | end 84 | 85 | s.subspec 'Reachability' do |rs| 86 | rs.source_files = 'GoogleUtilities/Reachability/**/*.[mh]' 87 | rs.public_header_files = 'GoogleUtilities/Reachability/Public/GoogleUtilities/*.h' 88 | rs.dependency 'GoogleUtilities/Privacy' 89 | rs.ios.frameworks = [ 90 | 'SystemConfiguration' 91 | ] 92 | rs.osx.frameworks = [ 93 | 'SystemConfiguration' 94 | ] 95 | rs.tvos.frameworks = [ 96 | 'SystemConfiguration' 97 | ] 98 | rs.dependency 'GoogleUtilities/Logger' 99 | end 100 | 101 | s.subspec 'AppDelegateSwizzler' do |adss| 102 | adss.source_files = [ 103 | 'GoogleUtilities/AppDelegateSwizzler/Internal/*.h', 104 | 'GoogleUtilities/AppDelegateSwizzler/Public/**/*.h', 105 | 'GoogleUtilities/AppDelegateSwizzler/*.m', 106 | 'GoogleUtilities/Common/*.h', 107 | ] 108 | adss.public_header_files = [ 109 | 'GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/*.h', 110 | ] 111 | adss.dependency 'GoogleUtilities/Privacy' 112 | adss.dependency 'GoogleUtilities/Logger' 113 | adss.dependency 'GoogleUtilities/Network' 114 | adss.dependency 'GoogleUtilities/Environment' 115 | end 116 | 117 | s.subspec 'MethodSwizzler' do |mss| 118 | mss.source_files = 'GoogleUtilities/MethodSwizzler/**/*.[mh]', 'GoogleUtilities/Common/*.h' 119 | mss.public_header_files = 'GoogleUtilities/MethodSwizzler/Public/GoogleUtilities/*.h' 120 | mss.dependency 'GoogleUtilities/Logger' 121 | mss.dependency 'GoogleUtilities/Privacy' 122 | end 123 | 124 | s.subspec 'SwizzlerTestHelpers' do |sths| 125 | sths.source_files = 'GoogleUtilities/SwizzlerTestHelpers/**/*.[hm]' 126 | sths.public_header_files = 'GoogleUtilities/SwizzlerTestHelpers/Public/GoogleUtilities/*.h' 127 | sths.dependency 'GoogleUtilities/MethodSwizzler' 128 | end 129 | 130 | s.subspec 'UserDefaults' do |ud| 131 | ud.source_files = 'GoogleUtilities/UserDefaults/**/*.[hm]' 132 | ud.public_header_files = 'GoogleUtilities/UserDefaults/Public/GoogleUtilities/*.h' 133 | ud.dependency 'GoogleUtilities/Logger' 134 | ud.dependency 'GoogleUtilities/Privacy' 135 | end 136 | 137 | s.test_spec 'unit' do |unit_tests| 138 | unit_tests.scheme = { :code_coverage => true } 139 | 140 | unit_tests.platforms = { 141 | :ios => ios_deployment_target, 142 | :osx => osx_deployment_target, 143 | :tvos => tvos_deployment_target 144 | } 145 | unit_tests.source_files = [ 146 | 'GoogleUtilities/Tests/Unit/**/*.[mh]', 147 | ] 148 | 149 | # All tests require arc except Tests/Network/third_party/GTMHTTPServer.m 150 | unit_tests.requires_arc = [ 151 | 'GoogleUtilities/Tests/Unit/*/*.[mh]', 152 | 'GoogleUtilities/Tests/Unit/Environment/**/*.[mh]' 153 | ] 154 | unit_tests.requires_app_host = true 155 | unit_tests.dependency 'OCMock' 156 | end 157 | 158 | s.test_spec 'unit-swift' do |unit_tests_swift| 159 | unit_tests_swift.scheme = { :code_coverage => true } 160 | unit_tests_swift.platforms = { 161 | :ios => ios_deployment_target, 162 | :osx => osx_deployment_target, 163 | :tvos => tvos_deployment_target 164 | } 165 | unit_tests_swift.source_files = 'GoogleUtilities/Tests/SwiftUnit/**/*.swift', 166 | 'GoogleUtilities/Tests/SwiftUnit/**/*.h' 167 | unit_tests_swift.requires_app_host = true 168 | end 169 | end 170 | -------------------------------------------------------------------------------- /GoogleUtilities/AppDelegateSwizzler/Internal/GULAppDelegateSwizzler_Private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | #import "GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h" 19 | #import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" 20 | 21 | @class GULApplication; 22 | 23 | NS_ASSUME_NONNULL_BEGIN 24 | 25 | @interface GULAppDelegateSwizzler () 26 | 27 | /** ISA Swizzles the given appDelegate as the original app delegate would be. 28 | * 29 | * @param appDelegate The object that needs to be isa swizzled. This should conform to the 30 | * application delegate protocol. 31 | */ 32 | + (void)proxyAppDelegate:(id)appDelegate; 33 | 34 | /** Returns a dictionary containing interceptor IDs mapped to a GULZeroingWeakContainer. 35 | * 36 | * @return A dictionary of the form {NSString : GULZeroingWeakContainer}, where the NSString is 37 | * the interceptorID. 38 | */ 39 | + (GULMutableDictionary *)interceptors; 40 | 41 | /** Deletes all the registered interceptors. */ 42 | + (void)clearInterceptors; 43 | 44 | /** Resets the token that prevents the app delegate proxy from being isa swizzled multiple times. */ 45 | + (void)resetProxyOriginalDelegateOnceToken; 46 | 47 | /** Returns the original app delegate that was proxied. 48 | * 49 | * @return The original app delegate instance that was proxied. 50 | */ 51 | + (id)originalDelegate; 52 | 53 | @end 54 | 55 | NS_ASSUME_NONNULL_END 56 | -------------------------------------------------------------------------------- /GoogleUtilities/AppDelegateSwizzler/Internal/GULSceneDelegateSwizzler_Private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | #import "GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULSceneDelegateSwizzler.h" 19 | #import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" 20 | 21 | NS_ASSUME_NONNULL_BEGIN 22 | 23 | @interface GULSceneDelegateSwizzler () 24 | 25 | #if UISCENE_SUPPORTED 26 | 27 | /** Returns a dictionary containing interceptor IDs mapped to a GULZeroingWeakContainer. 28 | * 29 | * @return A dictionary of the form {NSString : GULZeroingWeakContainer}, where the NSString is 30 | * the interceptorID. 31 | */ 32 | + (GULMutableDictionary *)interceptors; 33 | 34 | /** Deletes all the registered interceptors. */ 35 | + (void)clearInterceptors; 36 | 37 | /** ISA Swizzles the given appDelegate as the original app delegate would be. 38 | * 39 | * @param scene The scene whose delegate needs to be isa swizzled. This should conform to the 40 | * scene delegate protocol. 41 | */ 42 | + (void)proxySceneDelegateIfNeeded:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0)); 43 | 44 | #endif // UISCENE_SUPPORTED 45 | 46 | @end 47 | 48 | NS_ASSUME_NONNULL_END 49 | -------------------------------------------------------------------------------- /GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | #import "GULApplication.h" 20 | 21 | NS_ASSUME_NONNULL_BEGIN 22 | 23 | typedef NSString *const GULAppDelegateInterceptorID; 24 | 25 | /** This class contains methods that isa swizzle the app delegate. */ 26 | @interface GULAppDelegateSwizzler : NSProxy 27 | 28 | /** Registers an app delegate interceptor whose methods will be invoked as they're invoked on the 29 | * original app delegate. 30 | * 31 | * @param interceptor An instance of a class that conforms to the application delegate protocol. 32 | * The interceptor is NOT retained. 33 | * @return A unique GULAppDelegateInterceptorID if interceptor was successfully registered; nil 34 | * if it fails. 35 | */ 36 | + (nullable GULAppDelegateInterceptorID)registerAppDelegateInterceptor: 37 | (id)interceptor; 38 | 39 | /** Unregisters an interceptor with the given ID if it exists. 40 | * 41 | * @param interceptorID The object that was generated when the interceptor was registered. 42 | */ 43 | + (void)unregisterAppDelegateInterceptorWithID:(GULAppDelegateInterceptorID)interceptorID; 44 | 45 | /** This method ensures that the original app delegate has been proxied. Call this before 46 | * registering your interceptor. This method is safe to call multiple times (but it only proxies 47 | * the app delegate once). 48 | * 49 | * This method doesn't proxy APNS related methods: 50 | * @code 51 | * - application:didRegisterForRemoteNotificationsWithDeviceToken: 52 | * - application:didFailToRegisterForRemoteNotificationsWithError: 53 | * - application:didReceiveRemoteNotification:fetchCompletionHandler: 54 | * - application:didReceiveRemoteNotification: 55 | * @endcode 56 | * 57 | * To proxy these methods use +[GULAppDelegateSwizzler 58 | * proxyOriginalDelegateIncludingAPNSMethods]. The methods have to be proxied separately to 59 | * avoid potential warnings from Apple review about missing Push Notification Entitlement (e.g. 60 | * https://github.com/firebase/firebase-ios-sdk/issues/2807) 61 | * 62 | * The method has no effect for extensions. 63 | * 64 | * @see proxyOriginalDelegateIncludingAPNSMethods 65 | */ 66 | + (void)proxyOriginalDelegate; 67 | 68 | /** This method ensures that the original app delegate has been proxied including APNS related 69 | * methods. Call this before registering your interceptor. This method is safe to call multiple 70 | * times (but it only proxies the app delegate once) or 71 | * after +[GULAppDelegateSwizzler proxyOriginalDelegate] 72 | * 73 | * This method calls +[GULAppDelegateSwizzler proxyOriginalDelegate] under the hood. 74 | * After calling this method the following App Delegate methods will be proxied in addition to 75 | * the methods proxied by proxyOriginalDelegate: 76 | * @code 77 | * - application:didRegisterForRemoteNotificationsWithDeviceToken: 78 | * - application:didFailToRegisterForRemoteNotificationsWithError: 79 | * - application:didReceiveRemoteNotification:fetchCompletionHandler: 80 | * - application:didReceiveRemoteNotification: 81 | * @endcode 82 | * 83 | * The method has no effect for extensions. 84 | * 85 | * @see proxyOriginalDelegate 86 | */ 87 | + (void)proxyOriginalDelegateIncludingAPNSMethods; 88 | 89 | /** Indicates whether app delegate proxy is explicitly disabled or enabled. Enabled by default. 90 | * 91 | * @return YES if AppDelegateProxy is Enabled, NO otherwise. 92 | */ 93 | + (BOOL)isAppDelegateProxyEnabled; 94 | 95 | /** Returns the current sharedApplication. 96 | * 97 | * @return the current application instance if in an app, or nil if in extension or if it doesn't 98 | * exist. 99 | */ 100 | + (nullable GULApplication *)sharedApplication; 101 | 102 | /** Do not initialize this class. */ 103 | - (instancetype)init NS_UNAVAILABLE; 104 | 105 | NS_ASSUME_NONNULL_END 106 | 107 | @end 108 | -------------------------------------------------------------------------------- /GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULApplication.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | #if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_VISION 20 | 21 | #import 22 | 23 | #define GULApplication UIApplication 24 | #define GULApplicationDelegate UIApplicationDelegate 25 | #define GULUserActivityRestoring UIUserActivityRestoring 26 | 27 | static NSString *const kGULApplicationClassName = @"UIApplication"; 28 | 29 | #elif TARGET_OS_OSX 30 | 31 | #import 32 | 33 | #define GULApplication NSApplication 34 | #define GULApplicationDelegate NSApplicationDelegate 35 | #define GULUserActivityRestoring NSUserActivityRestoring 36 | 37 | static NSString *const kGULApplicationClassName = @"NSApplication"; 38 | 39 | #elif TARGET_OS_WATCH 40 | 41 | #import 42 | 43 | // We match the according watchOS API but swizzling should not work in watch 44 | #define GULApplication WKExtension 45 | #define GULApplicationDelegate WKExtensionDelegate 46 | #define GULUserActivityRestoring NSUserActivityRestoring 47 | 48 | static NSString *const kGULApplicationClassName = @"WKExtension"; 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULSceneDelegateSwizzler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | #import 19 | 20 | #if __has_include() 21 | #import 22 | #endif 23 | 24 | #if TARGET_OS_IOS || TARGET_OS_TV 25 | #define UISCENE_SUPPORTED 1 26 | #endif 27 | 28 | NS_ASSUME_NONNULL_BEGIN 29 | 30 | typedef NSString *const GULSceneDelegateInterceptorID; 31 | 32 | /** This class contains methods that isa swizzle the scene delegate. */ 33 | @interface GULSceneDelegateSwizzler : NSProxy 34 | 35 | #if UISCENE_SUPPORTED 36 | 37 | /** Registers a scene delegate interceptor whose methods will be invoked as they're invoked on the 38 | * original scene delegate. 39 | * 40 | * @param interceptor An instance of a class that conforms to the application delegate protocol. 41 | * The interceptor is NOT retained. 42 | * @return A unique GULSceneDelegateInterceptorID if interceptor was successfully registered; nil 43 | * if it fails. 44 | */ 45 | + (nullable GULSceneDelegateInterceptorID)registerSceneDelegateInterceptor: 46 | (id)interceptor API_AVAILABLE(ios(13.0), tvos(13.0)); 47 | 48 | /** Unregisters an interceptor with the given ID if it exists. 49 | * 50 | * @param interceptorID The object that was generated when the interceptor was registered. 51 | */ 52 | + (void)unregisterSceneDelegateInterceptorWithID:(GULSceneDelegateInterceptorID)interceptorID 53 | API_AVAILABLE(ios(13.0), tvos(13.0)); 54 | 55 | /** Do not initialize this class. */ 56 | - (instancetype)init NS_UNAVAILABLE; 57 | 58 | #endif // UISCENE_SUPPORTED 59 | 60 | /** This method ensures that the original scene delegate has been proxied. Call this before 61 | * registering your interceptor. This method is safe to call multiple times (but it only proxies 62 | * the scene delegate once). 63 | * 64 | * The method has no effect for extensions. 65 | */ 66 | + (void)proxyOriginalSceneDelegate; 67 | 68 | /** Indicates whether scene delegate proxy is explicitly disabled or enabled. Enabled by default. 69 | * 70 | * @return YES if SceneDelegateProxy is Enabled, NO otherwise. 71 | */ 72 | + (BOOL)isSceneDelegateProxyEnabled; 73 | 74 | @end 75 | 76 | NS_ASSUME_NONNULL_END 77 | -------------------------------------------------------------------------------- /GoogleUtilities/AppDelegateSwizzler/Resources/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyTracking 6 | 7 | NSPrivacyTrackingDomains 8 | 9 | 10 | NSPrivacyCollectedDataTypes 11 | 12 | 13 | NSPrivacyAccessedAPITypes 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /GoogleUtilities/Common/GULLoggerCodes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | typedef NS_ENUM(NSInteger, GULSwizzlerMessageCode) { 20 | // App Delegate Swizzling. 21 | kGULSwizzlerMessageCodeAppDelegateSwizzling000 = 1000, // I-SWZ001000 22 | kGULSwizzlerMessageCodeAppDelegateSwizzling001 = 1001, // I-SWZ001001 23 | kGULSwizzlerMessageCodeAppDelegateSwizzling002 = 1002, // I-SWZ001002 24 | kGULSwizzlerMessageCodeAppDelegateSwizzling003 = 1003, // I-SWZ001003 25 | kGULSwizzlerMessageCodeAppDelegateSwizzling004 = 1004, // I-SWZ001004 26 | kGULSwizzlerMessageCodeAppDelegateSwizzling005 = 1005, // I-SWZ001005 27 | kGULSwizzlerMessageCodeAppDelegateSwizzling006 = 1006, // I-SWZ001006 28 | kGULSwizzlerMessageCodeAppDelegateSwizzling007 = 1007, // I-SWZ001007 29 | kGULSwizzlerMessageCodeAppDelegateSwizzling008 = 1008, // I-SWZ001008 30 | kGULSwizzlerMessageCodeAppDelegateSwizzling009 = 1009, // I-SWZ001009 31 | kGULSwizzlerMessageCodeAppDelegateSwizzling010 = 1010, // I-SWZ001010 32 | kGULSwizzlerMessageCodeAppDelegateSwizzling011 = 1011, // I-SWZ001011 33 | kGULSwizzlerMessageCodeAppDelegateSwizzling012 = 1012, // I-SWZ001012 34 | kGULSwizzlerMessageCodeAppDelegateSwizzling013 = 1013, // I-SWZ001013 35 | kGULSwizzlerMessageCodeAppDelegateSwizzlingInvalidAppDelegate = 1014, // I-SWZ001014 36 | 37 | // Scene Delegate Swizzling. 38 | kGULSwizzlerMessageCodeSceneDelegateSwizzling000 = 1100, // I-SWZ001100 39 | kGULSwizzlerMessageCodeSceneDelegateSwizzling001 = 1101, // I-SWZ001101 40 | kGULSwizzlerMessageCodeSceneDelegateSwizzling002 = 1102, // I-SWZ001102 41 | kGULSwizzlerMessageCodeSceneDelegateSwizzling003 = 1103, // I-SWZ001103 42 | kGULSwizzlerMessageCodeSceneDelegateSwizzling004 = 1104, // I-SWZ001104 43 | kGULSwizzlerMessageCodeSceneDelegateSwizzling005 = 1105, // I-SWZ001105 44 | kGULSwizzlerMessageCodeSceneDelegateSwizzling006 = 1106, // I-SWZ001106 45 | kGULSwizzlerMessageCodeSceneDelegateSwizzling007 = 1107, // I-SWZ001107 46 | kGULSwizzlerMessageCodeSceneDelegateSwizzling008 = 1108, // I-SWZ001108 47 | kGULSwizzlerMessageCodeSceneDelegateSwizzling009 = 1109, // I-SWZ001109 48 | kGULSwizzlerMessageCodeSceneDelegateSwizzling010 = 1110, // I-SWZ001110 49 | kGULSwizzlerMessageCodeSceneDelegateSwizzling011 = 1111, // I-SWZ001111 50 | kGULSwizzlerMessageCodeSceneDelegateSwizzling012 = 1112, // I-SWZ001112 51 | kGULSwizzlerMessageCodeSceneDelegateSwizzling013 = 1113, // I-SWZ001113 52 | kGULSwizzlerMessageCodeSceneDelegateSwizzlingInvalidSceneDelegate = 1114, // I-SWZ001114 53 | 54 | // Method Swizzling. 55 | kGULSwizzlerMessageCodeMethodSwizzling000 = 2000, // I-SWZ002000 56 | }; 57 | -------------------------------------------------------------------------------- /GoogleUtilities/Environment/NetworkInfo/GULNetworkInfo.m: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import "GoogleUtilities/Environment/Public/GoogleUtilities/GULNetworkInfo.h" 16 | 17 | #import 18 | 19 | #import 20 | #if __has_include("CoreTelephony/CTTelephonyNetworkInfo.h") && !TARGET_OS_MACCATALYST && \ 21 | !TARGET_OS_OSX && !TARGET_OS_TV && !TARGET_OS_WATCH 22 | #define TARGET_HAS_MOBILE_CONNECTIVITY 23 | #import 24 | #import 25 | #endif 26 | 27 | @implementation GULNetworkInfo 28 | 29 | #ifdef TARGET_HAS_MOBILE_CONNECTIVITY 30 | + (CTTelephonyNetworkInfo *)getNetworkInfo { 31 | static CTTelephonyNetworkInfo *networkInfo; 32 | static dispatch_once_t onceToken; 33 | dispatch_once(&onceToken, ^{ 34 | networkInfo = [[CTTelephonyNetworkInfo alloc] init]; 35 | }); 36 | return networkInfo; 37 | } 38 | #endif 39 | 40 | + (GULNetworkType)getNetworkType { 41 | GULNetworkType networkType = GULNetworkTypeNone; 42 | 43 | #ifdef TARGET_HAS_MOBILE_CONNECTIVITY 44 | static SCNetworkReachabilityRef reachabilityRef = 0; 45 | static dispatch_once_t onceToken; 46 | dispatch_once(&onceToken, ^{ 47 | reachabilityRef = SCNetworkReachabilityCreateWithName(kCFAllocatorSystemDefault, "google.com"); 48 | }); 49 | 50 | if (!reachabilityRef) { 51 | return GULNetworkTypeNone; 52 | } 53 | 54 | SCNetworkReachabilityFlags reachabilityFlags = 0; 55 | SCNetworkReachabilityGetFlags(reachabilityRef, &reachabilityFlags); 56 | 57 | // Parse the network flags to set the network type. 58 | if (reachabilityFlags & kSCNetworkReachabilityFlagsReachable) { 59 | if (reachabilityFlags & kSCNetworkReachabilityFlagsIsWWAN) { 60 | networkType = GULNetworkTypeMobile; 61 | } else { 62 | networkType = GULNetworkTypeWIFI; 63 | } 64 | } 65 | #endif 66 | 67 | return networkType; 68 | } 69 | 70 | + (NSString *)getNetworkRadioType { 71 | #ifdef TARGET_HAS_MOBILE_CONNECTIVITY 72 | CTTelephonyNetworkInfo *networkInfo = [GULNetworkInfo getNetworkInfo]; 73 | if (networkInfo.serviceCurrentRadioAccessTechnology.count) { 74 | return networkInfo.serviceCurrentRadioAccessTechnology.allValues[0] ?: @""; 75 | } 76 | #endif 77 | return @""; 78 | } 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | NS_ASSUME_NONNULL_BEGIN 20 | 21 | @interface GULAppEnvironmentUtil : NSObject 22 | 23 | /// Indicates whether the app is from Apple Store or not. Returns NO if the app is on simulator, 24 | /// development environment or sideloaded. 25 | + (BOOL)isFromAppStore; 26 | 27 | /// Indicates whether the app is a Testflight app. Returns YES if the app has sandbox receipt. 28 | /// Returns NO otherwise. 29 | + (BOOL)isAppStoreReceiptSandbox; 30 | 31 | /// Indicates whether the app is on simulator or not at runtime depending on the device 32 | /// architecture. 33 | + (BOOL)isSimulator; 34 | 35 | /// The current device model. Returns an empty string if device model cannot be retrieved. 36 | + (nullable NSString *)deviceModel; 37 | 38 | /// The current device model, with simulator-specific values. Returns an empty string if device 39 | /// model cannot be retrieved. 40 | + (nullable NSString *)deviceSimulatorModel; 41 | 42 | /// The current operating system version. Returns an empty string if the system version cannot be 43 | /// retrieved. 44 | + (NSString *)systemVersion; 45 | 46 | /// Indicates whether it is running inside an extension or an app. 47 | + (BOOL)isAppExtension; 48 | 49 | /// Indicates whether it is running inside an app clip or a full app. 50 | + (BOOL)isAppClip; 51 | 52 | /// Indicates whether the current target supports background URL session uploads. 53 | /// App extensions and app clips do not support background URL sessions. 54 | + (BOOL)supportsBackgroundURLSessionUploads; 55 | 56 | /// @return An Apple platform. Possible values "ios", "tvos", "macos", "watchos", "maccatalyst", and 57 | /// "visionos". 58 | + (NSString *)applePlatform; 59 | 60 | /// @return An Apple Device platform. Same possible values as `applePlatform`, with the addition of 61 | /// "ipados". 62 | + (NSString *)appleDevicePlatform; 63 | 64 | /// @return The way the library was added to the app, e.g. "swiftpm", "cocoapods", etc. 65 | + (NSString *)deploymentType; 66 | 67 | @end 68 | 69 | NS_ASSUME_NONNULL_END 70 | -------------------------------------------------------------------------------- /GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainStorage.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | NS_ASSUME_NONNULL_BEGIN 20 | 21 | /// The class provides a convenient, multiplatform abstraction of the Keychain. 22 | /// 23 | /// When using this API on macOS, the corresponding target must be signed with a provisioning 24 | /// profile that has the Keychain Sharing capability enabled. 25 | @interface GULKeychainStorage : NSObject 26 | 27 | - (instancetype)init NS_UNAVAILABLE; 28 | 29 | /** Initializes the keychain storage with Keychain Service name. 30 | * @param service A Keychain Service name that will be used to store and retrieve objects. See also 31 | * `kSecAttrService`. 32 | */ 33 | - (instancetype)initWithService:(NSString *)service; 34 | 35 | /// Get an object by key. 36 | /// @param key The key. 37 | /// @param objectClass The expected object class required by `NSSecureCoding`. 38 | /// @param accessGroup The Keychain Access Group. 39 | /// @param completionHandler The completion handler to call when the 40 | /// synchronized keychain read is complete. An error is passed to the 41 | /// completion handler if the keychain read fails. Else, the object stored in 42 | /// the keychain, or `nil` if it does not exist, is passed to the completion 43 | /// handler. 44 | - (void)getObjectForKey:(NSString *)key 45 | objectClass:(Class)objectClass 46 | accessGroup:(nullable NSString *)accessGroup 47 | completionHandler: 48 | (void (^)(id _Nullable obj, NSError *_Nullable error))completionHandler; 49 | 50 | /// Saves the given object by the given key. 51 | /// @param object The object to store. 52 | /// @param key The key to store the object. If there is an existing object by the key, it will be 53 | /// overridden. 54 | /// @param accessGroup The Keychain Access Group. 55 | /// @param completionHandler The completion handler to call when the 56 | /// synchronized keychain write is complete. An error is passed to the 57 | /// completion handler if the keychain read fails. Else, the object written to 58 | /// the keychain is passed to the completion handler. 59 | - (void)setObject:(id)object 60 | forKey:(NSString *)key 61 | accessGroup:(nullable NSString *)accessGroup 62 | completionHandler: 63 | (void (^)(id _Nullable obj, NSError *_Nullable error))completionHandler; 64 | 65 | /// Removes the object by the given key. 66 | /// @param key The key to store the object. If there is an existing object by 67 | /// the key, it will be overridden. 68 | /// @param accessGroup The Keychain Access Group. 69 | /// @param completionHandler The completion handler to call when the 70 | /// synchronized keychain removal is complete. An error is passed to the 71 | /// completion handler if the keychain removal fails. 72 | - (void)removeObjectForKey:(NSString *)key 73 | accessGroup:(nullable NSString *)accessGroup 74 | completionHandler:(void (^)(NSError *_Nullable error))completionHandler; 75 | 76 | #if TARGET_OS_OSX 77 | /// If not `nil`, then only this keychain will be used to save and read data (see 78 | /// `kSecMatchSearchList` and `kSecUseKeychain`. It is mostly intended to be used by unit tests. 79 | @property(nonatomic, nullable) SecKeychainRef keychainRef; 80 | #endif // TARGET_OS_OSX 81 | 82 | @end 83 | 84 | NS_ASSUME_NONNULL_END 85 | -------------------------------------------------------------------------------- /GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainUtils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | NS_ASSUME_NONNULL_BEGIN 20 | 21 | FOUNDATION_EXPORT NSString *const kGULKeychainUtilsErrorDomain; 22 | 23 | /// A collection of helper functions that abstract away common Keychain operations. 24 | /// 25 | /// When using this API on macOS, the corresponding target must be signed with a provisioning 26 | /// profile that has the Keychain Sharing capability enabled. 27 | @interface GULKeychainUtils : NSObject 28 | 29 | /** Fetches a keychain item data matching to the provided query. 30 | * @param query A dictionary with Keychain query parameters. See docs for `SecItemCopyMatching` for 31 | * details. 32 | * @param outError A pointer to `NSError` instance or `NULL`. The instance at `outError` will be 33 | * assigned with an error if there is. 34 | * @returns Data for the first Keychain Item matching the provided query or `nil` if there is not 35 | * such an item (`outError` will be `nil` in this case) or an error occurred. 36 | */ 37 | + (nullable NSData *)getItemWithQuery:(NSDictionary *)query 38 | error:(NSError *_Nullable *_Nullable)outError; 39 | 40 | /** Stores data to a Keychain Item matching to the provided query. An existing Keychain Item 41 | * matching the query parameters will be updated or a new will be created. 42 | * @param item A Keychain Item data to store. 43 | * @param query A dictionary with Keychain query parameters. See docs for `SecItemAdd` and 44 | * `SecItemUpdate` for details. 45 | * @param outError A pointer to `NSError` instance or `NULL`. The instance at `outError` will be 46 | * assigned with an error if there is. 47 | * @returns `YES` when data was successfully stored, `NO` otherwise. 48 | */ 49 | + (BOOL)setItem:(NSData *)item 50 | withQuery:(NSDictionary *)query 51 | error:(NSError *_Nullable *_Nullable)outError; 52 | 53 | /** Removes a Keychain Item matching to the provided query. 54 | * @param query A dictionary with Keychain query parameters. See docs for `SecItemDelete` for 55 | * details. 56 | * @param outError A pointer to `NSError` instance or `NULL`. The instance at `outError` will be 57 | * assigned with an error if there is. 58 | * @returns `YES` if the item was removed successfully or doesn't exist, `NO` otherwise. 59 | */ 60 | + (BOOL)removeItemWithQuery:(NSDictionary *)query error:(NSError *_Nullable *_Nullable)outError; 61 | 62 | @end 63 | 64 | NS_ASSUME_NONNULL_END 65 | -------------------------------------------------------------------------------- /GoogleUtilities/Environment/Public/GoogleUtilities/GULNetworkInfo.h: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import 16 | 17 | NS_ASSUME_NONNULL_BEGIN 18 | 19 | /// The type of network that the device is running with. Values should correspond to the NetworkType 20 | /// values in android/play/playlog/proto/clientanalytics.proto 21 | typedef NS_ENUM(NSInteger, GULNetworkType) { 22 | GULNetworkTypeNone = -1, 23 | GULNetworkTypeMobile = 0, 24 | GULNetworkTypeWIFI = 1, 25 | }; 26 | 27 | /// Collection of utilities to read network status information 28 | @interface GULNetworkInfo : NSObject 29 | 30 | /// Returns an enum indicating the network type. The enum values should be easily transferrable to 31 | /// the NetworkType value in android/play/playlog/proto/clientanalytics.proto. Right now this always 32 | /// returns None on platforms other than iOS. This should be updated in the future to return Wi-Fi 33 | /// values for the other platforms when applicable. 34 | + (GULNetworkType)getNetworkType; 35 | 36 | /// Returns a string indicating the radio access technology used by the app. The return value will 37 | /// be one of CTRadioAccess constants defined in 38 | /// https://developer.apple.com/documentation/coretelephony/cttelephonynetworkinfo/radio_access_technology_constants 39 | + (NSString *)getNetworkRadioType; 40 | 41 | @end 42 | 43 | NS_ASSUME_NONNULL_END 44 | -------------------------------------------------------------------------------- /GoogleUtilities/Environment/Resources/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyTracking 6 | 7 | NSPrivacyTrackingDomains 8 | 9 | 10 | NSPrivacyCollectedDataTypes 11 | 12 | 13 | NSPrivacyAccessedAPITypes 14 | 15 | 16 | NSPrivacyAccessedAPIType 17 | NSPrivacyAccessedAPICategoryUserDefaults 18 | NSPrivacyAccessedAPITypeReasons 19 | 20 | C56D.1 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /GoogleUtilities/Environment/SecureStorage/GULKeychainUtils.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import "GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainUtils.h" 18 | 19 | NSString *const kGULKeychainUtilsErrorDomain = @"com.gul.keychain.ErrorDomain"; 20 | 21 | @implementation GULKeychainUtils 22 | 23 | + (nullable NSData *)getItemWithQuery:(NSDictionary *)query 24 | error:(NSError *_Nullable *_Nullable)outError { 25 | NSMutableDictionary *mutableGetItemQuery = 26 | [[[self class] multiplatformQueryWithQuery:query] mutableCopy]; 27 | 28 | mutableGetItemQuery[(__bridge id)kSecReturnData] = @YES; 29 | mutableGetItemQuery[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne; 30 | 31 | CFDataRef result = NULL; 32 | OSStatus status = 33 | SecItemCopyMatching((__bridge CFDictionaryRef)mutableGetItemQuery, (CFTypeRef *)&result); 34 | 35 | if (status == errSecSuccess && result != NULL) { 36 | if (outError) { 37 | *outError = nil; 38 | } 39 | 40 | return (__bridge_transfer NSData *)result; 41 | } 42 | 43 | if (status == errSecItemNotFound) { 44 | if (outError) { 45 | *outError = nil; 46 | } 47 | } else { 48 | if (outError) { 49 | *outError = [self keychainErrorWithFunction:@"SecItemCopyMatching" status:status]; 50 | } 51 | } 52 | return nil; 53 | } 54 | 55 | + (BOOL)setItem:(NSData *)item 56 | withQuery:(NSDictionary *)query 57 | error:(NSError *_Nullable *_Nullable)outError { 58 | NSDictionary *multiplatformQuery = [[self class] multiplatformQueryWithQuery:query]; 59 | 60 | NSData *existingItem = [self getItemWithQuery:multiplatformQuery error:outError]; 61 | if (outError && *outError) { 62 | return NO; 63 | } 64 | 65 | OSStatus status; 66 | if (!existingItem) { 67 | NSMutableDictionary *mutableAddItemQuery = [multiplatformQuery mutableCopy]; 68 | mutableAddItemQuery[(__bridge id)kSecAttrAccessible] = 69 | (__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly; 70 | mutableAddItemQuery[(__bridge id)kSecValueData] = item; 71 | 72 | status = SecItemAdd((__bridge CFDictionaryRef)mutableAddItemQuery, NULL); 73 | } else { 74 | NSDictionary *attributes = @{(__bridge id)kSecValueData : item}; 75 | status = SecItemUpdate((__bridge CFDictionaryRef)multiplatformQuery, 76 | (__bridge CFDictionaryRef)attributes); 77 | } 78 | 79 | if (status == noErr) { 80 | if (outError) { 81 | *outError = nil; 82 | } 83 | return YES; 84 | } 85 | 86 | NSString *function = existingItem ? @"SecItemUpdate" : @"SecItemAdd"; 87 | if (outError) { 88 | *outError = [self keychainErrorWithFunction:function status:status]; 89 | } 90 | return NO; 91 | } 92 | 93 | + (BOOL)removeItemWithQuery:(NSDictionary *)query error:(NSError *_Nullable *_Nullable)outError { 94 | NSDictionary *deleteItemQuery = [[self class] multiplatformQueryWithQuery:query]; 95 | 96 | OSStatus status = SecItemDelete((__bridge CFDictionaryRef)deleteItemQuery); 97 | 98 | if (status == noErr || status == errSecItemNotFound) { 99 | if (outError) { 100 | *outError = nil; 101 | } 102 | return YES; 103 | } 104 | 105 | if (outError) { 106 | *outError = [self keychainErrorWithFunction:@"SecItemDelete" status:status]; 107 | } 108 | return NO; 109 | } 110 | 111 | #pragma mark - Private 112 | 113 | /// Returns a `NSDictionary` query that behaves the same across all platforms. 114 | /// - Note: In practice, this API only makes a difference to keychain queries on macOS. 115 | /// See go/firebase-macos-keychain-popups for details. 116 | /// - Parameter query: A query to create the protected keychain query with. 117 | + (NSDictionary *)multiplatformQueryWithQuery:(NSDictionary *)query { 118 | NSMutableDictionary *multiplatformQuery = [query mutableCopy]; 119 | if (@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *)) { 120 | multiplatformQuery[(__bridge id)kSecUseDataProtectionKeychain] = (__bridge id)kCFBooleanTrue; 121 | } 122 | return [multiplatformQuery copy]; 123 | } 124 | 125 | #pragma mark - Errors 126 | 127 | + (NSError *)keychainErrorWithFunction:(NSString *)keychainFunction status:(OSStatus)status { 128 | NSString *failureReason = [NSString stringWithFormat:@"%@ (%li)", keychainFunction, (long)status]; 129 | NSDictionary *userInfo = @{NSLocalizedFailureReasonErrorKey : failureReason}; 130 | return [NSError errorWithDomain:kGULKeychainUtilsErrorDomain code:0 userInfo:userInfo]; 131 | } 132 | 133 | @end 134 | -------------------------------------------------------------------------------- /GoogleUtilities/Logger/Public/GoogleUtilities/GULLoggerLevel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Google 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | NS_ASSUME_NONNULL_BEGIN 20 | 21 | /// The log levels used by internal logging. 22 | typedef NS_ENUM(NSInteger, GULLoggerLevel) { 23 | /// Error level, corresponding to `OS_LOG_TYPE_ERROR`. 24 | GULLoggerLevelError = 3, // For backwards compatibility, the enum value matches `ASL_LEVEL_ERR`. 25 | 26 | /// Warning level, corresponding to `OS_LOG_TYPE_DEFAULT`. 27 | /// 28 | /// > Note: Since OSLog doesn't have a WARNING type, this is equivalent to `GULLoggerLevelNotice`. 29 | GULLoggerLevelWarning = 4, // For backwards compatibility, the value matches `ASL_LEVEL_WARNING`. 30 | 31 | /// Notice level, corresponding to `OS_LOG_TYPE_DEFAULT`. 32 | GULLoggerLevelNotice = 5, // For backwards compatibility, the value matches `ASL_LEVEL_NOTICE`. 33 | 34 | /// Info level, corresponding to `OS_LOG_TYPE_INFO`. 35 | GULLoggerLevelInfo = 6, // For backwards compatibility, the enum value matches `ASL_LEVEL_INFO`. 36 | 37 | /// Debug level, corresponding to `OS_LOG_TYPE_DEBUG`. 38 | GULLoggerLevelDebug = 7, // For backwards compatibility, the value matches `ASL_LEVEL_DEBUG`. 39 | 40 | /// The minimum (most severe) supported logging level. 41 | GULLoggerLevelMin = GULLoggerLevelError, 42 | 43 | /// The maximum (least severe) supported logging level. 44 | GULLoggerLevelMax = GULLoggerLevelDebug 45 | } NS_SWIFT_NAME(GoogleLoggerLevel); 46 | 47 | NS_ASSUME_NONNULL_END 48 | -------------------------------------------------------------------------------- /GoogleUtilities/Logger/Resources/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyTracking 6 | 7 | NSPrivacyTrackingDomains 8 | 9 | 10 | NSPrivacyCollectedDataTypes 11 | 12 | 13 | NSPrivacyAccessedAPITypes 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /GoogleUtilities/MethodSwizzler/GULSwizzler.m: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import "GoogleUtilities/MethodSwizzler/Public/GoogleUtilities/GULSwizzler.h" 16 | 17 | #import 18 | 19 | #ifdef DEBUG 20 | #import "GoogleUtilities/Common/GULLoggerCodes.h" 21 | #import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" 22 | 23 | static GULLoggerService kGULLoggerSwizzler = @"[GoogleUtilities/MethodSwizzler]"; 24 | #endif 25 | 26 | dispatch_queue_t GetGULSwizzlingQueue(void) { 27 | static dispatch_queue_t queue; 28 | static dispatch_once_t onceToken; 29 | dispatch_once(&onceToken, ^{ 30 | queue = dispatch_queue_create("com.google.GULSwizzler", DISPATCH_QUEUE_SERIAL); 31 | }); 32 | return queue; 33 | } 34 | 35 | @implementation GULSwizzler 36 | 37 | + (void)swizzleClass:(Class)aClass 38 | selector:(SEL)selector 39 | isClassSelector:(BOOL)isClassSelector 40 | withBlock:(nullable id)block { 41 | dispatch_sync(GetGULSwizzlingQueue(), ^{ 42 | NSAssert(selector, @"The selector cannot be NULL"); 43 | NSAssert(aClass, @"The class cannot be Nil"); 44 | Class resolvedClass = aClass; 45 | Method method = nil; 46 | if (isClassSelector) { 47 | method = class_getClassMethod(aClass, selector); 48 | resolvedClass = object_getClass(aClass); 49 | } else { 50 | method = class_getInstanceMethod(aClass, selector); 51 | } 52 | NSAssert(method, @"You're attempting to swizzle a method that doesn't exist. (%@, %@)", 53 | NSStringFromClass(resolvedClass), NSStringFromSelector(selector)); 54 | IMP newImp = imp_implementationWithBlock(block); 55 | #ifdef DEBUG 56 | IMP currentImp = class_getMethodImplementation(resolvedClass, selector); 57 | Class class = NSClassFromString(@"GULSwizzlingCache"); 58 | if (class) { 59 | SEL cacheSelector = NSSelectorFromString(@"cacheCurrentIMP:forNewIMP:forClass:withSelector:"); 60 | NSMethodSignature *methodSignature = [class methodSignatureForSelector:cacheSelector]; 61 | if (methodSignature != nil) { 62 | NSInvocation *inv = [NSInvocation invocationWithMethodSignature:methodSignature]; 63 | [inv setSelector:cacheSelector]; 64 | [inv setTarget:class]; 65 | [inv setArgument:&(currentImp) atIndex:2]; 66 | [inv setArgument:&(newImp) atIndex:3]; 67 | [inv setArgument:&(resolvedClass) atIndex:4]; 68 | [inv setArgument:(void *_Nonnull)&(selector) atIndex:5]; 69 | [inv invoke]; 70 | } 71 | } 72 | #endif 73 | 74 | const char *typeEncoding = method_getTypeEncoding(method); 75 | __unused IMP originalImpOfClass = 76 | class_replaceMethod(resolvedClass, selector, newImp, typeEncoding); 77 | 78 | #ifdef DEBUG 79 | // If !originalImpOfClass, then the IMP came from a superclass. 80 | if (originalImpOfClass) { 81 | SEL selector = NSSelectorFromString(@"originalIMPOfCurrentIMP:"); 82 | NSMethodSignature *methodSignature = [class methodSignatureForSelector:selector]; 83 | if (methodSignature != nil) { 84 | NSInvocation *inv = [NSInvocation invocationWithMethodSignature:methodSignature]; 85 | [inv setSelector:selector]; 86 | [inv setTarget:class]; 87 | [inv setArgument:&(currentImp) atIndex:2]; 88 | [inv invoke]; 89 | IMP testOriginal; 90 | [inv getReturnValue:&testOriginal]; 91 | if (originalImpOfClass != testOriginal) { 92 | GULOSLogWarning( 93 | kGULLogSubsystem, kGULLoggerSwizzler, NO, 94 | [NSString 95 | stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeMethodSwizzling000], 96 | @"Swizzling class: %@ SEL:%@ after it has been previously been swizzled.", 97 | NSStringFromClass(resolvedClass), NSStringFromSelector(selector)); 98 | } 99 | } 100 | } 101 | #endif 102 | }); 103 | } 104 | 105 | + (nullable IMP)currentImplementationForClass:(Class)aClass 106 | selector:(SEL)selector 107 | isClassSelector:(BOOL)isClassSelector { 108 | NSAssert(selector, @"The selector cannot be NULL"); 109 | NSAssert(aClass, @"The class cannot be Nil"); 110 | if (selector == NULL || aClass == nil) { 111 | return nil; 112 | } 113 | __block IMP currentIMP = nil; 114 | dispatch_sync(GetGULSwizzlingQueue(), ^{ 115 | Method method = nil; 116 | if (isClassSelector) { 117 | method = class_getClassMethod(aClass, selector); 118 | } else { 119 | method = class_getInstanceMethod(aClass, selector); 120 | } 121 | NSAssert(method, @"The Method for this class/selector combo doesn't exist (%@, %@).", 122 | NSStringFromClass(aClass), NSStringFromSelector(selector)); 123 | if (method == nil) { 124 | return; 125 | } 126 | currentIMP = method_getImplementation(method); 127 | NSAssert(currentIMP, @"The IMP for this class/selector combo doesn't exist (%@, %@).", 128 | NSStringFromClass(aClass), NSStringFromSelector(selector)); 129 | }); 130 | return currentIMP; 131 | } 132 | 133 | + (BOOL)selector:(SEL)selector existsInClass:(Class)aClass isClassSelector:(BOOL)isClassSelector { 134 | Method method = isClassSelector ? class_getClassMethod(aClass, selector) 135 | : class_getInstanceMethod(aClass, selector); 136 | return method != nil; 137 | } 138 | 139 | + (NSArray *)ivarObjectsForObject:(id)object { 140 | NSMutableArray *array = [NSMutableArray array]; 141 | unsigned int count; 142 | Ivar *vars = class_copyIvarList([object class], &count); 143 | for (NSUInteger i = 0; i < count; i++) { 144 | const char *typeEncoding = ivar_getTypeEncoding(vars[i]); 145 | // Check to see if the ivar is an object. 146 | if (strncmp(typeEncoding, "@", 1) == 0) { 147 | id ivarObject = object_getIvar(object, vars[i]); 148 | [array addObject:ivarObject]; 149 | } 150 | } 151 | free(vars); 152 | return array; 153 | } 154 | @end 155 | -------------------------------------------------------------------------------- /GoogleUtilities/MethodSwizzler/Public/GoogleUtilities/GULSwizzler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | NS_ASSUME_NONNULL_BEGIN 20 | 21 | /** This class handles the runtime manipulation necessary to instrument selectors. It stores the 22 | * classes and selectors that have been swizzled, and runs all operations on its own queue. 23 | */ 24 | @interface GULSwizzler : NSObject 25 | 26 | /** Manipulates the Objective-C runtime to replace the original IMP with the supplied block. 27 | * 28 | * @param aClass The class to swizzle. 29 | * @param selector The selector of the class to swizzle. 30 | * @param isClassSelector A BOOL specifying whether the selector is a class or instance selector. 31 | * @param block The block that replaces the original IMP. 32 | */ 33 | + (void)swizzleClass:(Class)aClass 34 | selector:(SEL)selector 35 | isClassSelector:(BOOL)isClassSelector 36 | withBlock:(nullable id)block; 37 | 38 | /** Returns the current IMP for the given class and selector. 39 | * 40 | * @param aClass The class to use. 41 | * @param selector The selector to find the implementation of. 42 | * @param isClassSelector A BOOL specifying whether the selector is a class or instance selector. 43 | * @return The implementation of the selector in the runtime. 44 | */ 45 | + (nullable IMP)currentImplementationForClass:(Class)aClass 46 | selector:(SEL)selector 47 | isClassSelector:(BOOL)isClassSelector; 48 | 49 | /** Checks the runtime to see if a selector exists on a class. If a property is declared as 50 | * @dynamic, we have a reverse swizzling situation, where the implementation of a method exists 51 | * only in concrete subclasses, and NOT in the superclass. We can detect that situation using 52 | * this helper method. Similarly, we can detect situations where a class doesn't implement a 53 | * protocol method. 54 | * 55 | * @param selector The selector to check for. 56 | * @param aClass The class to check. 57 | * @param isClassSelector A BOOL specifying whether the selector is a class or instance selector. 58 | * @return YES if the method was found in this selector/class combination, NO otherwise. 59 | */ 60 | + (BOOL)selector:(SEL)selector existsInClass:(Class)aClass isClassSelector:(BOOL)isClassSelector; 61 | 62 | /** Returns a list of all Objective-C (and not primitive) ivars contained by the given object. 63 | * 64 | * @param object The object whose ivars will be iterated. 65 | * @return The list of ivar objects. 66 | */ 67 | + (NSArray *)ivarObjectsForObject:(id)object; 68 | 69 | @end 70 | 71 | NS_ASSUME_NONNULL_END 72 | -------------------------------------------------------------------------------- /GoogleUtilities/MethodSwizzler/Resources/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyTracking 6 | 7 | NSPrivacyTrackingDomains 8 | 9 | 10 | NSPrivacyCollectedDataTypes 11 | 12 | 13 | NSPrivacyAccessedAPITypes 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /GoogleUtilities/NSData+zlib/Public/GoogleUtilities/GULNSData+zlib.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import 16 | 17 | NS_ASSUME_NONNULL_BEGIN 18 | 19 | /// This is a copy of Google Toolbox for Mac library to avoid creating an extra framework. 20 | 21 | // NOTE: For 64bit, none of these apis handle input sizes >32bits, they will return nil when given 22 | // such data. To handle data of that size you really should be streaming it rather then doing it all 23 | // in memory. 24 | 25 | @interface NSData (GULGzip) 26 | 27 | /// Returns an data as the result of decompressing the payload of |data|.The data to decompress must 28 | /// be a gzipped payloads. 29 | + (nullable NSData *)gul_dataByInflatingGzippedData:(NSData *)data error:(NSError **)error; 30 | 31 | /// Returns an compressed data with the result of gzipping the payload of |data|. Uses the default 32 | /// compression level. 33 | + (nullable NSData *)gul_dataByGzippingData:(NSData *)data error:(NSError **)error; 34 | 35 | FOUNDATION_EXPORT NSString *const GULNSDataZlibErrorDomain; 36 | FOUNDATION_EXPORT NSString *const GULNSDataZlibErrorKey; // NSNumber 37 | FOUNDATION_EXPORT NSString *const GULNSDataZlibRemainingBytesKey; // NSNumber 38 | 39 | typedef NS_ENUM(NSInteger, GULNSDataZlibError) { 40 | GULNSDataZlibErrorGreaterThan32BitsToCompress = 1024, 41 | // An internal zlib error. 42 | // GULNSDataZlibErrorKey will contain the error value. 43 | // NSLocalizedDescriptionKey may contain an error string from zlib. 44 | // Look in zlib.h for list of errors. 45 | GULNSDataZlibErrorInternal, 46 | // There was left over data in the buffer that was not used. 47 | // GULNSDataZlibRemainingBytesKey will contain number of remaining bytes. 48 | GULNSDataZlibErrorDataRemaining 49 | }; 50 | 51 | @end 52 | 53 | NS_ASSUME_NONNULL_END 54 | -------------------------------------------------------------------------------- /GoogleUtilities/NSData+zlib/Resources/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyTracking 6 | 7 | NSPrivacyTrackingDomains 8 | 9 | 10 | NSPrivacyCollectedDataTypes 11 | 12 | 13 | NSPrivacyAccessedAPITypes 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /GoogleUtilities/Network/GULMutableDictionary.m: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Google 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" 16 | 17 | @implementation GULMutableDictionary { 18 | /// The mutable dictionary. 19 | NSMutableDictionary *_objects; 20 | 21 | /// Serial synchronization queue. All reads should use dispatch_sync, while writes use 22 | /// dispatch_async. 23 | dispatch_queue_t _queue; 24 | } 25 | 26 | - (instancetype)init { 27 | self = [super init]; 28 | 29 | if (self) { 30 | _objects = [[NSMutableDictionary alloc] init]; 31 | _queue = dispatch_queue_create("GULMutableDictionary", DISPATCH_QUEUE_SERIAL); 32 | } 33 | 34 | return self; 35 | } 36 | 37 | - (NSString *)description { 38 | __block NSString *description; 39 | dispatch_sync(_queue, ^{ 40 | description = self->_objects.description; 41 | }); 42 | return description; 43 | } 44 | 45 | - (id)objectForKey:(id)key { 46 | __block id object; 47 | dispatch_sync(_queue, ^{ 48 | object = [self->_objects objectForKey:key]; 49 | }); 50 | return object; 51 | } 52 | 53 | - (void)setObject:(id)object forKey:(id)key { 54 | dispatch_async(_queue, ^{ 55 | [self->_objects setObject:object forKey:key]; 56 | }); 57 | } 58 | 59 | - (void)removeObjectForKey:(id)key { 60 | dispatch_async(_queue, ^{ 61 | [self->_objects removeObjectForKey:key]; 62 | }); 63 | } 64 | 65 | - (void)removeAllObjects { 66 | dispatch_async(_queue, ^{ 67 | [self->_objects removeAllObjects]; 68 | }); 69 | } 70 | 71 | - (NSUInteger)count { 72 | __block NSUInteger count; 73 | dispatch_sync(_queue, ^{ 74 | count = self->_objects.count; 75 | }); 76 | return count; 77 | } 78 | 79 | - (id)objectForKeyedSubscript:(id)key { 80 | __block id object; 81 | dispatch_sync(_queue, ^{ 82 | object = self->_objects[key]; 83 | }); 84 | return object; 85 | } 86 | 87 | - (void)setObject:(id)obj forKeyedSubscript:(id)key { 88 | dispatch_async(_queue, ^{ 89 | self->_objects[key] = obj; 90 | }); 91 | } 92 | 93 | - (NSDictionary *)dictionary { 94 | __block NSDictionary *dictionary; 95 | dispatch_sync(_queue, ^{ 96 | dictionary = [self->_objects copy]; 97 | }); 98 | return dictionary; 99 | } 100 | 101 | @end 102 | -------------------------------------------------------------------------------- /GoogleUtilities/Network/GULNetworkConstants.m: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Google 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import "GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h" 16 | #import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" 17 | 18 | #import 19 | 20 | NSString *const kGULNetworkBackgroundSessionConfigIDPrefix = @"com.gul.network.background-upload"; 21 | NSString *const kGULNetworkApplicationSupportSubdirectory = @"GUL/Network"; 22 | NSString *const kGULNetworkTempDirectoryName = @"GULNetworkTemporaryDirectory"; 23 | const NSTimeInterval kGULNetworkTempFolderExpireTime = 60 * 60; // 1 hour 24 | const NSTimeInterval kGULNetworkTimeOutInterval = 60; // 1 minute. 25 | NSString *const kGULNetworkReachabilityHost = @"app-measurement.com"; 26 | NSString *const kGULNetworkErrorContext = @"Context"; 27 | 28 | const int kGULNetworkHTTPStatusOK = 200; 29 | const int kGULNetworkHTTPStatusNoContent = 204; 30 | const int kGULNetworkHTTPStatusCodeMultipleChoices = 300; 31 | const int kGULNetworkHTTPStatusCodeMovedPermanently = 301; 32 | const int kGULNetworkHTTPStatusCodeFound = 302; 33 | const int kGULNetworkHTTPStatusCodeNotModified = 304; 34 | const int kGULNetworkHTTPStatusCodeMovedTemporarily = 307; 35 | const int kGULNetworkHTTPStatusCodeNotFound = 404; 36 | const int kGULNetworkHTTPStatusCodeCannotAcceptTraffic = 429; 37 | const int kGULNetworkHTTPStatusCodeUnavailable = 503; 38 | 39 | NSString *const kGULNetworkErrorDomain = @"com.gul.network.ErrorDomain"; 40 | 41 | GULLoggerService kGULLoggerNetwork = @"[GULNetwork]"; 42 | -------------------------------------------------------------------------------- /GoogleUtilities/Network/GULNetworkInternal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | #import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" 20 | 21 | extern NSString *const kGULNetworkErrorDomain; 22 | 23 | /// The logger service for GULNetwork. 24 | extern GULLoggerService kGULLoggerNetwork; 25 | -------------------------------------------------------------------------------- /GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | NS_ASSUME_NONNULL_BEGIN 20 | 21 | /// A mutable dictionary that provides atomic accessor and mutators. 22 | @interface GULMutableDictionary : NSObject 23 | 24 | /// Returns an object given a key in the dictionary or nil if not found. 25 | - (id)objectForKey:(id)key; 26 | 27 | /// Updates the object given its key or adds it to the dictionary if it is not in the dictionary. 28 | - (void)setObject:(id)object forKey:(id)key; 29 | 30 | /// Removes the object given its session ID from the dictionary. 31 | - (void)removeObjectForKey:(id)key; 32 | 33 | /// Removes all objects. 34 | - (void)removeAllObjects; 35 | 36 | /// Returns the number of current objects in the dictionary. 37 | - (NSUInteger)count; 38 | 39 | /// Returns an object given a key in the dictionary or nil if not found. 40 | - (id)objectForKeyedSubscript:(id)key; 41 | 42 | /// Updates the object given its key or adds it to the dictionary if it is not in the dictionary. 43 | - (void)setObject:(id)obj forKeyedSubscript:(id)key; 44 | 45 | /// Returns the immutable dictionary. 46 | - (NSDictionary *)dictionary; 47 | 48 | @end 49 | 50 | NS_ASSUME_NONNULL_END 51 | -------------------------------------------------------------------------------- /GoogleUtilities/Network/Public/GoogleUtilities/GULNetwork.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | #import "GULNetworkConstants.h" 20 | #import "GULNetworkLoggerProtocol.h" 21 | #import "GULNetworkURLSession.h" 22 | 23 | NS_ASSUME_NONNULL_BEGIN 24 | 25 | /// Delegate protocol for GULNetwork events. 26 | @protocol GULNetworkReachabilityDelegate 27 | 28 | /// Tells the delegate to handle events when the network reachability changes to connected or not 29 | /// connected. 30 | - (void)reachabilityDidChange; 31 | 32 | @end 33 | 34 | /// The Network component that provides network status and handles network requests and responses. 35 | /// This is not thread safe. 36 | /// 37 | /// NOTE: 38 | /// User must add FIRAnalytics handleEventsForBackgroundURLSessionID:completionHandler to the 39 | /// AppDelegate application:handleEventsForBackgroundURLSession:completionHandler: 40 | @interface GULNetwork : NSObject 41 | 42 | /// Indicates if network connectivity is available. 43 | @property(nonatomic, readonly, getter=isNetworkConnected) BOOL networkConnected; 44 | 45 | /// Indicates if there are any uploads in progress. 46 | @property(nonatomic, readonly, getter=hasUploadInProgress) BOOL uploadInProgress; 47 | 48 | /// An optional delegate that can be used in the event when network reachability changes. 49 | @property(nonatomic, weak) id reachabilityDelegate; 50 | 51 | /// An optional delegate that can be used to log messages, warnings or errors that occur in the 52 | /// network operations. 53 | @property(nonatomic, weak) id loggerDelegate; 54 | 55 | /// Indicates whether the logger should display debug messages. 56 | @property(nonatomic, assign) BOOL isDebugModeEnabled; 57 | 58 | /// The time interval in seconds for the network request to timeout. 59 | @property(nonatomic, assign) NSTimeInterval timeoutInterval; 60 | 61 | /// Initializes with the default reachability host. 62 | - (instancetype)init; 63 | 64 | /// Initializes with a custom reachability host. 65 | - (instancetype)initWithReachabilityHost:(NSString *)reachabilityHost; 66 | 67 | /// Handles events when background session with the given ID has finished. 68 | + (void)handleEventsForBackgroundURLSessionID:(NSString *)sessionID 69 | completionHandler:(GULNetworkSystemCompletionHandler)completionHandler; 70 | 71 | /// Compresses and sends a POST request with the provided data to the URL. The session will be 72 | /// background session if usingBackgroundSession is YES. Otherwise, the POST session is default 73 | /// session. Returns a session ID or nil if an error occurs. 74 | - (nullable NSString *)postURL:(NSURL *)url 75 | payload:(NSData *)payload 76 | queue:(nullable dispatch_queue_t)queue 77 | usingBackgroundSession:(BOOL)usingBackgroundSession 78 | completionHandler:(GULNetworkCompletionHandler)handler; 79 | 80 | /// Compresses and sends a POST request with the provided headers and data to the URL. The session 81 | /// will be background session if usingBackgroundSession is YES. Otherwise, the POST session is 82 | /// default session. Returns a session ID or nil if an error occurs. 83 | - (nullable NSString *)postURL:(NSURL *)url 84 | headers:(nullable NSDictionary *)headers 85 | payload:(NSData *)payload 86 | queue:(nullable dispatch_queue_t)queue 87 | usingBackgroundSession:(BOOL)usingBackgroundSession 88 | completionHandler:(GULNetworkCompletionHandler)handler; 89 | 90 | /// Sends a GET request with the provided data to the URL. The session will be background session 91 | /// if usingBackgroundSession is YES. Otherwise, the GET session is default session. Returns a 92 | /// session ID or nil if an error occurs. 93 | - (nullable NSString *)getURL:(NSURL *)url 94 | headers:(nullable NSDictionary *)headers 95 | queue:(nullable dispatch_queue_t)queue 96 | usingBackgroundSession:(BOOL)usingBackgroundSession 97 | completionHandler:(GULNetworkCompletionHandler)handler; 98 | 99 | @end 100 | 101 | NS_ASSUME_NONNULL_END 102 | -------------------------------------------------------------------------------- /GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | NS_ASSUME_NONNULL_BEGIN 20 | 21 | /// Error codes in Firebase Network error domain. 22 | /// Note: these error codes should never change. It would make it harder to decode the errors if 23 | /// we inadvertently altered any of these codes in a future SDK version. 24 | typedef NS_ENUM(NSInteger, GULNetworkErrorCode) { 25 | /// Unknown error. 26 | GULNetworkErrorCodeUnknown = 0, 27 | /// Error occurs when the request URL is invalid. 28 | GULErrorCodeNetworkInvalidURL = 1, 29 | /// Error occurs when request cannot be constructed. 30 | GULErrorCodeNetworkRequestCreation = 2, 31 | /// Error occurs when payload cannot be compressed. 32 | GULErrorCodeNetworkPayloadCompression = 3, 33 | /// Error occurs when session task cannot be created. 34 | GULErrorCodeNetworkSessionTaskCreation = 4, 35 | /// Error occurs when there is no response. 36 | GULErrorCodeNetworkInvalidResponse = 5 37 | }; 38 | 39 | #pragma mark - Network constants 40 | 41 | /// The prefix of the ID of the background session. 42 | extern NSString *const kGULNetworkBackgroundSessionConfigIDPrefix; 43 | 44 | /// The sub directory to store the files of data that is being uploaded in the background. 45 | extern NSString *const kGULNetworkApplicationSupportSubdirectory; 46 | 47 | /// Name of the temporary directory that stores files for background uploading. 48 | extern NSString *const kGULNetworkTempDirectoryName; 49 | 50 | /// The period when the temporary uploading file can stay. 51 | extern const NSTimeInterval kGULNetworkTempFolderExpireTime; 52 | 53 | /// The default network request timeout interval. 54 | extern const NSTimeInterval kGULNetworkTimeOutInterval; 55 | 56 | /// The host to check the reachability of the network. 57 | extern NSString *const kGULNetworkReachabilityHost; 58 | 59 | /// The key to get the error context of the UserInfo. 60 | extern NSString *const kGULNetworkErrorContext; 61 | 62 | #pragma mark - Network Status Code 63 | 64 | extern const int kGULNetworkHTTPStatusOK; 65 | extern const int kGULNetworkHTTPStatusNoContent; 66 | extern const int kGULNetworkHTTPStatusCodeMultipleChoices; 67 | extern const int kGULNetworkHTTPStatusCodeMovedPermanently; 68 | extern const int kGULNetworkHTTPStatusCodeFound; 69 | extern const int kGULNetworkHTTPStatusCodeNotModified; 70 | extern const int kGULNetworkHTTPStatusCodeMovedTemporarily; 71 | extern const int kGULNetworkHTTPStatusCodeNotFound; 72 | extern const int kGULNetworkHTTPStatusCodeCannotAcceptTraffic; 73 | extern const int kGULNetworkHTTPStatusCodeUnavailable; 74 | 75 | NS_ASSUME_NONNULL_END 76 | -------------------------------------------------------------------------------- /GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkLoggerProtocol.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | #import "GULNetworkMessageCode.h" 20 | 21 | NS_ASSUME_NONNULL_BEGIN 22 | 23 | /// The log levels used by GULNetworkLogger. 24 | typedef NS_ENUM(NSInteger, GULNetworkLogLevel) { 25 | kGULNetworkLogLevelError = 3, 26 | kGULNetworkLogLevelWarning = 4, 27 | kGULNetworkLogLevelInfo = 6, 28 | kGULNetworkLogLevelDebug = 7, 29 | }; 30 | 31 | @protocol GULNetworkLoggerDelegate 32 | 33 | @required 34 | /// Tells the delegate to log a message with an array of contexts and the log level. 35 | - (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel 36 | messageCode:(GULNetworkMessageCode)messageCode 37 | message:(NSString *)message 38 | contexts:(NSArray *)contexts; 39 | 40 | /// Tells the delegate to log a message with a context and the log level. 41 | - (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel 42 | messageCode:(GULNetworkMessageCode)messageCode 43 | message:(NSString *)message 44 | context:(id)context; 45 | 46 | /// Tells the delegate to log a message with the log level. 47 | - (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel 48 | messageCode:(GULNetworkMessageCode)messageCode 49 | message:(NSString *)message; 50 | 51 | @end 52 | 53 | NS_ASSUME_NONNULL_END 54 | -------------------------------------------------------------------------------- /GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkMessageCode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | NS_ASSUME_NONNULL_BEGIN 20 | 21 | // Make sure these codes do not overlap with any contained in the FIRAMessageCode enum. 22 | typedef NS_ENUM(NSInteger, GULNetworkMessageCode) { 23 | // GULNetwork.m 24 | kGULNetworkMessageCodeNetwork000 = 900000, // I-NET900000 25 | kGULNetworkMessageCodeNetwork001 = 900001, // I-NET900001 26 | kGULNetworkMessageCodeNetwork002 = 900002, // I-NET900002 27 | kGULNetworkMessageCodeNetwork003 = 900003, // I-NET900003 28 | // GULNetworkURLSession.m 29 | kGULNetworkMessageCodeURLSession000 = 901000, // I-NET901000 30 | kGULNetworkMessageCodeURLSession001 = 901001, // I-NET901001 31 | kGULNetworkMessageCodeURLSession002 = 901002, // I-NET901002 32 | kGULNetworkMessageCodeURLSession003 = 901003, // I-NET901003 33 | kGULNetworkMessageCodeURLSession004 = 901004, // I-NET901004 34 | kGULNetworkMessageCodeURLSession005 = 901005, // I-NET901005 35 | kGULNetworkMessageCodeURLSession006 = 901006, // I-NET901006 36 | kGULNetworkMessageCodeURLSession007 = 901007, // I-NET901007 37 | kGULNetworkMessageCodeURLSession008 = 901008, // I-NET901008 38 | kGULNetworkMessageCodeURLSession009 = 901009, // I-NET901009 39 | kGULNetworkMessageCodeURLSession010 = 901010, // I-NET901010 40 | kGULNetworkMessageCodeURLSession011 = 901011, // I-NET901011 41 | kGULNetworkMessageCodeURLSession012 = 901012, // I-NET901012 42 | kGULNetworkMessageCodeURLSession013 = 901013, // I-NET901013 43 | kGULNetworkMessageCodeURLSession014 = 901014, // I-NET901014 44 | kGULNetworkMessageCodeURLSession015 = 901015, // I-NET901015 45 | kGULNetworkMessageCodeURLSession016 = 901016, // I-NET901016 46 | kGULNetworkMessageCodeURLSession017 = 901017, // I-NET901017 47 | kGULNetworkMessageCodeURLSession018 = 901018, // I-NET901018 48 | kGULNetworkMessageCodeURLSession019 = 901019, // I-NET901019 49 | }; 50 | 51 | NS_ASSUME_NONNULL_END 52 | -------------------------------------------------------------------------------- /GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkURLSession.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | #import "GULNetworkLoggerProtocol.h" 20 | 21 | NS_ASSUME_NONNULL_BEGIN 22 | 23 | typedef void (^GULNetworkCompletionHandler)(NSHTTPURLResponse *_Nullable response, 24 | NSData *_Nullable data, 25 | NSError *_Nullable error); 26 | typedef void (^GULNetworkURLSessionCompletionHandler)(NSHTTPURLResponse *_Nullable response, 27 | NSData *_Nullable data, 28 | NSString *sessionID, 29 | NSError *_Nullable error); 30 | typedef void (^GULNetworkSystemCompletionHandler)(void); 31 | 32 | /// The protocol that uses NSURLSession for iOS >= 7.0 to handle requests and responses. 33 | @interface GULNetworkURLSession : NSObject 34 | 35 | /// Indicates whether the background network is enabled. Default value is NO. 36 | @property(nonatomic, getter=isBackgroundNetworkEnabled) BOOL backgroundNetworkEnabled; 37 | 38 | /// The logger delegate to log message, errors or warnings that occur during the network operations. 39 | @property(nonatomic, weak, nullable) id loggerDelegate; 40 | 41 | /// Calls the system provided completion handler after the background session is finished. 42 | + (void)handleEventsForBackgroundURLSessionID:(NSString *)sessionID 43 | completionHandler:(GULNetworkSystemCompletionHandler)completionHandler; 44 | 45 | /// Initializes with logger delegate. 46 | - (instancetype)initWithNetworkLoggerDelegate: 47 | (nullable id)networkLoggerDelegate NS_DESIGNATED_INITIALIZER; 48 | 49 | - (instancetype)init NS_UNAVAILABLE; 50 | 51 | /// Sends an asynchronous POST request and calls the provided completion handler when the request 52 | /// completes or when errors occur, and returns an ID of the session/connection. 53 | - (nullable NSString *)sessionIDFromAsyncPOSTRequest:(NSURLRequest *)request 54 | completionHandler:(GULNetworkURLSessionCompletionHandler)handler; 55 | 56 | /// Sends an asynchronous GET request and calls the provided completion handler when the request 57 | /// completes or when errors occur, and returns an ID of the session. 58 | - (nullable NSString *)sessionIDFromAsyncGETRequest:(NSURLRequest *)request 59 | completionHandler:(GULNetworkURLSessionCompletionHandler)handler; 60 | 61 | NS_ASSUME_NONNULL_END 62 | @end 63 | -------------------------------------------------------------------------------- /GoogleUtilities/Network/Resources/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyTracking 6 | 7 | NSPrivacyTrackingDomains 8 | 9 | 10 | NSPrivacyCollectedDataTypes 11 | 12 | 13 | NSPrivacyAccessedAPITypes 14 | 15 | 16 | NSPrivacyAccessedAPIType 17 | NSPrivacyAccessedAPICategoryFileTimestamp 18 | NSPrivacyAccessedAPITypeReasons 19 | 20 | C617.1 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /GoogleUtilities/Privacy/Empty.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // This file is intentionally empty and satisfies SwiftPM's requirement that a 16 | // target contain sources. 17 | -------------------------------------------------------------------------------- /GoogleUtilities/Privacy/Resources/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyTracking 6 | 7 | NSPrivacyTrackingDomains 8 | 9 | 10 | NSPrivacyCollectedDataTypes 11 | 12 | 13 | NSPrivacyAccessedAPITypes 14 | 15 | 16 | NSPrivacyAccessedAPIType 17 | NSPrivacyAccessedAPICategoryFileTimestamp 18 | NSPrivacyAccessedAPITypeReasons 19 | 20 | C617.1 21 | 22 | 23 | 24 | NSPrivacyAccessedAPIType 25 | NSPrivacyAccessedAPICategoryUserDefaults 26 | NSPrivacyAccessedAPITypeReasons 27 | 28 | C56D.1 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /GoogleUtilities/Reachability/GULReachabilityChecker+Internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import "GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h" 18 | 19 | #if !TARGET_OS_WATCH 20 | typedef SCNetworkReachabilityRef (*GULReachabilityCreateWithNameFn)(CFAllocatorRef allocator, 21 | const char *host); 22 | 23 | typedef Boolean (*GULReachabilitySetCallbackFn)(SCNetworkReachabilityRef target, 24 | SCNetworkReachabilityCallBack callback, 25 | SCNetworkReachabilityContext *context); 26 | typedef Boolean (*GULReachabilityScheduleWithRunLoopFn)(SCNetworkReachabilityRef target, 27 | CFRunLoopRef runLoop, 28 | CFStringRef runLoopMode); 29 | typedef Boolean (*GULReachabilityUnscheduleFromRunLoopFn)(SCNetworkReachabilityRef target, 30 | CFRunLoopRef runLoop, 31 | CFStringRef runLoopMode); 32 | 33 | typedef void (*GULReachabilityReleaseFn)(CFTypeRef cf); 34 | 35 | struct GULReachabilityApi { 36 | GULReachabilityCreateWithNameFn createWithNameFn; 37 | GULReachabilitySetCallbackFn setCallbackFn; 38 | GULReachabilityScheduleWithRunLoopFn scheduleWithRunLoopFn; 39 | GULReachabilityUnscheduleFromRunLoopFn unscheduleFromRunLoopFn; 40 | GULReachabilityReleaseFn releaseFn; 41 | }; 42 | #endif 43 | @interface GULReachabilityChecker (Internal) 44 | 45 | - (const struct GULReachabilityApi *)reachabilityApi; 46 | - (void)setReachabilityApi:(const struct GULReachabilityApi *)reachabilityApi; 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /GoogleUtilities/Reachability/GULReachabilityMessageCode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | // Make sure these codes do not overlap with any contained in the FIRAMessageCode enum. 20 | typedef NS_ENUM(NSInteger, GULReachabilityMessageCode) { 21 | // GULReachabilityChecker.m 22 | kGULReachabilityMessageCode000 = 902000, // I-NET902000 23 | kGULReachabilityMessageCode001 = 902001, // I-NET902001 24 | kGULReachabilityMessageCode002 = 902002, // I-NET902002 25 | kGULReachabilityMessageCode003 = 902003, // I-NET902003 26 | kGULReachabilityMessageCode004 = 902004, // I-NET902004 27 | kGULReachabilityMessageCode005 = 902005, // I-NET902005 28 | kGULReachabilityMessageCode006 = 902006, // I-NET902006 29 | }; 30 | -------------------------------------------------------------------------------- /GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | #if !TARGET_OS_WATCH 19 | #import 20 | #endif 21 | 22 | NS_ASSUME_NONNULL_BEGIN 23 | 24 | /// Reachability Status 25 | typedef enum { 26 | kGULReachabilityUnknown, ///< Have not yet checked or been notified whether host is reachable. 27 | kGULReachabilityNotReachable, ///< Host is not reachable. 28 | kGULReachabilityViaWifi, ///< Host is reachable via Wifi. 29 | kGULReachabilityViaCellular, ///< Host is reachable via cellular. 30 | } GULReachabilityStatus; 31 | 32 | const NSString *GULReachabilityStatusString(GULReachabilityStatus status); 33 | 34 | @class GULReachabilityChecker; 35 | 36 | /// Google Analytics iOS Reachability Checker. 37 | @protocol GULReachabilityDelegate 38 | @required 39 | /// Called when network status has changed. 40 | - (void)reachability:(GULReachabilityChecker *)reachability 41 | statusChanged:(GULReachabilityStatus)status; 42 | @end 43 | 44 | /// Google Analytics iOS Network Status Checker. 45 | @interface GULReachabilityChecker : NSObject 46 | 47 | /// The last known reachability status, or GULReachabilityStatusUnknown if the 48 | /// checker is not active. 49 | @property(nonatomic, readonly) GULReachabilityStatus reachabilityStatus; 50 | /// The host to which reachability status is to be checked. 51 | @property(nonatomic, copy, readonly) NSString *host; 52 | /// The delegate to be notified of reachability status changes. 53 | @property(nonatomic, weak) id reachabilityDelegate; 54 | /// `YES` if the reachability checker is active, `NO` otherwise. 55 | @property(nonatomic, readonly) BOOL isActive; 56 | 57 | /// Initialize the reachability checker. Note that you must call start to begin checking for and 58 | /// receiving notifications about network status changes. 59 | /// 60 | /// @param reachabilityDelegate The delegate to be notified when reachability status to host 61 | /// changes. 62 | /// 63 | /// @param host The name of the host. 64 | /// 65 | - (instancetype)initWithReachabilityDelegate:(id)reachabilityDelegate 66 | withHost:(NSString *)host; 67 | 68 | - (instancetype)init NS_UNAVAILABLE; 69 | 70 | /// Start checking for reachability to the specified host. This has no effect if the status 71 | /// checker is already checking for connectivity. 72 | /// 73 | /// @return `YES` if initiating status checking was successful or the status checking has already 74 | /// been initiated, `NO` otherwise. 75 | - (BOOL)start; 76 | 77 | /// Stop checking for reachability to the specified host. This has no effect if the status 78 | /// checker is not checking for connectivity. 79 | - (void)stop; 80 | 81 | @end 82 | 83 | NS_ASSUME_NONNULL_END 84 | -------------------------------------------------------------------------------- /GoogleUtilities/Reachability/Resources/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyTracking 6 | 7 | NSPrivacyTrackingDomains 8 | 9 | 10 | NSPrivacyCollectedDataTypes 11 | 12 | 13 | NSPrivacyAccessedAPITypes 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /GoogleUtilities/SwizzlerTestHelpers/GULRuntimeClassDiff.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | NS_ASSUME_NONNULL_BEGIN 20 | 21 | /** A simple container class for representing the diff of a class. */ 22 | @interface GULRuntimeClassDiff : NSObject 23 | 24 | /** The class this diff is with respect to. */ 25 | @property(nonatomic, nullable, weak) Class aClass; 26 | 27 | /** The added class properties (as opposed to instance properties). */ 28 | @property(nonatomic) NSSet *addedClassProperties; 29 | 30 | /** The added instance properties. */ 31 | @property(nonatomic) NSSet *addedInstanceProperties; 32 | 33 | /** The added class selectors. */ 34 | @property(nonatomic) NSSet *addedClassSelectors; 35 | 36 | /** The added instance selectors. */ 37 | @property(nonatomic) NSSet *addedInstanceSelectors; 38 | 39 | /** The modified imps. */ 40 | @property(nonatomic) NSSet *modifiedImps; 41 | 42 | @end 43 | 44 | NS_ASSUME_NONNULL_END 45 | -------------------------------------------------------------------------------- /GoogleUtilities/SwizzlerTestHelpers/GULRuntimeClassDiff.m: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import "GoogleUtilities/SwizzlerTestHelpers/GULRuntimeClassDiff.h" 16 | 17 | /** Computes the equality of possibly nil or empty NSSets. 18 | * 19 | * @param firstSet The first set of strings. 20 | * @param secondSet The second set of strings. 21 | * @return YES if both sets are zero length or nil, or the result of `isEqualToSet:`. 22 | */ 23 | FOUNDATION_STATIC_INLINE 24 | BOOL IsEqual(NSSet *firstSet, NSSet *secondSet) { 25 | return ((!firstSet || firstSet.count == 0) && (!secondSet || secondSet.count == 0)) || 26 | [firstSet isEqualToSet:secondSet]; 27 | } 28 | 29 | @implementation GULRuntimeClassDiff 30 | 31 | - (NSUInteger)hash { 32 | return [_aClass hash] ^ [_addedClassProperties hash] ^ [_addedInstanceProperties hash] ^ 33 | [_addedClassSelectors hash] ^ [_addedInstanceSelectors hash] ^ [_modifiedImps hash]; 34 | } 35 | 36 | - (BOOL)isEqual:(id)object { 37 | GULRuntimeClassDiff *otherObject = (GULRuntimeClassDiff *)object; 38 | return _aClass == otherObject->_aClass && 39 | IsEqual(_addedClassProperties, otherObject->_addedClassProperties) && 40 | IsEqual(_addedInstanceProperties, otherObject->_addedInstanceProperties) && 41 | IsEqual(_addedClassSelectors, otherObject->_addedClassSelectors) && 42 | IsEqual(_addedInstanceSelectors, otherObject->_addedInstanceSelectors) && 43 | IsEqual(_modifiedImps, otherObject->_modifiedImps); 44 | } 45 | 46 | - (NSString *)description { 47 | NSMutableString *description = [[NSMutableString alloc] init]; 48 | [description appendFormat:@"%@:\n", NSStringFromClass(self.aClass)]; 49 | if (_addedClassProperties.count) { 50 | [description appendString:@"\tAdded class properties:\n"]; 51 | for (NSString *addedClassProperty in _addedClassProperties) { 52 | [description appendFormat:@"\t\t%@\n", addedClassProperty]; 53 | } 54 | } 55 | if (_addedInstanceProperties.count) { 56 | [description appendString:@"\tAdded instance properties:\n"]; 57 | for (NSString *addedInstanceProperty in _addedInstanceProperties) { 58 | [description appendFormat:@"\t\t%@\n", addedInstanceProperty]; 59 | } 60 | } 61 | if (_addedClassSelectors.count) { 62 | [description appendString:@"\tAdded class selectors:\n"]; 63 | for (NSString *addedClassSelector in _addedClassSelectors) { 64 | [description appendFormat:@"\t\t%@\n", addedClassSelector]; 65 | } 66 | } 67 | if (_addedInstanceSelectors.count) { 68 | [description appendString:@"\tAdded instance selectors:\n"]; 69 | for (NSString *addedInstanceSelector in _addedInstanceSelectors) { 70 | [description appendFormat:@"\t\t%@\n", addedInstanceSelector]; 71 | } 72 | } 73 | if (_modifiedImps.count) { 74 | [description appendString:@"\tModified IMPs:\n"]; 75 | for (NSString *modifiedImp in _modifiedImps) { 76 | [description appendFormat:@"\t\t%@\n", modifiedImp]; 77 | } 78 | } 79 | return description; 80 | } 81 | 82 | @end 83 | -------------------------------------------------------------------------------- /GoogleUtilities/SwizzlerTestHelpers/GULRuntimeClassSnapshot.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | @class GULRuntimeClassDiff; 20 | 21 | NS_ASSUME_NONNULL_BEGIN 22 | 23 | /** This class is able to capture the runtime state of a given class. */ 24 | @interface GULRuntimeClassSnapshot : NSObject 25 | 26 | - (instancetype)init NS_UNAVAILABLE; 27 | 28 | /** Instantiates an instance of this class with the given class. 29 | * 30 | * @param aClass The class that will be snapshot. 31 | * @return An instance of this class. 32 | */ 33 | - (instancetype)initWithClass:(Class)aClass NS_DESIGNATED_INITIALIZER; 34 | 35 | /** Captures the runtime state of this class. */ 36 | - (void)capture; 37 | 38 | /** Calculates the diff between snapshots and returns a diff object populated with information. 39 | * 40 | * @param otherClassSnapshot The other snapshot to compare it to. It's assumed that the 41 | * otherClassSnapshot was created after the caller. 42 | * @return A diff object representing the diff between the two snapshots. 43 | */ 44 | - (GULRuntimeClassDiff *)diff:(GULRuntimeClassSnapshot *)otherClassSnapshot; 45 | 46 | @end 47 | 48 | NS_ASSUME_NONNULL_END 49 | -------------------------------------------------------------------------------- /GoogleUtilities/SwizzlerTestHelpers/GULRuntimeDiff.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | @class GULRuntimeClassDiff; 20 | 21 | NS_ASSUME_NONNULL_BEGIN 22 | 23 | /** A simple container class for storing the diff of some runtime state. */ 24 | @interface GULRuntimeDiff : NSObject 25 | 26 | /** The added classes. */ 27 | @property(nonatomic) NSSet *addedClasses; 28 | 29 | /** The removed classes. */ 30 | @property(nonatomic) NSSet *removedClasses; 31 | 32 | /** The diff objects for modified classes. */ 33 | @property(nonatomic) NSSet *classDiffs; 34 | 35 | @end 36 | 37 | NS_ASSUME_NONNULL_END 38 | -------------------------------------------------------------------------------- /GoogleUtilities/SwizzlerTestHelpers/GULRuntimeDiff.m: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import "GoogleUtilities/SwizzlerTestHelpers/GULRuntimeDiff.h" 16 | 17 | #import "GoogleUtilities/SwizzlerTestHelpers/GULRuntimeClassDiff.h" 18 | 19 | /** Computes the equality of possibly nil or empty NSSets. 20 | * 21 | * @param firstSet The first set of strings. 22 | * @param secondSet The second set of strings. 23 | * @return YES if both sets are zero length or nil, or the result of `isEqualToSet:`. 24 | */ 25 | FOUNDATION_STATIC_INLINE 26 | BOOL IsEqual(NSSet *firstSet, NSSet *secondSet) { 27 | return ((!firstSet || firstSet.count == 0) && (!secondSet || secondSet.count == 0)) || 28 | [firstSet isEqualToSet:secondSet]; 29 | } 30 | 31 | @implementation GULRuntimeDiff 32 | 33 | - (NSUInteger)hash { 34 | return [_addedClasses hash] ^ [_removedClasses hash] ^ [_classDiffs hash]; 35 | } 36 | 37 | - (BOOL)isEqual:(id)object { 38 | GULRuntimeDiff *otherObject = (GULRuntimeDiff *)object; 39 | return IsEqual(_addedClasses, otherObject->_addedClasses) && 40 | IsEqual(_removedClasses, otherObject->_removedClasses) && 41 | IsEqual(_classDiffs, otherObject->_classDiffs); 42 | } 43 | 44 | - (NSString *)description { 45 | NSMutableString *description = [[NSMutableString alloc] init]; 46 | if (_addedClasses.count) { 47 | [description appendString:@"Added classes:\n"]; 48 | for (NSString *classString in _addedClasses) { 49 | [description appendFormat:@"\t%@\n", classString]; 50 | } 51 | } 52 | if (_removedClasses.count) { 53 | [description appendString:@"\nRemoved classes:\n"]; 54 | for (NSString *classString in _removedClasses) { 55 | [description appendFormat:@"\t%@\n", classString]; 56 | } 57 | } 58 | if (_classDiffs.count) { 59 | [description appendString:@"\nClass diffs:\n"]; 60 | for (GULRuntimeClassDiff *classDiff in _classDiffs) { 61 | NSString *classDiffDescription = 62 | [[classDiff description] stringByReplacingOccurrencesOfString:@"\n" withString:@"\n\t"]; 63 | [description appendFormat:@"\t%@\n", classDiffDescription]; 64 | } 65 | } 66 | return description; 67 | } 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /GoogleUtilities/SwizzlerTestHelpers/GULRuntimeSnapshot.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | @class GULRuntimeClassSnapshot; 20 | @class GULRuntimeDiff; 21 | 22 | NS_ASSUME_NONNULL_BEGIN 23 | 24 | /** This class captures various aspects the current state of the Objective-C runtime. */ 25 | @interface GULRuntimeSnapshot : NSObject 26 | 27 | /** Initializes an instance of this class. The designated initializer. 28 | * 29 | * @param classes The set of classes to track. If nil or empty, all ObjC classes are tracked. 30 | * @return An instance of this class. 31 | */ 32 | - (instancetype)initWithClasses:(nullable NSSet *)classes NS_DESIGNATED_INITIALIZER; 33 | 34 | /** Captures the state of the class set. */ 35 | - (void)capture; 36 | 37 | /** Computes the diff between this snapshot and another snapshot. 38 | * 39 | * @param otherSnapshot The other snapshot, assumed to be more recent than self. 40 | * @return A diff object populated with the diff. 41 | */ 42 | - (GULRuntimeDiff *)diff:(GULRuntimeSnapshot *)otherSnapshot; 43 | 44 | @end 45 | 46 | NS_ASSUME_NONNULL_END 47 | -------------------------------------------------------------------------------- /GoogleUtilities/SwizzlerTestHelpers/GULRuntimeSnapshot.m: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import "GoogleUtilities/SwizzlerTestHelpers/GULRuntimeSnapshot.h" 16 | 17 | #import 18 | 19 | #import "GoogleUtilities/SwizzlerTestHelpers/GULRuntimeClassDiff.h" 20 | #import "GoogleUtilities/SwizzlerTestHelpers/GULRuntimeClassSnapshot.h" 21 | #import "GoogleUtilities/SwizzlerTestHelpers/GULRuntimeDiff.h" 22 | 23 | @implementation GULRuntimeSnapshot { 24 | /** The set of tracked classes. */ 25 | NSSet *__nullable _classes; 26 | 27 | /** The class snapshots for each tracked class. */ 28 | NSMutableDictionary *_classSnapshots; 29 | 30 | /** The hash value of this object. */ 31 | NSUInteger _runningHash; 32 | } 33 | 34 | - (instancetype)init { 35 | return [self initWithClasses:nil]; 36 | } 37 | 38 | - (instancetype)initWithClasses:(nullable NSSet *)classes { 39 | self = [super init]; 40 | if (self) { 41 | _classSnapshots = [[NSMutableDictionary alloc] init]; 42 | _classes = classes; 43 | _runningHash = [_classes hash] ^ [_classSnapshots hash]; 44 | } 45 | return self; 46 | } 47 | 48 | - (NSUInteger)hash { 49 | return _runningHash; 50 | } 51 | 52 | - (BOOL)isEqual:(id)object { 53 | return [self hash] == [object hash]; 54 | } 55 | 56 | - (NSString *)description { 57 | return [[super description] stringByAppendingFormat:@" Hash: 0x%lX", (unsigned long)[self hash]]; 58 | } 59 | 60 | - (void)capture { 61 | int numberOfClasses = objc_getClassList(NULL, 0); 62 | Class *classList = (Class *)malloc(numberOfClasses * sizeof(Class)); 63 | numberOfClasses = objc_getClassList(classList, numberOfClasses); 64 | 65 | // If we should track specific classes, then there's no need to figure out all ObjC classes. 66 | if (_classes) { 67 | for (Class aClass in _classes) { 68 | NSString *classString = NSStringFromClass(aClass); 69 | GULRuntimeClassSnapshot *classSnapshot = 70 | [[GULRuntimeClassSnapshot alloc] initWithClass:aClass]; 71 | _classSnapshots[classString] = classSnapshot; 72 | [classSnapshot capture]; 73 | _runningHash ^= [classSnapshot hash]; 74 | } 75 | } else { 76 | for (int i = 0; i < numberOfClasses; i++) { 77 | Class aClass = classList[i]; 78 | NSString *classString = NSStringFromClass(aClass); 79 | GULRuntimeClassSnapshot *classSnapshot = 80 | [[GULRuntimeClassSnapshot alloc] initWithClass:aClass]; 81 | _classSnapshots[classString] = classSnapshot; 82 | [classSnapshot capture]; 83 | _runningHash ^= [classSnapshot hash]; 84 | } 85 | } 86 | free(classList); 87 | } 88 | 89 | - (GULRuntimeDiff *)diff:(GULRuntimeSnapshot *)otherSnapshot { 90 | GULRuntimeDiff *runtimeDiff = [[GULRuntimeDiff alloc] init]; 91 | NSSet *setOne = [NSSet setWithArray:[_classSnapshots allKeys]]; 92 | NSSet *setTwo = [NSSet setWithArray:[otherSnapshot->_classSnapshots allKeys]]; 93 | 94 | // All items contained within setOne, but not in setTwo. 95 | NSSet *removedClasses = [setOne 96 | filteredSetUsingPredicate:[NSPredicate predicateWithBlock:^BOOL( 97 | id _Nullable evaluatedObject, 98 | NSDictionary *_Nullable bindings) { 99 | return ![setTwo containsObject:evaluatedObject]; 100 | }]]; 101 | 102 | // All items contained within setTwo, but not in setOne. 103 | NSSet *addedClasses = [setTwo 104 | filteredSetUsingPredicate:[NSPredicate predicateWithBlock:^BOOL( 105 | id _Nullable evaluatedObject, 106 | NSDictionary *_Nullable bindings) { 107 | return ![setOne containsObject:evaluatedObject]; 108 | }]]; 109 | runtimeDiff.removedClasses = removedClasses; 110 | runtimeDiff.addedClasses = addedClasses; 111 | 112 | NSMutableSet *classDiffs = [[NSMutableSet alloc] init]; 113 | [_classSnapshots 114 | enumerateKeysAndObjectsUsingBlock:^( 115 | NSString *_Nonnull key, GULRuntimeClassSnapshot *_Nonnull obj, BOOL *_Nonnull stop) { 116 | GULRuntimeClassSnapshot *classSnapshot = self->_classSnapshots[key]; 117 | GULRuntimeClassSnapshot *otherClassSnapshot = otherSnapshot->_classSnapshots[key]; 118 | GULRuntimeClassDiff *classDiff = [classSnapshot diff:otherClassSnapshot]; 119 | if ([classDiff hash]) { 120 | NSAssert(![classDiffs containsObject:classDiff], 121 | @"An equivalent class diff has already been stored."); 122 | [classDiffs addObject:classDiff]; 123 | } 124 | }]; 125 | runtimeDiff.classDiffs = classDiffs; 126 | return runtimeDiff; 127 | } 128 | 129 | @end 130 | -------------------------------------------------------------------------------- /GoogleUtilities/SwizzlerTestHelpers/GULRuntimeStateHelper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | #import "GoogleUtilities/SwizzlerTestHelpers/GULRuntimeClassDiff.h" 20 | #import "GoogleUtilities/SwizzlerTestHelpers/GULRuntimeDiff.h" 21 | 22 | NS_ASSUME_NONNULL_BEGIN 23 | 24 | /** A helper class that enables the snapshotting and diffing of ObjC runtime state. */ 25 | @interface GULRuntimeStateHelper : NSObject 26 | 27 | /** Captures the current state of the entire runtime and returns the snapshot number. 28 | * 29 | * @return The snapshot number corresponding to this capture. 30 | */ 31 | + (NSUInteger)captureRuntimeState; 32 | 33 | /** Captures the current state of the runtime for the provided classes. 34 | * 35 | * @param classes The classes whose state should be snapshotted. 36 | * @return The snapshot number corresponding to this capture. 37 | */ 38 | + (NSUInteger)captureRuntimeStateOfClasses:(NSSet *)classes; 39 | 40 | /** Prints the diff between two snapshot numbers. 41 | * 42 | * @param firstSnapshot The first runtime snapshot, as provided by captureRuntimeState. 43 | * @param secondSnapshot The runtime snapshot sometime after firstSnapshot. 44 | * @return An instance of GULRuntimeDiff that contains the diff information. 45 | */ 46 | + (GULRuntimeDiff *)diffBetween:(NSUInteger)firstSnapshot secondSnapshot:(NSUInteger)secondSnapshot; 47 | 48 | @end 49 | 50 | NS_ASSUME_NONNULL_END 51 | -------------------------------------------------------------------------------- /GoogleUtilities/SwizzlerTestHelpers/GULRuntimeStateHelper.m: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import "GoogleUtilities/SwizzlerTestHelpers/GULRuntimeStateHelper.h" 16 | 17 | #import 18 | 19 | #import "GoogleUtilities/SwizzlerTestHelpers/GULRuntimeSnapshot.h" 20 | 21 | @implementation GULRuntimeStateHelper 22 | 23 | /** Initializes and returns the snapshot cache. 24 | * 25 | * @return A singleton snapshot cache. 26 | */ 27 | + (NSMutableArray *)snapshotCache { 28 | static NSMutableArray *snapshots; 29 | static dispatch_once_t onceToken; 30 | dispatch_once(&onceToken, ^{ 31 | snapshots = [[NSMutableArray alloc] init]; 32 | }); 33 | return snapshots; 34 | } 35 | 36 | + (NSUInteger)captureRuntimeState { 37 | GULRuntimeSnapshot *snapshot = [[GULRuntimeSnapshot alloc] init]; 38 | [snapshot capture]; 39 | [[self snapshotCache] addObject:snapshot]; 40 | return [self snapshotCache].count - 1; 41 | } 42 | 43 | + (NSUInteger)captureRuntimeStateOfClasses:(NSSet *)classes { 44 | GULRuntimeSnapshot *snapshot = [[GULRuntimeSnapshot alloc] initWithClasses:classes]; 45 | [snapshot capture]; 46 | [[self snapshotCache] addObject:snapshot]; 47 | return [self snapshotCache].count - 1; 48 | } 49 | 50 | + (GULRuntimeDiff *)diffBetween:(NSUInteger)firstSnapshot 51 | secondSnapshot:(NSUInteger)secondSnapshot { 52 | NSArray *snapshotCache = [self snapshotCache]; 53 | return [snapshotCache[firstSnapshot] diff:snapshotCache[secondSnapshot]]; 54 | } 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /GoogleUtilities/SwizzlerTestHelpers/GULSwizzler+Unswizzle.m: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import "GoogleUtilities/MethodSwizzler/Public/GoogleUtilities/GULSwizzler.h" 16 | 17 | #import 18 | 19 | #import "GoogleUtilities/SwizzlerTestHelpers/GULSwizzlingCache.h" 20 | 21 | extern dispatch_queue_t GetGULSwizzlingQueue(void); 22 | 23 | @implementation GULSwizzler (Unswizzle) 24 | 25 | + (void)unswizzleClass:(Class)aClass selector:(SEL)selector isClassSelector:(BOOL)isClassSelector { 26 | dispatch_sync(GetGULSwizzlingQueue(), ^{ 27 | NSAssert(aClass != nil && selector != nil, @"You cannot unswizzle a nil class or selector."); 28 | Method method = nil; 29 | Class resolvedClass = aClass; 30 | if (isClassSelector) { 31 | resolvedClass = object_getClass(aClass); 32 | method = class_getClassMethod(aClass, selector); 33 | } else { 34 | method = class_getInstanceMethod(aClass, selector); 35 | } 36 | NSAssert(method, @"Couldn't find the method you're unswizzling in the runtime."); 37 | IMP originalImp = [[GULSwizzlingCache sharedInstance] cachedIMPForClass:resolvedClass 38 | withSelector:selector]; 39 | NSAssert(originalImp, @"This class/selector combination hasn't been swizzled"); 40 | IMP currentImp = method_setImplementation(method, originalImp); 41 | __unused BOOL didRemoveBlock = imp_removeBlock(currentImp); 42 | NSAssert(didRemoveBlock, @"Wasn't able to remove the block of a swizzled IMP."); 43 | [[GULSwizzlingCache sharedInstance] clearCacheForSwizzledIMP:currentImp 44 | selector:selector 45 | aClass:resolvedClass]; 46 | }); 47 | } 48 | 49 | + (nullable IMP)originalImplementationForClass:(Class)aClass 50 | selector:(SEL)selector 51 | isClassSelector:(BOOL)isClassSelector { 52 | __block IMP originalImp = nil; 53 | dispatch_sync(GetGULSwizzlingQueue(), ^{ 54 | Class resolvedClass = isClassSelector ? object_getClass(aClass) : aClass; 55 | originalImp = [[GULSwizzlingCache sharedInstance] cachedIMPForClass:resolvedClass 56 | withSelector:selector]; 57 | NSAssert(originalImp, @"The IMP for this class/selector combo doesn't exist (%@, %@).", 58 | NSStringFromClass(resolvedClass), NSStringFromSelector(selector)); 59 | }); 60 | return originalImp; 61 | } 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /GoogleUtilities/SwizzlerTestHelpers/GULSwizzlingCache.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | /** This class handles the caching and retrieval of IMPs as we swizzle and unswizzle them. It uses 20 | * two C++ STL unordered_maps as the underlying data store. This class is NOT thread safe. 21 | */ 22 | @interface GULSwizzlingCache : NSObject 23 | 24 | /** Singleton initializer. 25 | * 26 | * @return a singleton GULSwizzlingCache. 27 | */ 28 | + (instancetype)sharedInstance; 29 | 30 | /** Save the existing IMP that exists before we install the new IMP for a class, selector combo. 31 | * If the currentIMP is something that we put there, it will ignore it and instead point newIMP 32 | * to what existed before we swizzled. 33 | * 34 | * @param currentIMP The IMP returned by class_getMethodImplementation. 35 | * @param newIMP new The IMP that is going to replace the current IMP. 36 | * @param aClass The class that we're swizzling. 37 | * @param selector The selector we're swizzling. 38 | */ 39 | - (void)cacheCurrentIMP:(IMP)currentIMP 40 | forNewIMP:(IMP)newIMP 41 | forClass:(Class)aClass 42 | withSelector:(SEL)selector; 43 | 44 | /** Save the existing IMP that exists before we install the new IMP for a class, selector combo. 45 | * If the currentIMP is something that we put there, it will ignore it and instead point newIMP 46 | * to what existed before we swizzled. 47 | * 48 | * @param currentIMP The IMP returned by class_getMethodImplementation. 49 | * @param newIMP new The IMP that is going to replace the current IMP. 50 | * @param aClass The class that we're swizzling. 51 | * @param selector The selector we're swizzling. 52 | */ 53 | + (void)cacheCurrentIMP:(IMP)currentIMP 54 | forNewIMP:(IMP)newIMP 55 | forClass:(Class)aClass 56 | withSelector:(SEL)selector; 57 | 58 | /** Returns the cached IMP that would be invoked with the class and selector combo had we 59 | * never swizzled. 60 | * 61 | * @param aClass The class the selector would be invoked on. 62 | * @param selector The selector 63 | * @return The original IMP i.e. the one that existed right before GULSwizzler swizzled either 64 | * this or a superclass. 65 | */ 66 | - (IMP)cachedIMPForClass:(Class)aClass withSelector:(SEL)selector; 67 | 68 | /** Clears the cache of values we no longer need because we've unswizzled the relevant method. 69 | * 70 | * @param swizzledIMP The IMP we replaced the existing IMP with. 71 | * @param selector The selector which that we swizzled for. 72 | * @param aClass The class that we're swizzling. 73 | */ 74 | - (void)clearCacheForSwizzledIMP:(IMP)swizzledIMP selector:(SEL)selector aClass:(Class)aClass; 75 | 76 | @end 77 | -------------------------------------------------------------------------------- /GoogleUtilities/SwizzlerTestHelpers/GULSwizzlingCache.m: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import "GoogleUtilities/SwizzlerTestHelpers/GULSwizzlingCache.h" 16 | 17 | #import 18 | 19 | @interface GULSwizzlingCache () 20 | - (IMP)originalIMPOfCurrentIMP:(IMP)currentIMP; 21 | @end 22 | 23 | @implementation GULSwizzlingCache { 24 | /** A mapping from the new IMP to the original IMP. */ 25 | CFMutableDictionaryRef _newToOriginalImps; 26 | 27 | /** A mapping from a Class and SEL (stored in a CFArray) to the original IMP that existed for it. 28 | */ 29 | CFMutableDictionaryRef _originalImps; 30 | } 31 | 32 | + (instancetype)sharedInstance { 33 | static GULSwizzlingCache *sharedInstance; 34 | static dispatch_once_t token; 35 | dispatch_once(&token, ^{ 36 | sharedInstance = [[GULSwizzlingCache alloc] init]; 37 | }); 38 | return sharedInstance; 39 | } 40 | 41 | - (instancetype)init { 42 | self = [super init]; 43 | if (self) { 44 | _newToOriginalImps = CFDictionaryCreateMutable(kCFAllocatorDefault, 45 | 0, // Size. 46 | NULL, // Keys are pointers, so this is NULL. 47 | NULL); // Values are pointers so this is NULL. 48 | _originalImps = CFDictionaryCreateMutable(kCFAllocatorDefault, 49 | 0, // Size. 50 | &kCFTypeDictionaryKeyCallBacks, // Keys are CFArrays. 51 | NULL); // Values are pointers so this is NULL. 52 | } 53 | return self; 54 | } 55 | 56 | - (void)dealloc { 57 | CFRelease(_newToOriginalImps); 58 | CFRelease(_originalImps); 59 | } 60 | 61 | - (void)cacheCurrentIMP:(IMP)currentIMP 62 | forNewIMP:(IMP)newIMP 63 | forClass:(Class)aClass 64 | withSelector:(SEL)selector { 65 | IMP originalIMP = [self originalIMPOfCurrentIMP:currentIMP]; 66 | CFDictionaryAddValue(_newToOriginalImps, newIMP, originalIMP); 67 | 68 | const void *classSELCArray[2] = {(__bridge void *)(aClass), selector}; 69 | CFArrayRef classSELPair = CFArrayCreate(kCFAllocatorDefault, classSELCArray, 70 | 2, // Size. 71 | NULL); // Elements are pointers so this is NULL. 72 | CFDictionaryAddValue(_originalImps, classSELPair, originalIMP); 73 | CFRelease(classSELPair); 74 | } 75 | 76 | + (void)cacheCurrentIMP:(IMP)currentIMP 77 | forNewIMP:(IMP)newIMP 78 | forClass:(Class)aClass 79 | withSelector:(SEL)selector { 80 | [[GULSwizzlingCache sharedInstance] cacheCurrentIMP:currentIMP 81 | forNewIMP:newIMP 82 | forClass:aClass 83 | withSelector:selector]; 84 | } 85 | 86 | - (IMP)cachedIMPForClass:(Class)aClass withSelector:(SEL)selector { 87 | const void *classSELCArray[2] = {(__bridge void *)(aClass), selector}; 88 | CFArrayRef classSELPair = CFArrayCreate(kCFAllocatorDefault, classSELCArray, 89 | 2, // Size. 90 | NULL); // Elements are pointers so this is NULL. 91 | const void *returnedIMP = CFDictionaryGetValue(_originalImps, classSELPair); 92 | CFRelease(classSELPair); 93 | return (IMP)returnedIMP; 94 | } 95 | 96 | - (void)clearCacheForSwizzledIMP:(IMP)swizzledIMP selector:(SEL)selector aClass:(Class)aClass { 97 | CFDictionaryRemoveValue(_newToOriginalImps, swizzledIMP); 98 | const void *classSELCArray[2] = {(__bridge void *)(aClass), selector}; 99 | CFArrayRef classSELPair = CFArrayCreate(kCFAllocatorDefault, classSELCArray, 100 | 2, // Size. 101 | NULL); // Elements are pointers so this is NULL. 102 | CFDictionaryRemoveValue(_originalImps, classSELPair); 103 | CFRelease(classSELPair); 104 | } 105 | 106 | - (IMP)originalIMPOfCurrentIMP:(IMP)currentIMP { 107 | const void *returnedIMP = CFDictionaryGetValue(_newToOriginalImps, currentIMP); 108 | if (returnedIMP != NULL) { 109 | return (IMP)returnedIMP; 110 | } else { 111 | return currentIMP; 112 | } 113 | } 114 | 115 | + (IMP)originalIMPOfCurrentIMP:(IMP)currentIMP { 116 | return [[GULSwizzlingCache sharedInstance] originalIMPOfCurrentIMP:currentIMP]; 117 | } 118 | 119 | #pragma mark - Helper methods for testing 120 | 121 | - (void)clearCache { 122 | CFDictionaryRemoveAllValues(_originalImps); 123 | CFDictionaryRemoveAllValues(_newToOriginalImps); 124 | } 125 | 126 | - (CFMutableDictionaryRef)originalImps { 127 | return _originalImps; 128 | } 129 | 130 | - (CFMutableDictionaryRef)newToOriginalImps { 131 | return _newToOriginalImps; 132 | } 133 | 134 | @end 135 | -------------------------------------------------------------------------------- /GoogleUtilities/SwizzlerTestHelpers/GULSwizzlingCache_Private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | @interface GULSwizzlingCache () 18 | 19 | /** Checks if we've swizzled the currentIMP and returns the original IMP that would be invoked if 20 | * we hadn't swizzled it in the first place. This method is private because consumers don't need it 21 | * to cache or retrieve any IMPs. It is used internally and for certain asserts in GULSwizzler. 22 | * 23 | * @param currentIMP The IMP returned by class_getMethodImplementation. 24 | * @return The original IMP that would be invoked if we hadn't swizzled at all, and in cases where 25 | * currentIMP is not something that we put there, just returns currentIMP. 26 | */ 27 | + (IMP)originalIMPOfCurrentIMP:(IMP)currentIMP; 28 | 29 | #pragma mark - Helper methods for testing 30 | 31 | /** Clears all the cache data structures. */ 32 | - (void)clearCache; 33 | 34 | /** Allows tests access to the originalImps CFMutableDictionaryRef. 35 | * 36 | * @returns the originalImps CFMutableDictionaryRef. 37 | */ 38 | - (CFMutableDictionaryRef)originalImps; 39 | 40 | /** Allows tests access to the newToOriginalImps CFMutableDictionaryRef. 41 | * 42 | * @returns the newToOriginalImps CFMutableDictionaryRef. 43 | */ 44 | - (CFMutableDictionaryRef)newToOriginalImps; 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /GoogleUtilities/SwizzlerTestHelpers/Public/GoogleUtilities/GULSwizzler+Unswizzle.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | #import 19 | 20 | NS_ASSUME_NONNULL_BEGIN 21 | 22 | /** This category adds methods for unswizzling that are only used for testing. 23 | */ 24 | @interface GULSwizzler (Unswizzle) 25 | 26 | /** Restores the original implementation. 27 | * 28 | * @param aClass The class to unswizzle. 29 | * @param selector The selector to restore the original implementation of. 30 | * @param isClassSelector A BOOL specifying whether the selector is a class or instance selector. 31 | */ 32 | + (void)unswizzleClass:(Class)aClass selector:(SEL)selector isClassSelector:(BOOL)isClassSelector; 33 | 34 | /** Returns the original IMP for the given class and selector. 35 | * 36 | * @param aClass The class to use. 37 | * @param selector The selector to find the implementation of. 38 | * @param isClassSelector A BOOL specifying whether the selector is a class or instance selector. 39 | * @return The implementation of the selector in the runtime before any consumer or GULSwizzler 40 | * swizzled. 41 | */ 42 | + (nullable IMP)originalImplementationForClass:(Class)aClass 43 | selector:(SEL)selector 44 | isClassSelector:(BOOL)isClassSelector; 45 | 46 | @end 47 | 48 | NS_ASSUME_NONNULL_END 49 | -------------------------------------------------------------------------------- /GoogleUtilities/Tests/SwiftUnit/GULAppEnvironmentUtilTest.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | @testable import GoogleUtilities 18 | import XCTest 19 | 20 | class GULAppEnvironmentUtilTest: XCTestCase { 21 | func testIsAppExtension() throws { 22 | XCTAssertFalse(GULAppEnvironmentUtil.isAppExtension()) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /GoogleUtilities/Tests/Unit/Environment/GULAppEnvironmentUtilTest.m: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import 16 | #import 17 | #import 18 | 19 | #if __has_include() 20 | #import 21 | #endif 22 | 23 | #import "GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h" 24 | 25 | @interface GULAppEnvironmentUtilTest : XCTestCase 26 | 27 | @property(nonatomic) id processInfoMock; 28 | 29 | @end 30 | 31 | @implementation GULAppEnvironmentUtilTest 32 | 33 | - (void)setUp { 34 | [super setUp]; 35 | 36 | _processInfoMock = OCMPartialMock([NSProcessInfo processInfo]); 37 | } 38 | 39 | - (void)tearDown { 40 | [super tearDown]; 41 | 42 | [_processInfoMock stopMocking]; 43 | } 44 | 45 | - (void)testSystemVersionInfoMajorOnly { 46 | #if TARGET_OS_IOS 47 | XCTAssertEqualObjects([GULAppEnvironmentUtil systemVersion], 48 | [UIDevice currentDevice].systemVersion); 49 | #else 50 | NSOperatingSystemVersion osTen = {.majorVersion = 10, .minorVersion = 0, .patchVersion = 0}; 51 | OCMStub([self.processInfoMock operatingSystemVersion]).andReturn(osTen); 52 | XCTAssertEqualObjects([GULAppEnvironmentUtil systemVersion], @"10.0"); 53 | #endif 54 | } 55 | 56 | - (void)testSystemVersionInfoMajorMinor { 57 | #if TARGET_OS_IOS 58 | XCTAssertEqualObjects([GULAppEnvironmentUtil systemVersion], 59 | [UIDevice currentDevice].systemVersion); 60 | #else 61 | NSOperatingSystemVersion osTenTwo = {.majorVersion = 10, .minorVersion = 2, .patchVersion = 0}; 62 | OCMStub([self.processInfoMock operatingSystemVersion]).andReturn(osTenTwo); 63 | XCTAssertEqualObjects([GULAppEnvironmentUtil systemVersion], @"10.2"); 64 | #endif 65 | } 66 | 67 | - (void)testSystemVersionInfoMajorMinorPatch { 68 | #if TARGET_OS_IOS 69 | XCTAssertEqualObjects([GULAppEnvironmentUtil systemVersion], 70 | [UIDevice currentDevice].systemVersion); 71 | #else 72 | NSOperatingSystemVersion osTenTwoOne = {.majorVersion = 10, .minorVersion = 2, .patchVersion = 1}; 73 | OCMStub([self.processInfoMock operatingSystemVersion]).andReturn(osTenTwoOne); 74 | XCTAssertEqualObjects([GULAppEnvironmentUtil systemVersion], @"10.2.1"); 75 | #endif 76 | } 77 | 78 | - (void)testDeploymentType { 79 | #if SWIFT_PACKAGE 80 | NSString *deploymentType = @"swiftpm"; 81 | #elif FIREBASE_BUILD_CARTHAGE 82 | NSString *deploymentType = @"carthage"; 83 | #elif FIREBASE_BUILD_ZIP_FILE 84 | NSString *deploymentType = @"zip"; 85 | #elif COCOAPODS 86 | NSString *deploymentType = @"cocoapods"; 87 | #else 88 | NSString *deploymentType = @"unknown"; 89 | #endif 90 | 91 | XCTAssertEqualObjects([GULAppEnvironmentUtil deploymentType], deploymentType); 92 | } 93 | 94 | - (void)testApplePlatform { 95 | // The below ordering is important. For example, both `TARGET_OS_MACCATALYST` 96 | // and `TARGET_OS_IOS` are `true` when building a macCatalyst app. 97 | #if TARGET_OS_MACCATALYST 98 | NSString *expectedPlatform = @"maccatalyst"; 99 | #elif TARGET_OS_IOS 100 | NSString *expectedPlatform = @"ios"; 101 | #elif TARGET_OS_TV 102 | NSString *expectedPlatform = @"tvos"; 103 | #elif TARGET_OS_OSX 104 | NSString *expectedPlatform = @"macos"; 105 | #elif TARGET_OS_WATCH 106 | NSString *expectedPlatform = @"watchos"; 107 | #endif // TARGET_OS_MACCATALYST 108 | 109 | #if TARGET_OS_VISION 110 | NSString *expectedPlatform = @"visionos"; 111 | #endif // TARGET_OS_VISION 112 | 113 | XCTAssertEqualObjects([GULAppEnvironmentUtil applePlatform], expectedPlatform); 114 | } 115 | 116 | - (void)testAppleDevicePlatform { 117 | // When a Catalyst app is run on macOS then both `TARGET_OS_MACCATALYST` and `TARGET_OS_IOS` are 118 | // `true`. 119 | #if TARGET_OS_MACCATALYST 120 | NSString *expectedPlatform = @"maccatalyst"; 121 | #elif TARGET_OS_IOS 122 | NSString *expectedPlatform = @"ios"; 123 | 124 | if ([[UIDevice currentDevice].model.lowercaseString containsString:@"ipad"] || 125 | [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) { 126 | expectedPlatform = @"ipados"; 127 | } 128 | #endif // TARGET_OS_MACCATALYST 129 | 130 | #if TARGET_OS_TV 131 | NSString *expectedPlatform = @"tvos"; 132 | #endif // TARGET_OS_TV 133 | 134 | #if TARGET_OS_OSX 135 | NSString *expectedPlatform = @"macos"; 136 | #endif // TARGET_OS_OSX 137 | 138 | #if TARGET_OS_WATCH 139 | NSString *expectedPlatform = @"watchos"; 140 | #endif // TARGET_OS_WATCH 141 | 142 | #if TARGET_OS_VISION 143 | NSString *expectedPlatform = @"visionos"; 144 | #endif // TARGET_OS_VISION 145 | 146 | XCTAssertEqualObjects([GULAppEnvironmentUtil appleDevicePlatform], expectedPlatform); 147 | } 148 | 149 | @end 150 | -------------------------------------------------------------------------------- /GoogleUtilities/Tests/Unit/Logger/GULLoggerTest.m: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifdef DEBUG 16 | // The tests depend upon library methods only built with #ifdef DEBUG 17 | 18 | #import 19 | #import 20 | 21 | #import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" 22 | 23 | #import 24 | #import 25 | 26 | extern void GULResetLogger(void); 27 | 28 | extern dispatch_queue_t getGULClientQueue(void); 29 | 30 | extern BOOL getGULLoggerDebugMode(void); 31 | 32 | extern os_log_type_t GULLoggerLevelToOSLogType(GULLoggerLevel level); 33 | 34 | static NSString *const kMessageCode = @"I-COR000001"; 35 | 36 | @interface GULLoggerTest : XCTestCase 37 | 38 | @property(nonatomic) NSString *randomLogString; 39 | 40 | @property(nonatomic, strong) NSUserDefaults *defaults; 41 | 42 | @end 43 | 44 | @implementation GULLoggerTest 45 | 46 | + (void)setUp { 47 | GULLoggerInitialize(); 48 | } 49 | 50 | - (void)setUp { 51 | [super setUp]; 52 | GULResetLogger(); 53 | 54 | // Stub NSUserDefaults for cleaner testing. 55 | _defaults = [[NSUserDefaults alloc] initWithSuiteName:@"com.google.logger_test"]; 56 | } 57 | 58 | - (void)tearDown { 59 | [super tearDown]; 60 | 61 | _defaults = nil; 62 | } 63 | 64 | - (void)testMessageCodeFormat { 65 | // Valid case. 66 | XCTAssertNoThrow( 67 | GULOSLogError(@"com.my.service", @"My/Category", NO, @"I-APP000001", @"Message.")); 68 | 69 | // An extra dash or missing dash should fail. 70 | XCTAssertThrows( 71 | GULOSLogError(@"com.my.service", @"My/Category", NO, @"I-APP-000001", @"Message.")); 72 | XCTAssertThrows(GULOSLogError(@"com.my.service", @"My/Category", NO, @"IAPP000001", @"Message.")); 73 | 74 | // Wrong number of digits should fail. 75 | XCTAssertThrows(GULOSLogError(@"com.my.service", @"My/Category", NO, @"I-APP00001", @"Message.")); 76 | XCTAssertThrows( 77 | GULOSLogError(@"com.my.service", @"My/Category", NO, @"I-APP0000001", @"Message.")); 78 | 79 | // Lowercase should fail. 80 | XCTAssertThrows( 81 | GULOSLogError(@"com.my.service", @"My/Category", NO, @"I-app000001", @"Message.")); 82 | 83 | // nil or empty message code should fail. 84 | #pragma clang diagnostic push 85 | #pragma clang diagnostic ignored "-Wnonnull" 86 | XCTAssertThrows(GULOSLogError(@"com.my.service", @"My/Category", NO, nil, @"Message.")); 87 | #pragma clang diagnostic pop 88 | 89 | XCTAssertThrows(GULOSLogError(@"com.my.service", @"My/Category", NO, @"", @"Message.")); 90 | 91 | // Android message code should fail. 92 | XCTAssertThrows( 93 | GULOSLogError(@"com.my.service", @"My/Category", NO, @"A-APP000001", @"Message.")); 94 | } 95 | 96 | // The GULLoggerLevel enum must match the ASL_LEVEL_* constants, but we manually redefine 97 | // them in GULLoggerLevel.h since we cannot include (see b/34976089 for more details). 98 | // This test ensures the constants match. 99 | - (void)testGULLoggerLevelValues { 100 | XCTAssertEqual(GULLoggerLevelError, ASL_LEVEL_ERR); 101 | XCTAssertEqual(GULLoggerLevelWarning, ASL_LEVEL_WARNING); 102 | XCTAssertEqual(GULLoggerLevelNotice, ASL_LEVEL_NOTICE); 103 | XCTAssertEqual(GULLoggerLevelInfo, ASL_LEVEL_INFO); 104 | XCTAssertEqual(GULLoggerLevelDebug, ASL_LEVEL_DEBUG); 105 | } 106 | 107 | - (void)testGULLoggerLevelToOSLogType { 108 | XCTAssertEqual(GULLoggerLevelToOSLogType(GULLoggerLevelError), OS_LOG_TYPE_ERROR); 109 | // OSLog doesn't have a WARNING level so it is remapped to DEFAULT (Notice). 110 | XCTAssertEqual(GULLoggerLevelToOSLogType(GULLoggerLevelWarning), 111 | GULLoggerLevelToOSLogType(GULLoggerLevelNotice)); 112 | XCTAssertEqual(GULLoggerLevelToOSLogType(GULLoggerLevelNotice), OS_LOG_TYPE_DEFAULT); 113 | XCTAssertEqual(GULLoggerLevelToOSLogType(GULLoggerLevelInfo), OS_LOG_TYPE_INFO); 114 | XCTAssertEqual(GULLoggerLevelToOSLogType(GULLoggerLevelDebug), OS_LOG_TYPE_DEBUG); 115 | } 116 | 117 | - (void)testGULGetLoggerLevel { 118 | GULLoggerLevel loggerLevel = GULGetLoggerLevel(); 119 | 120 | // The default logger level is GULLoggerLevelNotice. 121 | XCTAssertEqual(loggerLevel, GULLoggerLevelNotice); 122 | } 123 | 124 | - (void)testGULSetLoggerLevel { 125 | GULSetLoggerLevel(GULLoggerLevelDebug); 126 | 127 | GULLoggerLevel loggerLevel = GULGetLoggerLevel(); 128 | 129 | // The default logger level is GULLoggerLevelNotice. 130 | XCTAssertEqual(loggerLevel, GULLoggerLevelDebug); 131 | } 132 | 133 | - (void)testGULResetLogger_ResetsLoggerLevel { 134 | GULSetLoggerLevel(GULLoggerLevelDebug); 135 | 136 | GULResetLogger(); 137 | GULLoggerLevel loggerLevel = GULGetLoggerLevel(); 138 | 139 | // The default logger level is GULLoggerLevelNotice. 140 | XCTAssertEqual(loggerLevel, GULLoggerLevelNotice); 141 | } 142 | 143 | @end 144 | #endif 145 | -------------------------------------------------------------------------------- /GoogleUtilities/Tests/Unit/Network/GULMutableDictionaryTest.m: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import 16 | 17 | #import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" 18 | 19 | const static NSString *const kKey = @"testKey1"; 20 | const static NSString *const kValue = @"testValue1"; 21 | const static NSString *const kKey2 = @"testKey2"; 22 | const static NSString *const kValue2 = @"testValue2"; 23 | 24 | @interface GULMutableDictionaryTest : XCTestCase 25 | @property(nonatomic) GULMutableDictionary *dictionary; 26 | @end 27 | 28 | @implementation GULMutableDictionaryTest 29 | 30 | - (void)setUp { 31 | [super setUp]; 32 | self.dictionary = [[GULMutableDictionary alloc] init]; 33 | } 34 | 35 | - (void)tearDown { 36 | self.dictionary = nil; 37 | [super tearDown]; 38 | } 39 | 40 | - (void)testSetGetAndRemove { 41 | XCTAssertNil([self.dictionary objectForKey:kKey]); 42 | [self.dictionary setObject:kValue forKey:kKey]; 43 | XCTAssertEqual(kValue, [self.dictionary objectForKey:kKey]); 44 | [self.dictionary removeObjectForKey:kKey]; 45 | XCTAssertNil([self.dictionary objectForKey:kKey]); 46 | } 47 | 48 | - (void)testSetGetAndRemoveKeyed { 49 | XCTAssertNil(self.dictionary[kKey]); 50 | self.dictionary[kKey] = kValue; 51 | XCTAssertEqual(kValue, self.dictionary[kKey]); 52 | [self.dictionary removeObjectForKey:kKey]; 53 | XCTAssertNil(self.dictionary[kKey]); 54 | } 55 | 56 | - (void)testRemoveAll { 57 | XCTAssertNil(self.dictionary[kKey]); 58 | XCTAssertNil(self.dictionary[kKey2]); 59 | self.dictionary[kKey] = kValue; 60 | self.dictionary[kKey2] = kValue2; 61 | [self.dictionary removeAllObjects]; 62 | XCTAssertNil(self.dictionary[kKey]); 63 | XCTAssertNil(self.dictionary[kKey2]); 64 | } 65 | 66 | - (void)testCount { 67 | XCTAssertEqual([self.dictionary count], 0); 68 | self.dictionary[kKey] = kValue; 69 | XCTAssertEqual([self.dictionary count], 1); 70 | self.dictionary[kKey2] = kValue2; 71 | XCTAssertEqual([self.dictionary count], 2); 72 | [self.dictionary removeAllObjects]; 73 | XCTAssertEqual([self.dictionary count], 0); 74 | } 75 | 76 | - (void)testUnderlyingDictionary { 77 | XCTAssertEqual([self.dictionary count], 0); 78 | self.dictionary[kKey] = kValue; 79 | self.dictionary[kKey2] = kValue2; 80 | 81 | NSDictionary *dict = self.dictionary.dictionary; 82 | XCTAssertEqual([dict count], 2); 83 | XCTAssertEqual(dict[kKey], kValue); 84 | XCTAssertEqual(dict[kKey2], kValue2); 85 | } 86 | 87 | @end 88 | -------------------------------------------------------------------------------- /GoogleUtilities/Tests/Unit/Network/third_party/GTMHTTPServer.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2010 Google Inc. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | // 17 | // GTMHTTPServer.h 18 | // 19 | // This is a *very* *simple* webserver that can be built into something, it is 20 | // not meant to stand up a site, it sends all requests to its delegate for 21 | // processing on the main thread. It does not support pipelining, etc. It's 22 | // great for places where you need a simple webserver to unittest some code 23 | // that hits a server. 24 | // 25 | // NOTE: there are several TODOs left in here as markers for things that could 26 | // be done if one wanted to add more to this class. 27 | // 28 | // Based a little on HTTPServer, part of the CocoaHTTPServer sample code found at 29 | // https://opensource.apple.com/source/HTTPServer/HTTPServer-11/CocoaHTTPServer/ 30 | // License for the CocoaHTTPServer sample code: 31 | // 32 | // Software License Agreement (BSD License) 33 | // 34 | // Copyright (c) 2011, Deusty, LLC 35 | // All rights reserved. 36 | // 37 | // Redistribution and use of this software in source and binary forms, 38 | // with or without modification, are permitted provided that the following conditions are met: 39 | // 40 | // * Redistributions of source code must retain the above 41 | // copyright notice, this list of conditions and the 42 | // following disclaimer. 43 | // 44 | // * Neither the name of Deusty nor the names of its 45 | // contributors may be used to endorse or promote products 46 | // derived from this software without specific prior 47 | // written permission of Deusty, LLC. 48 | // 49 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 50 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 51 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 52 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 53 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 54 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 55 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 56 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 57 | // POSSIBILITY OF SUCH DAMAGE. 58 | 59 | #import 60 | 61 | #if GTM_IPHONE_SDK 62 | #import 63 | #endif // GTM_IPHONE_SDK 64 | 65 | // Global constants needed for errors from start 66 | 67 | #undef _EXTERN 68 | #undef _INITIALIZE_AS 69 | #ifdef GTMHTTPSERVER_DEFINE_GLOBALS 70 | #define _EXTERN 71 | #define _INITIALIZE_AS(x) = x 72 | #else 73 | #define _EXTERN extern 74 | #define _INITIALIZE_AS(x) 75 | #endif 76 | 77 | _EXTERN NSString *const kGTMHTTPServerErrorDomain 78 | _INITIALIZE_AS(@"com.google.mactoolbox.HTTPServerDomain"); 79 | enum { 80 | kGTMHTTPServerSocketCreateFailedError = -100, 81 | kGTMHTTPServerBindFailedError = -101, 82 | kGTMHTTPServerListenFailedError = -102, 83 | kGTMHTTPServerHandleCreateFailedError = -103, 84 | }; 85 | 86 | @class GTMHTTPRequestMessage, GTMHTTPResponseMessage; 87 | 88 | // ---------------------------------------------------------------------------- 89 | 90 | // See comment at top of file for the intended use of this class. 91 | @interface GTMHTTPServer : NSObject { 92 | @private 93 | id delegate_; // WEAK 94 | uint16_t port_; 95 | BOOL reusePort_; 96 | BOOL localhostOnly_; 97 | NSFileHandle *listenHandle_; 98 | NSMutableArray *connections_; 99 | } 100 | 101 | // The delegate must support the httpServer:handleRequest: method in 102 | // NSObject(GTMHTTPServerDelegateMethods) below. 103 | - (id)initWithDelegate:(id)delegate; 104 | 105 | - (id)delegate; 106 | 107 | // Passing port zero will let one get assigned. 108 | - (uint16_t)port; 109 | - (void)setPort:(uint16_t)port; 110 | 111 | // Controls listening socket behavior: SO_REUSEADDR vs SO_REUSEPORT. 112 | // The default is NO (SO_REUSEADDR) 113 | - (BOOL)reusePort; 114 | - (void)setReusePort:(BOOL)reusePort; 115 | 116 | // Receive connections on the localHost loopback address only or on all 117 | // interfaces for this machine. The default is to only listen on localhost. 118 | - (BOOL)localhostOnly; 119 | - (void)setLocalhostOnly:(BOOL)yesno; 120 | 121 | // Start/Stop the web server. If there is an error starting up the server, |NO| 122 | // is returned, and the specific startup failure can be returned in |error| (see 123 | // above for the error domain and error codes). If the server is started, |YES| 124 | // is returned and the server's delegate is called for any requests that come 125 | // in. 126 | - (BOOL)start:(NSError **)error; 127 | - (void)stop; 128 | 129 | // returns the number of requests currently active in the server (i.e.-being 130 | // read in, sent replies). 131 | - (NSUInteger)activeRequestCount; 132 | 133 | @end 134 | 135 | @interface NSObject (GTMHTTPServerDelegateMethods) 136 | - (GTMHTTPResponseMessage *)httpServer:(GTMHTTPServer *)server 137 | handleRequest:(GTMHTTPRequestMessage *)request; 138 | @end 139 | 140 | // ---------------------------------------------------------------------------- 141 | 142 | // Encapsulates an http request, one of these is sent to the server's delegate 143 | // for each request. 144 | @interface GTMHTTPRequestMessage : NSObject { 145 | @private 146 | CFHTTPMessageRef message_; 147 | } 148 | - (NSString *)version; 149 | - (NSURL *)URL; 150 | - (NSString *)method; 151 | - (NSData *)body; 152 | - (NSDictionary *)allHeaderFieldValues; 153 | @end 154 | 155 | // ---------------------------------------------------------------------------- 156 | 157 | // Encapsulates an http response, the server's delegate should return one for 158 | // each request received. 159 | @interface GTMHTTPResponseMessage : NSObject { 160 | @private 161 | CFHTTPMessageRef message_; 162 | } 163 | + (instancetype)responseWithString:(NSString *)plainText; 164 | + (instancetype)responseWithHTMLString:(NSString *)htmlString; 165 | + (instancetype)responseWithBody:(NSData *)body 166 | contentType:(NSString *)contentType 167 | statusCode:(int)statusCode; 168 | + (instancetype)emptyResponseWithCode:(int)statusCode; 169 | // TODO: class method for redirections? 170 | // TODO: add helper for expire/no-cache 171 | - (void)setValue:(NSString *)value forHeaderField:(NSString *)headerField; 172 | - (void)setHeaderValuesFromDictionary:(NSDictionary *)dict; 173 | @end 174 | -------------------------------------------------------------------------------- /GoogleUtilities/Tests/Unit/Network/third_party/LICENSE: -------------------------------------------------------------------------------- 1 | Based a little on HTTPServer, part of the CocoaHTTPServer sample code found at 2 | https://opensource.apple.com/source/HTTPServer/HTTPServer-11/CocoaHTTPServer/ 3 | License for the CocoaHTTPServer sample code: 4 | 5 | Software License Agreement (BSD License) 6 | 7 | Copyright (c) 2011, Deusty, LLC 8 | All rights reserved. 9 | 10 | Redistribution and use of this software in source and binary forms, 11 | with or without modification, are permitted provided that the following conditions are met: 12 | 13 | * Redistributions of source code must retain the above 14 | copyright notice, this list of conditions and the 15 | following disclaimer. 16 | 17 | * Neither the name of Deusty nor the names of its 18 | contributors may be used to endorse or promote products 19 | derived from this software without specific prior 20 | written permission of Deusty, LLC. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 23 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 24 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 25 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 29 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /GoogleUtilities/Tests/Unit/Shared/URLSession/FIRURLSessionOCMockStub.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | NS_ASSUME_NONNULL_BEGIN 20 | 21 | typedef BOOL (^FIRRequestValidationBlock)(NSURLRequest *request); 22 | 23 | @interface FIRURLSessionOCMockStub : NSObject 24 | 25 | + (id)stubURLSessionDataTaskWithResponse:(nullable NSHTTPURLResponse *)response 26 | body:(nullable NSData *)body 27 | error:(nullable NSError *)error 28 | URLSessionMock:(id)URLSessionMock 29 | requestValidationBlock:(nullable FIRRequestValidationBlock)requestValidationBlock; 30 | 31 | + (NSHTTPURLResponse *)HTTPResponseWithCode:(NSInteger)statusCode; 32 | 33 | @end 34 | 35 | NS_ASSUME_NONNULL_END 36 | -------------------------------------------------------------------------------- /GoogleUtilities/Tests/Unit/Shared/URLSession/FIRURLSessionOCMockStub.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import "GoogleUtilities/Tests/Unit/Shared/URLSession/FIRURLSessionOCMockStub.h" 18 | 19 | #import 20 | 21 | @implementation FIRURLSessionOCMockStub 22 | 23 | + (id)stubURLSessionDataTaskWithResponse:(NSHTTPURLResponse *)response 24 | body:(NSData *)body 25 | error:(NSError *)error 26 | URLSessionMock:(id)URLSessionMock 27 | requestValidationBlock:(FIRRequestValidationBlock)requestValidationBlock { 28 | id mockDataTask = OCMStrictClassMock([NSURLSessionDataTask class]); 29 | 30 | // Validate request content. 31 | FIRRequestValidationBlock nonOptionalRequestValidationBlock = 32 | requestValidationBlock ?: ^BOOL(id request) { 33 | return YES; 34 | }; 35 | 36 | id URLRequestValidationArg = [OCMArg checkWithBlock:nonOptionalRequestValidationBlock]; 37 | 38 | // Save task completion to be called on the `[NSURLSessionDataTask resume]` 39 | __block void (^taskCompletion)(NSData *, NSURLResponse *, NSError *); 40 | id completionArg = [OCMArg checkWithBlock:^BOOL(id obj) { 41 | taskCompletion = obj; 42 | return YES; 43 | }]; 44 | 45 | // Expect `dataTaskWithRequest` to be called. 46 | OCMExpect([URLSessionMock dataTaskWithRequest:URLRequestValidationArg 47 | completionHandler:completionArg]) 48 | .andReturn(mockDataTask); 49 | 50 | // Expect the task to be resumed and call the task completion. 51 | OCMExpect([(NSURLSessionDataTask *)mockDataTask resume]).andDo(^(NSInvocation *invocation) { 52 | taskCompletion(body, response, error); 53 | }); 54 | 55 | return mockDataTask; 56 | } 57 | 58 | + (NSHTTPURLResponse *)HTTPResponseWithCode:(NSInteger)statusCode { 59 | return [[NSHTTPURLResponse alloc] initWithURL:[NSURL URLWithString:@"http://localhost"] 60 | statusCode:statusCode 61 | HTTPVersion:@"HTTP/1.1" 62 | headerFields:nil]; 63 | } 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /GoogleUtilities/Tests/Unit/Swizzler/GULRuntimeClassDiffTests.m: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import 16 | 17 | #import "GoogleUtilities/SwizzlerTestHelpers/GULRuntimeClassDiff.h" 18 | 19 | @interface GULRuntimeClassDiffTests : XCTestCase 20 | 21 | @end 22 | 23 | @implementation GULRuntimeClassDiffTests 24 | 25 | /** Tests various different permutations of diff hashes and equality. */ 26 | - (void)testHashAndEquality { 27 | GULRuntimeClassDiff *classDiff1 = [[GULRuntimeClassDiff alloc] init]; 28 | classDiff1.aClass = [self class]; 29 | GULRuntimeClassDiff *classDiff2 = [[GULRuntimeClassDiff alloc] init]; 30 | classDiff2.aClass = [NSObject class]; 31 | XCTAssertNotEqual([classDiff1 hash], [classDiff2 hash]); 32 | XCTAssertNotEqualObjects(classDiff1, classDiff2); 33 | 34 | classDiff2.aClass = [self class]; 35 | XCTAssertEqual([classDiff1 hash], [classDiff2 hash]); 36 | XCTAssertEqualObjects(classDiff1, classDiff2); 37 | 38 | classDiff1.addedClassSelectors = [[NSSet alloc] initWithObjects:@"selector", nil]; 39 | XCTAssertNotEqual([classDiff1 hash], [classDiff2 hash]); 40 | XCTAssertNotEqualObjects(classDiff1, classDiff2); 41 | 42 | classDiff2.addedClassSelectors = [[NSSet alloc] initWithObjects:@"selector", nil]; 43 | XCTAssertEqual([classDiff1 hash], [classDiff2 hash]); 44 | XCTAssertEqualObjects(classDiff1, classDiff2); 45 | 46 | classDiff1.modifiedImps = [[NSSet alloc] initWithObjects:@"someImp", nil]; 47 | XCTAssertNotEqual([classDiff1 hash], [classDiff2 hash]); 48 | XCTAssertNotEqualObjects(classDiff1, classDiff2); 49 | 50 | classDiff2.modifiedImps = [[NSSet alloc] initWithObjects:@"someImp", nil]; 51 | XCTAssertEqual([classDiff1 hash], [classDiff2 hash]); 52 | XCTAssertEqualObjects(classDiff1, classDiff2); 53 | } 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /GoogleUtilities/Tests/Unit/Swizzler/GULRuntimeDiffTests.m: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import 16 | 17 | #import "GoogleUtilities/SwizzlerTestHelpers/GULRuntimeClassDiff.h" 18 | #import "GoogleUtilities/SwizzlerTestHelpers/GULRuntimeDiff.h" 19 | 20 | @interface GULRuntimeDiffTests : XCTestCase 21 | 22 | @end 23 | 24 | @implementation GULRuntimeDiffTests 25 | 26 | /** Tests various different permutations of diff hashes and equality. */ 27 | - (void)testHashAndEquality { 28 | GULRuntimeDiff *runtimeDiff1 = [[GULRuntimeDiff alloc] init]; 29 | GULRuntimeDiff *runtimeDiff2 = [[GULRuntimeDiff alloc] init]; 30 | XCTAssertEqual([runtimeDiff1 hash], [runtimeDiff2 hash]); 31 | XCTAssertEqualObjects(runtimeDiff1, runtimeDiff2); 32 | 33 | runtimeDiff1.addedClasses = [[NSSet alloc] initWithObjects:@"FakeClass", nil]; 34 | XCTAssertNotEqual([runtimeDiff1 hash], [runtimeDiff2 hash]); 35 | XCTAssertNotEqualObjects(runtimeDiff1, runtimeDiff2); 36 | 37 | runtimeDiff2.addedClasses = [[NSSet alloc] initWithObjects:@"FakeClass", nil]; 38 | XCTAssertEqual([runtimeDiff1 hash], [runtimeDiff2 hash]); 39 | XCTAssertEqualObjects(runtimeDiff1, runtimeDiff2); 40 | 41 | runtimeDiff1.removedClasses = [[NSSet alloc] initWithObjects:@"FakeClass", nil]; 42 | XCTAssertNotEqual([runtimeDiff1 hash], [runtimeDiff2 hash]); 43 | XCTAssertNotEqualObjects(runtimeDiff1, runtimeDiff2); 44 | 45 | runtimeDiff2.removedClasses = [[NSSet alloc] initWithObjects:@"FakeClass", nil]; 46 | XCTAssertEqual([runtimeDiff1 hash], [runtimeDiff2 hash]); 47 | XCTAssertEqualObjects(runtimeDiff1, runtimeDiff2); 48 | 49 | runtimeDiff2.classDiffs = [[NSSet alloc] init]; 50 | XCTAssertEqual([runtimeDiff1 hash], [runtimeDiff2 hash]); 51 | XCTAssertEqualObjects(runtimeDiff1, runtimeDiff2); 52 | 53 | runtimeDiff1.classDiffs = [[NSSet alloc] init]; 54 | XCTAssertEqual([runtimeDiff1 hash], [runtimeDiff2 hash]); 55 | XCTAssertEqualObjects(runtimeDiff1, runtimeDiff2); 56 | 57 | GULRuntimeClassDiff *classDiff1 = [[GULRuntimeClassDiff alloc] init]; 58 | classDiff1.aClass = [self class]; 59 | classDiff1.addedClassSelectors = [[NSSet alloc] initWithObjects:@"selector", nil]; 60 | 61 | GULRuntimeClassDiff *classDiff2 = [[GULRuntimeClassDiff alloc] init]; 62 | classDiff2.aClass = [self class]; 63 | classDiff2.addedClassSelectors = [[NSSet alloc] initWithObjects:@"selector2", nil]; 64 | 65 | runtimeDiff1.classDiffs = [runtimeDiff1.classDiffs setByAddingObject:classDiff1]; 66 | XCTAssertNotEqual([runtimeDiff1 hash], [runtimeDiff2 hash]); 67 | XCTAssertNotEqualObjects(runtimeDiff1, runtimeDiff2); 68 | 69 | runtimeDiff2.classDiffs = [runtimeDiff2.classDiffs setByAddingObject:classDiff1]; 70 | XCTAssertEqual([runtimeDiff1 hash], [runtimeDiff2 hash]); 71 | XCTAssertEqualObjects(runtimeDiff1, runtimeDiff2); 72 | 73 | runtimeDiff1.classDiffs = [runtimeDiff1.classDiffs setByAddingObject:classDiff2]; 74 | XCTAssertNotEqual([runtimeDiff1 hash], [runtimeDiff2 hash]); 75 | XCTAssertNotEqualObjects(runtimeDiff1, runtimeDiff2); 76 | } 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /GoogleUtilities/Tests/Unit/Swizzler/GULRuntimeSnapshotTests.m: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import 16 | #import 17 | 18 | #import "GoogleUtilities/SwizzlerTestHelpers/GULRuntimeDiff.h" 19 | #import "GoogleUtilities/SwizzlerTestHelpers/GULRuntimeSnapshot.h" 20 | 21 | @interface GULRuntimeSnapshotTestsTestClass : NSObject 22 | 23 | @end 24 | 25 | @implementation GULRuntimeSnapshotTestsTestClass 26 | 27 | - (NSString *)description { 28 | return [super description]; 29 | } 30 | 31 | @end 32 | 33 | @interface GULRuntimeSnapshotTests : XCTestCase 34 | 35 | @end 36 | 37 | @implementation GULRuntimeSnapshotTests 38 | 39 | /** Tests default init. */ 40 | - (void)testInitDoesntThrow { 41 | XCTAssertNoThrow([[GULRuntimeSnapshot alloc] init]); 42 | } 43 | 44 | /** Tests the designated initializer. */ 45 | - (void)testDesignatedInitializer { 46 | XCTAssertNoThrow([[GULRuntimeSnapshot alloc] initWithClasses:nil]); 47 | NSSet *classes = [NSSet setWithObjects:[NSString class], [NSObject class], [self class], nil]; 48 | XCTAssertNoThrow([[GULRuntimeSnapshot alloc] initWithClasses:classes]); 49 | } 50 | 51 | /** Tests equality of snapshots. */ 52 | - (void)testEquality { 53 | GULRuntimeSnapshot *snapshot1 = [[GULRuntimeSnapshot alloc] initWithClasses:nil]; 54 | GULRuntimeSnapshot *snapshot2 = [[GULRuntimeSnapshot alloc] initWithClasses:nil]; 55 | XCTAssertEqualObjects(snapshot1, snapshot2); 56 | snapshot1 = nil; 57 | snapshot2 = nil; 58 | 59 | NSSet *classSet = [NSSet setWithObject:[GULRuntimeSnapshotTestsTestClass class]]; 60 | snapshot1 = [[GULRuntimeSnapshot alloc] initWithClasses:classSet]; 61 | snapshot2 = [[GULRuntimeSnapshot alloc] initWithClasses:classSet]; 62 | XCTAssertEqualObjects(snapshot1, snapshot2); 63 | 64 | [snapshot1 capture]; 65 | [snapshot2 capture]; 66 | XCTAssertEqualObjects(snapshot1, snapshot2); 67 | 68 | SEL selector = @selector(description); 69 | Method description = class_getInstanceMethod([GULRuntimeSnapshotTestsTestClass class], selector); 70 | IMP newDescriptionIMP = imp_implementationWithBlock(^(id _self) { 71 | return @"swizzled description"; 72 | }); 73 | IMP originalDescriptionIMP = method_getImplementation(description); 74 | IMP probableOriginalDescriptionIMP = method_setImplementation(description, newDescriptionIMP); 75 | XCTAssertEqual(probableOriginalDescriptionIMP, originalDescriptionIMP); 76 | 77 | [snapshot1 capture]; 78 | [snapshot2 capture]; 79 | XCTAssertEqualObjects(snapshot1, snapshot2); 80 | 81 | method_setImplementation(description, originalDescriptionIMP); 82 | 83 | [snapshot2 capture]; 84 | XCTAssertNotEqualObjects(snapshot2, snapshot1); 85 | [snapshot1 capture]; 86 | XCTAssertEqualObjects(snapshot1, snapshot2); 87 | } 88 | 89 | /** Tests capturing snapshots doesn't throw. */ 90 | - (void)testCapture { 91 | GULRuntimeSnapshot *snapshot1 = [[GULRuntimeSnapshot alloc] initWithClasses:nil]; 92 | XCTAssertNoThrow([snapshot1 capture]); 93 | 94 | GULRuntimeSnapshot *snapshot2 = [[GULRuntimeSnapshot alloc] initWithClasses:nil]; 95 | XCTAssertNoThrow([snapshot2 capture]); 96 | } 97 | 98 | /** Tests detecting a new class works. */ 99 | - (void)testNewClassDetected { 100 | GULRuntimeSnapshot *snapshot1 = [[GULRuntimeSnapshot alloc] initWithClasses:nil]; 101 | [snapshot1 capture]; 102 | 103 | Class newClass = objc_allocateClassPair([NSObject class], "GULNewClass", 0); 104 | objc_registerClassPair(newClass); 105 | 106 | GULRuntimeSnapshot *snapshot2 = [[GULRuntimeSnapshot alloc] initWithClasses:nil]; 107 | [snapshot2 capture]; 108 | 109 | GULRuntimeDiff *diff = [snapshot1 diff:snapshot2]; 110 | XCTAssertGreaterThan(diff.addedClasses.count, 0); 111 | BOOL found = NO; 112 | for (NSString *class in diff.addedClasses) { 113 | if ([class isEqualToString:@"GULNewClass"]) { 114 | found = YES; 115 | break; 116 | } 117 | } 118 | XCTAssertTrue(found); 119 | } 120 | 121 | /** Tests detecting a class deletion works. */ 122 | - (void)testClassRemovedDetected { 123 | Class newClass = objc_allocateClassPair([NSObject class], "GULNewClass2", 0); 124 | objc_registerClassPair(newClass); 125 | 126 | GULRuntimeSnapshot *snapshot1 = [[GULRuntimeSnapshot alloc] initWithClasses:nil]; 127 | [snapshot1 capture]; 128 | 129 | objc_disposeClassPair(NSClassFromString(@"GULNewClass2")); 130 | 131 | GULRuntimeSnapshot *snapshot2 = [[GULRuntimeSnapshot alloc] initWithClasses:nil]; 132 | [snapshot2 capture]; 133 | 134 | GULRuntimeDiff *diff = [snapshot1 diff:snapshot2]; 135 | XCTAssertGreaterThan(diff.removedClasses.count, 0); 136 | BOOL found = NO; 137 | for (NSString *class in diff.removedClasses) { 138 | if ([class isEqualToString:@"GULNewClass2"]) { 139 | found = YES; 140 | break; 141 | } 142 | } 143 | XCTAssertTrue(found); 144 | } 145 | 146 | @end 147 | -------------------------------------------------------------------------------- /GoogleUtilities/Tests/Unit/Swizzler/GULRuntimeStateHelperTests.m: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import 16 | #import 17 | 18 | #import "GoogleUtilities/SwizzlerTestHelpers/GULRuntimeStateHelper.h" 19 | 20 | @interface GULRuntimeStateHelperTestHelperClass : NSObject 21 | 22 | @end 23 | 24 | @implementation GULRuntimeStateHelperTestHelperClass 25 | 26 | @end 27 | 28 | @interface GULRuntimeStateHelperTests : XCTestCase 29 | 30 | @end 31 | 32 | @implementation GULRuntimeStateHelperTests 33 | 34 | - (void)testCaptureRuntimeState { 35 | NSUInteger snapshot1 = 0; 36 | XCTAssertNoThrow(snapshot1 = [GULRuntimeStateHelper captureRuntimeState]); 37 | } 38 | 39 | - (void)testDiffBetweenFirstSnapshotSecondSnapshot { 40 | NSUInteger snapshot1 = [GULRuntimeStateHelper captureRuntimeState]; 41 | 42 | NSString *newClassName = [NSStringFromClass([self class]) stringByAppendingString:@"_gen"]; 43 | Class newSubclass = objc_allocateClassPair([self class], [newClassName UTF8String], 0); 44 | objc_registerClassPair(newSubclass); 45 | 46 | Method dummyMethod = class_getInstanceMethod([self class], @selector(dummyMethod)); 47 | IMP originalIMP = method_getImplementation(dummyMethod); 48 | NSString *originalIMPString = [NSString stringWithFormat:@"%p", originalIMP]; 49 | IMP newIMP = imp_implementationWithBlock((NSString *)^(id _self) { 50 | return @"Goodbye!"; 51 | }); 52 | method_setImplementation(dummyMethod, newIMP); 53 | 54 | NSUInteger snapshot2 = [GULRuntimeStateHelper captureRuntimeState]; 55 | GULRuntimeDiff *diff = [GULRuntimeStateHelper diffBetween:snapshot1 secondSnapshot:snapshot2]; 56 | 57 | BOOL found = NO; 58 | for (NSString *class in diff.addedClasses) { 59 | if ([class isEqualToString:newClassName]) { 60 | found = YES; 61 | break; 62 | } 63 | } 64 | XCTAssertTrue(found, @"The generated class above should be found in the list of added classes"); 65 | 66 | found = NO; 67 | for (GULRuntimeClassDiff *classDiff in diff.classDiffs) { 68 | for (NSString *modifiedIMP in classDiff.modifiedImps) { 69 | if ([modifiedIMP containsString:originalIMPString]) { 70 | found = YES; 71 | break; 72 | } 73 | } 74 | } 75 | XCTAssertTrue(found, @"One of the classdiffs should contain the address of the original IMP of " 76 | "the method that was modified above"); 77 | } 78 | 79 | #pragma mark - Helper methods 80 | 81 | /** Exists to just be swizzled, to test detection capability. 82 | * 83 | * @return The string "Hello!". 84 | */ 85 | - (NSString *)dummyMethod { 86 | return @"Hello!"; 87 | } 88 | 89 | @end 90 | -------------------------------------------------------------------------------- /GoogleUtilities/Tests/Unit/Utils/GULTestKeychain.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #import 17 | #import 18 | 19 | NS_ASSUME_NONNULL_BEGIN 20 | 21 | #if TARGET_OS_OSX 22 | 23 | @interface GULTestKeychain : NSObject 24 | 25 | - (nullable instancetype)init; 26 | 27 | @property(nonatomic, readonly, nullable) SecKeychainRef testKeychainRef; 28 | 29 | @end 30 | 31 | #endif // TARGET_OS_OSX 32 | 33 | NS_ASSUME_NONNULL_END 34 | -------------------------------------------------------------------------------- /GoogleUtilities/Tests/Unit/Utils/GULTestKeychain.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | #if TARGET_OS_OSX 19 | 20 | #import "GoogleUtilities/Tests/Unit/Utils/GULTestKeychain.h" 21 | 22 | #import 23 | 24 | @implementation GULTestKeychain 25 | 26 | - (nullable instancetype)init { 27 | self = [super init]; 28 | if (self) { 29 | SecKeychainRef privateKeychain; 30 | NSString *keychainPath = 31 | [NSTemporaryDirectory() stringByAppendingPathComponent:@"GULTestKeychain"]; 32 | if ([[NSFileManager defaultManager] fileExistsAtPath:keychainPath]) { 33 | NSError *error; 34 | if (![[NSFileManager defaultManager] removeItemAtPath:keychainPath error:&error]) { 35 | NSLog(@"Failed to delete existing test keychain: %@", error); 36 | return nil; 37 | } 38 | } 39 | #pragma clang diagnostic push 40 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 41 | OSStatus result = SecKeychainCreate([keychainPath cStringUsingEncoding:NSUTF8StringEncoding], 0, 42 | "1", false, nil, &privateKeychain); 43 | #pragma clang diagnostic pop 44 | if (result != errSecSuccess) { 45 | NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:result userInfo:nil]; 46 | NSLog(@"SecKeychainCreate error: %@", error); 47 | return nil; 48 | } 49 | _testKeychainRef = privateKeychain; 50 | } 51 | return self; 52 | } 53 | 54 | - (void)dealloc { 55 | if (self.testKeychainRef) { 56 | #pragma clang diagnostic push 57 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 58 | OSStatus result = SecKeychainDelete(self.testKeychainRef); 59 | #pragma clang diagnostic pop 60 | if (result != errSecSuccess) { 61 | NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:result userInfo:nil]; 62 | NSLog(@"SecKeychainCreate error: %@", error); 63 | } 64 | 65 | CFRelease(self.testKeychainRef); 66 | } 67 | } 68 | 69 | @end 70 | 71 | #endif // TARGET_OS_OSX 72 | -------------------------------------------------------------------------------- /GoogleUtilities/UserDefaults/GULUserDefaults.m: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import "GoogleUtilities/UserDefaults/Public/GoogleUtilities/GULUserDefaults.h" 16 | 17 | #import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" 18 | 19 | NS_ASSUME_NONNULL_BEGIN 20 | 21 | static NSString *const kGULLogFormat = @"I-GUL%06ld"; 22 | 23 | static GULLoggerService kGULLogUserDefaultsService = @"[GoogleUtilities/UserDefaults]"; 24 | 25 | typedef NS_ENUM(NSInteger, GULUDMessageCode) { 26 | GULUDMessageCodeInvalidKeyGet = 1, 27 | GULUDMessageCodeInvalidKeySet = 2, 28 | GULUDMessageCodeInvalidObjectSet = 3, 29 | GULUDMessageCodeSynchronizeFailed = 4, 30 | }; 31 | 32 | @interface GULUserDefaults () 33 | 34 | @property(nonatomic, readonly) NSUserDefaults *userDefaults; 35 | 36 | @end 37 | 38 | @implementation GULUserDefaults 39 | 40 | + (GULUserDefaults *)standardUserDefaults { 41 | static GULUserDefaults *standardUserDefaults; 42 | static dispatch_once_t onceToken; 43 | dispatch_once(&onceToken, ^{ 44 | standardUserDefaults = [[GULUserDefaults alloc] init]; 45 | }); 46 | return standardUserDefaults; 47 | } 48 | 49 | - (instancetype)init { 50 | return [self initWithSuiteName:nil]; 51 | } 52 | 53 | - (instancetype)initWithSuiteName:(nullable NSString *)suiteName { 54 | self = [super init]; 55 | 56 | NSString *name = [suiteName copy]; 57 | 58 | if (self) { 59 | _userDefaults = name.length ? [[NSUserDefaults alloc] initWithSuiteName:name] 60 | : [NSUserDefaults standardUserDefaults]; 61 | } 62 | 63 | return self; 64 | } 65 | 66 | - (nullable id)objectForKey:(NSString *)defaultName { 67 | NSString *key = [defaultName copy]; 68 | if (![key isKindOfClass:[NSString class]] || !key.length) { 69 | GULOSLogWarning(kGULLogSubsystem, @"", NO, 70 | [NSString stringWithFormat:kGULLogFormat, (long)GULUDMessageCodeInvalidKeyGet], 71 | @"Cannot get object for invalid user default key."); 72 | return nil; 73 | } 74 | 75 | return [self.userDefaults objectForKey:key]; 76 | } 77 | 78 | - (void)setObject:(nullable id)value forKey:(NSString *)defaultName { 79 | NSString *key = [defaultName copy]; 80 | if (![key isKindOfClass:[NSString class]] || !key.length) { 81 | GULOSLogWarning(kGULLogSubsystem, kGULLogUserDefaultsService, NO, 82 | [NSString stringWithFormat:kGULLogFormat, (long)GULUDMessageCodeInvalidKeySet], 83 | @"Cannot set object for invalid user default key."); 84 | return; 85 | } 86 | if (!value) { 87 | [self.userDefaults removeObjectForKey:key]; 88 | return; 89 | } 90 | BOOL isAcceptableValue = 91 | [value isKindOfClass:[NSString class]] || [value isKindOfClass:[NSNumber class]] || 92 | [value isKindOfClass:[NSArray class]] || [value isKindOfClass:[NSDictionary class]] || 93 | [value isKindOfClass:[NSDate class]] || [value isKindOfClass:[NSData class]]; 94 | if (!isAcceptableValue) { 95 | GULOSLogWarning( 96 | kGULLogSubsystem, kGULLogUserDefaultsService, NO, 97 | [NSString stringWithFormat:kGULLogFormat, (long)GULUDMessageCodeInvalidObjectSet], 98 | @"Cannot set invalid object to user defaults. Must be a string, number, array, " 99 | @"dictionary, date, or data. Value: %@", 100 | value); 101 | return; 102 | } 103 | 104 | [self.userDefaults setObject:value forKey:key]; 105 | } 106 | 107 | - (void)removeObjectForKey:(NSString *)key { 108 | [self setObject:nil forKey:key]; 109 | } 110 | 111 | #pragma mark - Getters 112 | 113 | - (NSInteger)integerForKey:(NSString *)defaultName { 114 | NSNumber *object = [self objectForKey:defaultName]; 115 | return object.integerValue; 116 | } 117 | 118 | - (float)floatForKey:(NSString *)defaultName { 119 | NSNumber *object = [self objectForKey:defaultName]; 120 | return object.floatValue; 121 | } 122 | 123 | - (double)doubleForKey:(NSString *)defaultName { 124 | NSNumber *object = [self objectForKey:defaultName]; 125 | return object.doubleValue; 126 | } 127 | 128 | - (BOOL)boolForKey:(NSString *)defaultName { 129 | NSNumber *object = [self objectForKey:defaultName]; 130 | return object.boolValue; 131 | } 132 | 133 | - (nullable NSString *)stringForKey:(NSString *)defaultName { 134 | return [self objectForKey:defaultName]; 135 | } 136 | 137 | - (nullable NSArray *)arrayForKey:(NSString *)defaultName { 138 | return [self objectForKey:defaultName]; 139 | } 140 | 141 | - (nullable NSDictionary *)dictionaryForKey:(NSString *)defaultName { 142 | return [self objectForKey:defaultName]; 143 | } 144 | 145 | #pragma mark - Setters 146 | 147 | - (void)setInteger:(NSInteger)integer forKey:(NSString *)defaultName { 148 | [self setObject:@(integer) forKey:defaultName]; 149 | } 150 | 151 | - (void)setFloat:(float)value forKey:(NSString *)defaultName { 152 | [self setObject:@(value) forKey:defaultName]; 153 | } 154 | 155 | - (void)setDouble:(double)doubleNumber forKey:(NSString *)defaultName { 156 | [self setObject:@(doubleNumber) forKey:defaultName]; 157 | } 158 | 159 | - (void)setBool:(BOOL)boolValue forKey:(NSString *)defaultName { 160 | [self setObject:@(boolValue) forKey:defaultName]; 161 | } 162 | 163 | @end 164 | 165 | NS_ASSUME_NONNULL_END 166 | -------------------------------------------------------------------------------- /GoogleUtilities/UserDefaults/Public/GoogleUtilities/GULUserDefaults.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import 16 | 17 | NS_ASSUME_NONNULL_BEGIN 18 | 19 | /// A thread-safe user defaults that uses C functions from CFPreferences.h instead of 20 | /// `NSUserDefaults`. This is to avoid sending an `NSNotification` when it's changed from a 21 | /// background thread to avoid crashing. // TODO: Insert radar number here. 22 | @interface GULUserDefaults : NSObject 23 | 24 | /// A shared user defaults similar to +[NSUserDefaults standardUserDefaults] and accesses the same 25 | /// data of the standardUserDefaults. 26 | + (GULUserDefaults *)standardUserDefaults; 27 | 28 | /// Initializes preferences with a suite name that is the same with the NSUserDefaults' suite name. 29 | /// Both of CFPreferences and NSUserDefaults share the same plist file so their data will exactly 30 | /// the same. 31 | /// 32 | /// @param suiteName The name of the suite of the user defaults. 33 | - (instancetype)initWithSuiteName:(nullable NSString *)suiteName; 34 | 35 | #pragma mark - Getters 36 | 37 | /// Searches the receiver's search list for a default with the key 'defaultName' and return it. If 38 | /// another process has changed defaults in the search list, NSUserDefaults will automatically 39 | /// update to the latest values. If the key in question has been marked as ubiquitous via a Defaults 40 | /// Configuration File, the latest value may not be immediately available, and the registered value 41 | /// will be returned instead. 42 | - (nullable id)objectForKey:(NSString *)defaultName; 43 | 44 | /// Equivalent to -objectForKey:, except that it will return nil if the value is not an NSArray. 45 | - (nullable NSArray *)arrayForKey:(NSString *)defaultName; 46 | 47 | /// Equivalent to -objectForKey:, except that it will return nil if the value 48 | /// is not an NSDictionary. 49 | - (nullable NSDictionary *)dictionaryForKey:(NSString *)defaultName; 50 | 51 | /// Equivalent to -objectForKey:, except that it will convert NSNumber values to their NSString 52 | /// representation. If a non-string non-number value is found, nil will be returned. 53 | - (nullable NSString *)stringForKey:(NSString *)defaultName; 54 | 55 | /// Equivalent to -objectForKey:, except that it converts the returned value to an NSInteger. If the 56 | /// value is an NSNumber, the result of -integerValue will be returned. If the value is an NSString, 57 | /// it will be converted to NSInteger if possible. If the value is a boolean, it will be converted 58 | /// to either 1 for YES or 0 for NO. If the value is absent or can't be converted to an integer, 0 59 | /// will be returned. 60 | - (NSInteger)integerForKey:(NSString *)defaultName; 61 | 62 | /// Similar to -integerForKey:, except that it returns a float, and boolean values will not be 63 | /// converted. 64 | - (float)floatForKey:(NSString *)defaultName; 65 | 66 | /// Similar to -integerForKey:, except that it returns a double, and boolean values will not be 67 | /// converted. 68 | - (double)doubleForKey:(NSString *)defaultName; 69 | 70 | /// Equivalent to -objectForKey:, except that it converts the returned value to a BOOL. If the value 71 | /// is an NSNumber, NO will be returned if the value is 0, YES otherwise. If the value is an 72 | /// NSString, values of "YES" or "1" will return YES, and values of "NO", "0", or any other string 73 | /// will return NO. If the value is absent or can't be converted to a BOOL, NO will be returned. 74 | - (BOOL)boolForKey:(NSString *)defaultName; 75 | 76 | #pragma mark - Setters 77 | 78 | /// Immediately stores a value (or removes the value if `nil` is passed as the value) for the 79 | /// provided key in the search list entry for the receiver's suite name in the current user and any 80 | /// host, then asynchronously stores the value persistently, where it is made available to other 81 | /// processes. 82 | - (void)setObject:(nullable id)value forKey:(NSString *)defaultName; 83 | 84 | /// Equivalent to -setObject:forKey: except that the value is converted from a float to an NSNumber. 85 | - (void)setFloat:(float)value forKey:(NSString *)defaultName; 86 | 87 | /// Equivalent to -setObject:forKey: except that the value is converted from a double to an 88 | /// NSNumber. 89 | - (void)setDouble:(double)value forKey:(NSString *)defaultName; 90 | 91 | /// Equivalent to -setObject:forKey: except that the value is converted from an NSInteger to an 92 | /// NSNumber. 93 | - (void)setInteger:(NSInteger)value forKey:(NSString *)defaultName; 94 | 95 | /// Equivalent to -setObject:forKey: except that the value is converted from a BOOL to an NSNumber. 96 | - (void)setBool:(BOOL)value forKey:(NSString *)defaultName; 97 | 98 | #pragma mark - Removing Defaults 99 | 100 | /// Equivalent to -[... setObject:nil forKey:defaultName] 101 | - (void)removeObjectForKey:(NSString *)defaultName; 102 | 103 | @end 104 | 105 | NS_ASSUME_NONNULL_END 106 | -------------------------------------------------------------------------------- /GoogleUtilities/UserDefaults/Resources/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyTracking 6 | 7 | NSPrivacyTrackingDomains 8 | 9 | 10 | NSPrivacyCollectedDataTypes 11 | 12 | 13 | NSPrivacyAccessedAPITypes 14 | 15 | 16 | NSPrivacyAccessedAPIType 17 | NSPrivacyAccessedAPICategoryUserDefaults 18 | NSPrivacyAccessedAPITypeReasons 19 | 20 | 1C8F.1 21 | C56D.1 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Mintfile: -------------------------------------------------------------------------------- 1 | nicklockwood/SwiftFormat@0.49.2 2 | -------------------------------------------------------------------------------- /SwiftPMTests/objc-import-test/objc-header.m: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import "GoogleUtilities/GULApplication.h" 16 | #import "GoogleUtilities/GULKeychainStorage.h" 17 | #import "GoogleUtilities/GULLogger.h" 18 | #import "GoogleUtilities/GULNSData+zlib.h" 19 | #import "GoogleUtilities/GULNetwork.h" 20 | #import "GoogleUtilities/GULReachabilityChecker.h" 21 | #import "GoogleUtilities/GULSwizzler.h" 22 | #import "GoogleUtilities/GULUserDefaults.h" 23 | 24 | #import 25 | #import 26 | #import 27 | #import 28 | #import 29 | #import 30 | #import 31 | #import 32 | -------------------------------------------------------------------------------- /SwiftPMTests/objc-import-test/objc-module.m: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | @import GoogleUtilities_AppDelegateSwizzler; 16 | @import GoogleUtilities_Environment; 17 | @import GoogleUtilities_Logger; 18 | @import GoogleUtilities_MethodSwizzler; 19 | @import GoogleUtilities_Network; 20 | @import GoogleUtilities_NSData; 21 | @import GoogleUtilities_Reachability; 22 | @import GoogleUtilities_UserDefaults; 23 | -------------------------------------------------------------------------------- /SwiftPMTests/swift-test/main.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import Foundation 16 | import GoogleUtilities_AppDelegateSwizzler 17 | import GoogleUtilities_Environment 18 | import GoogleUtilities_Logger 19 | import GoogleUtilities_MethodSwizzler 20 | import GoogleUtilities_Network 21 | import GoogleUtilities_NSData 22 | import GoogleUtilities_Reachability 23 | import GoogleUtilities_UserDefaults 24 | 25 | import XCTest 26 | 27 | class importTest: XCTestCase { 28 | func testImports() throws { 29 | XCTAssertFalse(GULAppEnvironmentUtil.isAppStoreReceiptSandbox()) 30 | XCTAssertFalse(GULAppEnvironmentUtil.isFromAppStore()) 31 | #if targetEnvironment(simulator) 32 | XCTAssertTrue(GULAppEnvironmentUtil.isSimulator()) 33 | #else 34 | XCTAssertFalse(GULAppEnvironmentUtil.isSimulator()) 35 | #endif 36 | XCTAssertFalse(GULAppEnvironmentUtil.isAppExtension()) 37 | 38 | #if os(macOS) || targetEnvironment(macCatalyst) 39 | // Device model should now return the appropriate hardware model on macOS. 40 | XCTAssertNotEqual(GULAppEnvironmentUtil.deviceModel(), "x86_64") 41 | #else 42 | // Device model should show up as x86_64 for iOS, tvOS, and watchOS 43 | // simulators. 44 | let device = GULAppEnvironmentUtil.deviceModel() 45 | XCTAssertTrue(device == "x86_64" || device == "arm64") 46 | #endif 47 | 48 | print("System version? Answer: \(GULAppEnvironmentUtil.systemVersion())") 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /setup-scripts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2021 Google LLC 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License. 13 | 14 | git clone \ 15 | --depth 1 \ 16 | --no-checkout \ 17 | https://github.com/firebase/firebase-ios-sdk.git \ 18 | ; 19 | cd firebase-ios-sdk 20 | git checkout main -- scripts 21 | cd .. 22 | ln -s firebase-ios-sdk/scripts scripts 23 | -------------------------------------------------------------------------------- /third_party/IsAppEncrypted/IsAppEncrypted.m: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Landon J. Fuller 2 | // All rights reserved. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to 6 | // deal in the Software without restriction, including without limitation the 7 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | // IN THE SOFTWARE. 21 | // 22 | // Comment from 23 | // iPhone Dev 24 | // Wiki Crack Prevention: 25 | // App Store binaries are signed by both their developer and Apple. This 26 | // encrypts the binary so that decryption keys are needed in order to make the 27 | // binary readable. When iOS executes the binary, the decryption keys are used 28 | // to decrypt the binary into a readable state where it is then loaded into 29 | // memory and executed. iOS can tell the encryption status of a binary via the 30 | // cryptid structure member of LC_ENCRYPTION_INFO MachO load command. If 31 | // cryptid is a non-zero value then the binary is encrypted. 32 | // 33 | // 'Cracking' works by letting the kernel decrypt the binary then siphoning the 34 | // decrypted data into a new binary file, resigning, and repackaging. This will 35 | // only work on jailbroken devices as codesignature validation has been 36 | // removed. Resigning takes place because while the codesignature doesn't have 37 | // to be valid thanks to the jailbreak, it does have to be in place unless you 38 | // have AppSync or similar to disable codesignature checks. 39 | // 40 | // More information at 41 | // Landon Fuller's blog 42 | 43 | #import "third_party/IsAppEncrypted/Public/IsAppEncrypted.h" 44 | 45 | #import 46 | #import 47 | 48 | /// The encryption info struct and constants are missing from the iPhoneSimulator SDK, but not from 49 | /// the iPhoneOS or Mac OS X SDKs. Since one doesn't ever ship a Simulator binary, we'll just 50 | /// provide the definitions here. 51 | #if TARGET_OS_SIMULATOR && !defined(LC_ENCRYPTION_INFO) 52 | #define LC_ENCRYPTION_INFO 0x21 53 | struct encryption_info_command { 54 | uint32_t cmd; 55 | uint32_t cmdsize; 56 | uint32_t cryptoff; 57 | uint32_t cryptsize; 58 | uint32_t cryptid; 59 | }; 60 | #endif 61 | 62 | BOOL IsAppEncrypted(void) { 63 | const struct mach_header *executableHeader = NULL; 64 | for (uint32_t i = 0; i < _dyld_image_count(); i++) { 65 | const struct mach_header *header = _dyld_get_image_header(i); 66 | if (header && header->filetype == MH_EXECUTE) { 67 | executableHeader = header; 68 | break; 69 | } 70 | } 71 | 72 | if (!executableHeader) { 73 | return NO; 74 | } 75 | 76 | BOOL is64bit = (executableHeader->magic == MH_MAGIC_64); 77 | uintptr_t cursor = (uintptr_t)executableHeader + 78 | (is64bit ? sizeof(struct mach_header_64) : sizeof(struct mach_header)); 79 | const struct segment_command *segmentCommand = NULL; 80 | uint32_t i = 0; 81 | 82 | while (i++ < executableHeader->ncmds) { 83 | segmentCommand = (struct segment_command *)cursor; 84 | 85 | if (!segmentCommand) { 86 | continue; 87 | } 88 | 89 | if ((!is64bit && segmentCommand->cmd == LC_ENCRYPTION_INFO) || 90 | (is64bit && segmentCommand->cmd == LC_ENCRYPTION_INFO_64)) { 91 | if (is64bit) { 92 | struct encryption_info_command_64 *cryptCmd = 93 | (struct encryption_info_command_64 *)segmentCommand; 94 | return cryptCmd && cryptCmd->cryptid != 0; 95 | } else { 96 | struct encryption_info_command *cryptCmd = (struct encryption_info_command *)segmentCommand; 97 | return cryptCmd && cryptCmd->cryptid != 0; 98 | } 99 | } 100 | cursor += segmentCommand->cmdsize; 101 | } 102 | 103 | return NO; 104 | } 105 | -------------------------------------------------------------------------------- /third_party/IsAppEncrypted/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Landon J. Fuller 2 | All rights reserved. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | and associated documentation files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | Software is furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all copies or 11 | substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 17 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /third_party/IsAppEncrypted/Public/IsAppEncrypted.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Landon J. Fuller 2 | // All rights reserved. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to 6 | // deal in the Software without restriction, including without limitation the 7 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | // IN THE SOFTWARE. 21 | 22 | #import 23 | 24 | BOOL IsAppEncrypted(void); 25 | --------------------------------------------------------------------------------