diff --git a/.github/workflows/build-and-lint.yml b/.github/workflows/build-and-lint.yml index b1743ea5a..965be3080 100644 --- a/.github/workflows/build-and-lint.yml +++ b/.github/workflows/build-and-lint.yml @@ -21,10 +21,10 @@ jobs: steps: - name: Checkout uses: actions/checkout@v5 - + - name: Select Xcode run: sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app - + - name: Update xcodeproj gem run: sudo gem install xcodeproj diff --git a/.github/workflows/build-secondary-platforms.yml b/.github/workflows/build-secondary-platforms.yml index df6d896d2..ba27e4b9e 100644 --- a/.github/workflows/build-secondary-platforms.yml +++ b/.github/workflows/build-secondary-platforms.yml @@ -17,7 +17,7 @@ jobs: - name: Select Xcode run: sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app - + - name: Add React Native cli run: yarn add -D @react-native-community/cli diff --git a/.github/workflows/cross-platform-tests.yml b/.github/workflows/cross-platform-tests.yml index 7c8478ee2..32ec7e23d 100644 --- a/.github/workflows/cross-platform-tests.yml +++ b/.github/workflows/cross-platform-tests.yml @@ -44,4 +44,4 @@ jobs: uses: actions/upload-artifact@v4 with: name: ios-test-results - path: Users/runner/Library/Developer/Xcode/DerivedData \ No newline at end of file + path: Users/runner/Library/Developer/Xcode/DerivedData diff --git a/.github/workflows/issue-autorespond-and-close.yml b/.github/workflows/issue-autorespond-and-close.yml index f1a6baa64..bc1347c8a 100644 --- a/.github/workflows/issue-autorespond-and-close.yml +++ b/.github/workflows/issue-autorespond-and-close.yml @@ -11,4 +11,4 @@ jobs: with: issue_number: ${{ github.event.issue.number }} repository: ${{ github.repository }} - user_login: ${{ github.event.issue.user.login }} \ No newline at end of file + user_login: ${{ github.event.issue.user.login }} diff --git a/.github/workflows/native-tests.yml b/.github/workflows/native-tests.yml index e7d4a81ac..d176781cf 100644 --- a/.github/workflows/native-tests.yml +++ b/.github/workflows/native-tests.yml @@ -29,6 +29,6 @@ jobs: - name: Select Xcode run: sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app - + - name: Run iOS unit tests run: xcodebuild -project mParticle-Apple-SDK.xcodeproj -scheme ${{ matrix.scheme }} -destination 'platform=${{ matrix.platform }} Simulator,name=${{ matrix.device }},OS=latest' test diff --git a/.trunk/.gitignore b/.trunk/.gitignore new file mode 100644 index 000000000..15966d087 --- /dev/null +++ b/.trunk/.gitignore @@ -0,0 +1,9 @@ +*out +*logs +*actions +*notifications +*tools +plugins +user_trunk.yaml +user.yaml +tmp diff --git a/.trunk/configs/.isort.cfg b/.trunk/configs/.isort.cfg new file mode 100644 index 000000000..b9fb3f3e8 --- /dev/null +++ b/.trunk/configs/.isort.cfg @@ -0,0 +1,2 @@ +[settings] +profile=black diff --git a/.trunk/configs/.markdownlint.yaml b/.trunk/configs/.markdownlint.yaml new file mode 100644 index 000000000..b40ee9d7a --- /dev/null +++ b/.trunk/configs/.markdownlint.yaml @@ -0,0 +1,2 @@ +# Prettier friendly markdownlint config (all formatting rules disabled) +extends: markdownlint/style/prettier diff --git a/.trunk/configs/.shellcheckrc b/.trunk/configs/.shellcheckrc new file mode 100644 index 000000000..8c7b1ada8 --- /dev/null +++ b/.trunk/configs/.shellcheckrc @@ -0,0 +1,7 @@ +enable=all +source-path=SCRIPTDIR +disable=SC2154 + +# If you're having issues with shellcheck following source, disable the errors via: +# disable=SC1090 +# disable=SC1091 diff --git a/.trunk/configs/.swiftformat b/.trunk/configs/.swiftformat new file mode 100644 index 000000000..3aa835f44 --- /dev/null +++ b/.trunk/configs/.swiftformat @@ -0,0 +1,117 @@ +--swiftversion 5.9 +--acronyms ID,URL,UUID +--allman false +--anonymousforeach convert +--assetliterals visual-width +--asynccapturing +--beforemarks +--binarygrouping none +--callsiteparen default +--categorymark "MARK: %c" +--classthreshold 0 +--closingparen balanced +--closurevoid remove +--commas inline +--complexattrs preserve +--computedvarattrs preserve +--condassignment after-property +--conflictmarkers reject +--dateformat system +--decimalgrouping none +--doccomments before-declarations +--elseposition same-line +--emptybraces no-space +--enumnamespaces always +--enumthreshold 0 +--exponentcase lowercase +--exponentgrouping disabled +--extensionacl on-extension +--extensionlength 0 +--extensionmark "MARK: - %t + %c" +--fractiongrouping disabled +--fragment false +--funcattributes preserve +--generictypes +--groupedextension "MARK: %c" +--guardelse auto +--header ignore +--hexgrouping none +--hexliteralcase uppercase +--ifdef no-indent +--importgrouping alpha +--indent 4 +--indentcase false +--indentstrings false +--initcodernil false +--lifecycle +--lineaftermarks true +--linebreaks lf +--markcategories true +--markextensions always +--marktypes always + +# Wrap lines that exceed the specified maximum width. +--rules wrap +--maxwidth 130 + +--modifierorder +--nevertrailing +--nilinit remove +--noncomplexattrs +--nospaceoperators ...,..<,/ +--nowrapoperators +--octalgrouping none +--onelineforeach ignore +--operatorfunc spaced +--organizationmode visibility +--organizetypes actor,class,enum,struct +--patternlet inline +--ranges spaced +--redundanttype infer-locals-only +--self remove +--selfrequired +--semicolons never +--shortoptionals except-properties +--smarttabs enabled +--someany true +--storedvarattrs preserve +--stripunusedargs closure-only +--structthreshold 0 +--tabwidth unspecified +--throwcapturing +--timezone system +--trailingclosures +--trimwhitespace always +--typeattributes preserve +--typeblanklines remove +--typedelimiter space-after +--typemark "MARK: - %t" +--voidtype void +--wraparguments preserve +--wrapcollections preserve +--wrapconditions preserve +--wrapeffects preserve +--wrapenumcases always +--wrapparameters default +--wrapreturntype preserve +--wrapternary default +--wraptypealiases preserve +--xcodeindentation disabled +--yodaswap always +--rules blankLinesAroundMark +--rules isEmpty +# Replace consecutive blank lines with a single blank line. +--rules consecutiveBlankLines + +# Replace consecutive spaces with a single space. +--rules consecutiveSpaces +--rules spaceAroundOperators +--operatorfunc spaced + +# Add or remove space around parentheses. +--rules spaceAroundParens +--rules spaceInsideParens + +# Mark unused function arguments with _. +--rules unusedArguments +--stripunusedargs closure-only \ No newline at end of file diff --git a/.trunk/configs/.swiftlint.yml b/.trunk/configs/.swiftlint.yml new file mode 100644 index 000000000..76bf40806 --- /dev/null +++ b/.trunk/configs/.swiftlint.yml @@ -0,0 +1,22 @@ +disabled_rules: # rule identifiers to exclude from running + - identifier_name + - force_cast + - weak_delegate + - function_parameter_count + - file_length + - type_body_length + - cyclomatic_complexity + - function_body_length + +line_length: + warning: 130 + error: 160 + ignores_comments: true + ignores_urls: true + +type_name: + min_length: 1 + max_length: 40 + +excluded: # paths to ignore during linting. Takes precedence over `included`. + - UnitTests diff --git a/.trunk/configs/.yamllint.yaml b/.trunk/configs/.yamllint.yaml new file mode 100644 index 000000000..184e251f8 --- /dev/null +++ b/.trunk/configs/.yamllint.yaml @@ -0,0 +1,7 @@ +rules: + quoted-strings: + required: only-when-needed + extra-allowed: ["{|}"] + key-duplicates: {} + octal-values: + forbid-implicit-octal: true diff --git a/.trunk/configs/ruff.toml b/.trunk/configs/ruff.toml new file mode 100644 index 000000000..f5a235cf9 --- /dev/null +++ b/.trunk/configs/ruff.toml @@ -0,0 +1,5 @@ +# Generic, formatter-friendly config. +select = ["B", "D3", "E", "F"] + +# Never enforce `E501` (line length violations). This should be handled by formatters. +ignore = ["E501"] diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml new file mode 100644 index 000000000..bfc58669e --- /dev/null +++ b/.trunk/trunk.yaml @@ -0,0 +1,54 @@ +# This file controls the behavior of Trunk: https://docs.trunk.io/cli +# To learn more about the format of this file, see https://docs.trunk.io/reference/trunk-yaml +version: 0.1 +cli: + version: 1.25.0 + sha256: + darwin_arm64: 2cff4f1cc63916db290359a058b88167beeac07a496682d9307a1804b498f225 + darwin_x86_64: d0153b87a7eba4cd7d09a048b97bd60ac3ac15352def2bc3599d548875823ed3 + linux_arm64: cc210d2185cf95bedbec06384be6ef342bdb7dcf3ff72dd08fe0e69859516887 + linux_x86_64: 3845ff76a70cebb10e61a267ff719ffdccfa3ef6d877d51870a2c62b79603ab9 + mingw_x86_64: 739f6aabc91d9ba4bce894314e01ab56d2c11b573c921b6f8caed6393c66c5f1 + windows_x86_64: d883930b487d12a47e2c42fb83391417db4c4254c7346720c11e6a947c305a2c +# Trunk provides extensibility via plugins. (https://docs.trunk.io/plugins) +plugins: + sources: + - id: trunk + ref: v1.7.2 + uri: https://github.com/trunk-io/plugins +# Many linters and tools depend on runtimes - configure them here. (https://docs.trunk.io/runtimes) +runtimes: + enabled: + - go@1.21.0 + - node@22.16.0 + - python@3.10.8 +# This is the section where you manage your linters. (https://docs.trunk.io/check/configuration) +lint: + enabled: + - actionlint@1.7.7 # Validates GitHub Actions workflows for syntax and logic errors + - git-diff-check # Ensures only allowed changes are staged (enforces diff-based policies) + - markdownlint@0.45.0 # Checks Markdown files for style consistency and common issues + - osv-scanner@2.2.2 # Scans dependencies for known vulnerabilities using OSV database + - prettier@3.6.2 # Formatter for JavaScript, TypeScript, JSON, CSS, Markdown, etc. + - shellcheck@0.11.0 # Detects bugs and best-practice issues in shell scripts + - shfmt@3.6.0 # Formats shell scripts for consistent style + - trufflehog@3.90.8 # Scans code and git history for secrets (API keys, passwords, etc.) + - swiftlint@0.58.2 # Lints Swift code against style & convention rules + - swiftformat@0.55.5 # Automatically formats Swift code to follow style guidelines + disabled: + - yamllint + ignore: + - linters: [ALL] + paths: + - Example/Pods + - Example/Podfile.lock + - RNExample/Gemfile.lock + - RNExample/Gemfile + +actions: + enabled: + - trunk-announce + - trunk-check-pre-push + - trunk-check-pre-push-always + - trunk-fmt-pre-commit + - trunk-upgrade-available diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index cba35ea12..0b3931205 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -1,5 +1,9 @@ # Architecture + ## mParticle Initialization Sequence Diagram + ![mParticle Initialization Sequence Diagram](.github/mParticle-Initialization-Sequence-Diagram.png?raw=true) + ## mParticle Event Flow Diagram + ![mParticle Event Flow](.github/mParticle-Event-Flow.png?raw=true) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c0e0f7a2..41bf3a632 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,596 +1,513 @@ # [8.39.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.38.0...v8.39.0) (2025-09-18) - ### Bug Fixes -* Update Hashed Email Logic With Unassigned ([#401](https://github.com/mParticle/mparticle-apple-sdk/issues/401)) ([c50b101](https://github.com/mParticle/mparticle-apple-sdk/commit/c50b101de6d7d4f66ea7708fb435607399b61c71)) - +- Update Hashed Email Logic With Unassigned ([#401](https://github.com/mParticle/mparticle-apple-sdk/issues/401)) ([c50b101](https://github.com/mParticle/mparticle-apple-sdk/commit/c50b101de6d7d4f66ea7708fb435607399b61c71)) ### Features -* SDKE-119 Create protocols for testability ([#402](https://github.com/mParticle/mparticle-apple-sdk/issues/402)) ([12b636e](https://github.com/mParticle/mparticle-apple-sdk/commit/12b636ee1e777c2de323f2f1ed071af64b1f9a20)) -* SDKE-119 Create protocols for testability. Part 2 ([#403](https://github.com/mParticle/mparticle-apple-sdk/issues/403)) ([6401e0c](https://github.com/mParticle/mparticle-apple-sdk/commit/6401e0ce5d90a645b2b5b21d03bb8952d9634477)) -* SDKE-119 Create protocols for testability. Part 3 ([#404](https://github.com/mParticle/mparticle-apple-sdk/issues/404)) ([9032458](https://github.com/mParticle/mparticle-apple-sdk/commit/90324581718d148c757fc8166b23f28bd8be08a3)) -* SDKE-61 Extract and test callback logic. Part 1 ([#395](https://github.com/mParticle/mparticle-apple-sdk/issues/395)) ([c3a7da9](https://github.com/mParticle/mparticle-apple-sdk/commit/c3a7da9aa5020051e18026572f893b50022d3809)) -* SDKE-61 Extract and test callback logic. Part 2 ([#396](https://github.com/mParticle/mparticle-apple-sdk/issues/396)) ([2fb2490](https://github.com/mParticle/mparticle-apple-sdk/commit/2fb2490d0c2b0021d3277ab56b60f46d5b134771)) -* SDKE-61 Extract and test callback logic. Part 3 ([#397](https://github.com/mParticle/mparticle-apple-sdk/issues/397)) ([b6cd236](https://github.com/mParticle/mparticle-apple-sdk/commit/b6cd236a729f96d94b20e60e661c00846131e434)) -* SDKE-61 Extract and test callback logic. Part 4 ([#398](https://github.com/mParticle/mparticle-apple-sdk/issues/398)) ([3cf3c88](https://github.com/mParticle/mparticle-apple-sdk/commit/3cf3c881fed67467854117f2b742e3dac241ad4c)) -* SDKE-62 Refactor MPListenerController for Testability ([#400](https://github.com/mParticle/mparticle-apple-sdk/issues/400)) ([cc843a5](https://github.com/mParticle/mparticle-apple-sdk/commit/cc843a5e87c92a9d5660ec585a0d196df8c70295)) -* SDKE-63-replace-logging-macros-with-swift-helpers ([#405](https://github.com/mParticle/mparticle-apple-sdk/issues/405)) ([0ca4964](https://github.com/mParticle/mparticle-apple-sdk/commit/0ca49647884abef0268666d926d35bc4866e8831)) -* SDKE-64 Improve mParticle.m test coverage in swift ([#406](https://github.com/mParticle/mparticle-apple-sdk/issues/406)) ([d4ef623](https://github.com/mParticle/mparticle-apple-sdk/commit/d4ef62322d4749f716ad0ebf38014b59e87244f3)) -* SDKE-64 Improve mParticle.m test coverage in swift 2 ([#407](https://github.com/mParticle/mparticle-apple-sdk/issues/407)) ([b8d67ec](https://github.com/mParticle/mparticle-apple-sdk/commit/b8d67ec49dd2394a8991df04f76a590ff98d4f24)) -* SDKE-64 Improve mParticle.m test coverage in swift 3 ([#410](https://github.com/mParticle/mparticle-apple-sdk/issues/410)) ([72a111c](https://github.com/mParticle/mparticle-apple-sdk/commit/72a111c0f6d00f6d10cf5724f2164a6a5db07111)) +- SDKE-119 Create protocols for testability ([#402](https://github.com/mParticle/mparticle-apple-sdk/issues/402)) ([12b636e](https://github.com/mParticle/mparticle-apple-sdk/commit/12b636ee1e777c2de323f2f1ed071af64b1f9a20)) +- SDKE-119 Create protocols for testability. Part 2 ([#403](https://github.com/mParticle/mparticle-apple-sdk/issues/403)) ([6401e0c](https://github.com/mParticle/mparticle-apple-sdk/commit/6401e0ce5d90a645b2b5b21d03bb8952d9634477)) +- SDKE-119 Create protocols for testability. Part 3 ([#404](https://github.com/mParticle/mparticle-apple-sdk/issues/404)) ([9032458](https://github.com/mParticle/mparticle-apple-sdk/commit/90324581718d148c757fc8166b23f28bd8be08a3)) +- SDKE-61 Extract and test callback logic. Part 1 ([#395](https://github.com/mParticle/mparticle-apple-sdk/issues/395)) ([c3a7da9](https://github.com/mParticle/mparticle-apple-sdk/commit/c3a7da9aa5020051e18026572f893b50022d3809)) +- SDKE-61 Extract and test callback logic. Part 2 ([#396](https://github.com/mParticle/mparticle-apple-sdk/issues/396)) ([2fb2490](https://github.com/mParticle/mparticle-apple-sdk/commit/2fb2490d0c2b0021d3277ab56b60f46d5b134771)) +- SDKE-61 Extract and test callback logic. Part 3 ([#397](https://github.com/mParticle/mparticle-apple-sdk/issues/397)) ([b6cd236](https://github.com/mParticle/mparticle-apple-sdk/commit/b6cd236a729f96d94b20e60e661c00846131e434)) +- SDKE-61 Extract and test callback logic. Part 4 ([#398](https://github.com/mParticle/mparticle-apple-sdk/issues/398)) ([3cf3c88](https://github.com/mParticle/mparticle-apple-sdk/commit/3cf3c881fed67467854117f2b742e3dac241ad4c)) +- SDKE-62 Refactor MPListenerController for Testability ([#400](https://github.com/mParticle/mparticle-apple-sdk/issues/400)) ([cc843a5](https://github.com/mParticle/mparticle-apple-sdk/commit/cc843a5e87c92a9d5660ec585a0d196df8c70295)) +- SDKE-63-replace-logging-macros-with-swift-helpers ([#405](https://github.com/mParticle/mparticle-apple-sdk/issues/405)) ([0ca4964](https://github.com/mParticle/mparticle-apple-sdk/commit/0ca49647884abef0268666d926d35bc4866e8831)) +- SDKE-64 Improve mParticle.m test coverage in swift ([#406](https://github.com/mParticle/mparticle-apple-sdk/issues/406)) ([d4ef623](https://github.com/mParticle/mparticle-apple-sdk/commit/d4ef62322d4749f716ad0ebf38014b59e87244f3)) +- SDKE-64 Improve mParticle.m test coverage in swift 2 ([#407](https://github.com/mParticle/mparticle-apple-sdk/issues/407)) ([b8d67ec](https://github.com/mParticle/mparticle-apple-sdk/commit/b8d67ec49dd2394a8991df04f76a590ff98d4f24)) +- SDKE-64 Improve mParticle.m test coverage in swift 3 ([#410](https://github.com/mParticle/mparticle-apple-sdk/issues/410)) ([72a111c](https://github.com/mParticle/mparticle-apple-sdk/commit/72a111c0f6d00f6d10cf5724f2164a6a5db07111)) # [8.38.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.37.1...v8.38.0) (2025-08-20) - ### Features -* Decouple MParticle.m for Swift Migration ([#393](https://github.com/mParticle/mparticle-apple-sdk/issues/393)) ([23f5434](https://github.com/mParticle/mparticle-apple-sdk/commit/23f543485132ee4c280d18060a9688629f458b59)) -* Map Selected Identity to Emailsha256 ([#391](https://github.com/mParticle/mparticle-apple-sdk/issues/391)) ([a14544b](https://github.com/mParticle/mparticle-apple-sdk/commit/a14544b0a711b0fb4df9d76a0cdc914b1a63c265)) +- Decouple MParticle.m for Swift Migration ([#393](https://github.com/mParticle/mparticle-apple-sdk/issues/393)) ([23f5434](https://github.com/mParticle/mparticle-apple-sdk/commit/23f543485132ee4c280d18060a9688629f458b59)) +- Map Selected Identity to Emailsha256 ([#391](https://github.com/mParticle/mparticle-apple-sdk/issues/391)) ([a14544b](https://github.com/mParticle/mparticle-apple-sdk/commit/a14544b0a711b0fb4df9d76a0cdc914b1a63c265)) ## [8.37.1](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.37.0...v8.37.1) (2025-08-08) - ### Bug Fixes -* Prevent Swift Name Spacing for Encodable Objects ([#385](https://github.com/mParticle/mparticle-apple-sdk/issues/385)) ([b83480e](https://github.com/mParticle/mparticle-apple-sdk/commit/b83480ea3721a9970fd3713c83701776df8a3386)) +- Prevent Swift Name Spacing for Encodable Objects ([#385](https://github.com/mParticle/mparticle-apple-sdk/issues/385)) ([b83480e](https://github.com/mParticle/mparticle-apple-sdk/commit/b83480ea3721a9970fd3713c83701776df8a3386)) # [8.37.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.36.0...v8.37.0) (2025-08-04) - ### Bug Fixes -* Make documentation generation non-blocking for releases ([1dc0c66](https://github.com/mParticle/mparticle-apple-sdk/commit/1dc0c666df8e55ca04f621bd2c09c76e84fd487d)) - +- Make documentation generation non-blocking for releases ([1dc0c66](https://github.com/mParticle/mparticle-apple-sdk/commit/1dc0c666df8e55ca04f621bd2c09c76e84fd487d)) ### Features -* Handle Hashed Email for Rokt ([#383](https://github.com/mParticle/mparticle-apple-sdk/issues/383)) ([3b9e072](https://github.com/mParticle/mparticle-apple-sdk/commit/3b9e0727fcfd9843928ec6a2e6396d9ead1af8e7)) -* Update Hashed Email for Rokt ([#384](https://github.com/mParticle/mparticle-apple-sdk/issues/384)) ([475e5d4](https://github.com/mParticle/mparticle-apple-sdk/commit/475e5d442471e2b287e98c6effb3d14fbc6e5ed0)) +- Handle Hashed Email for Rokt ([#383](https://github.com/mParticle/mparticle-apple-sdk/issues/383)) ([3b9e072](https://github.com/mParticle/mparticle-apple-sdk/commit/3b9e0727fcfd9843928ec6a2e6396d9ead1af8e7)) +- Update Hashed Email for Rokt ([#384](https://github.com/mParticle/mparticle-apple-sdk/issues/384)) ([475e5d4](https://github.com/mParticle/mparticle-apple-sdk/commit/475e5d442471e2b287e98c6effb3d14fbc6e5ed0)) # [8.36.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.35.0...v8.36.0) (2025-07-25) - ### Bug Fixes -* Prevent Apple Caused xCode crash on Launch ([#372](https://github.com/mParticle/mparticle-apple-sdk/issues/372)) ([4c5b001](https://github.com/mParticle/mparticle-apple-sdk/commit/4c5b001cc6b8aed2831e1f7938d655a98a75a94e)) -* Update Bundle ID for No Location ([#381](https://github.com/mParticle/mparticle-apple-sdk/issues/381)) ([4474537](https://github.com/mParticle/mparticle-apple-sdk/commit/44745374c2e4601532115f500b73be741af4490a)) - +- Prevent Apple Caused xCode crash on Launch ([#372](https://github.com/mParticle/mparticle-apple-sdk/issues/372)) ([4c5b001](https://github.com/mParticle/mparticle-apple-sdk/commit/4c5b001cc6b8aed2831e1f7938d655a98a75a94e)) +- Update Bundle ID for No Location ([#381](https://github.com/mParticle/mparticle-apple-sdk/issues/381)) ([4474537](https://github.com/mParticle/mparticle-apple-sdk/commit/44745374c2e4601532115f500b73be741af4490a)) ### Features -* Create Rokt.close method ([#373](https://github.com/mParticle/mparticle-apple-sdk/issues/373)) ([cdc45bb](https://github.com/mParticle/mparticle-apple-sdk/commit/cdc45bb8b7d031902b446d5e9f480e08df0309bd)) +- Create Rokt.close method ([#373](https://github.com/mParticle/mparticle-apple-sdk/issues/373)) ([cdc45bb](https://github.com/mParticle/mparticle-apple-sdk/commit/cdc45bb8b7d031902b446d5e9f480e08df0309bd)) # [8.35.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.34.1...v8.35.0) (2025-06-20) - ### Features -* SQDSDKS-7421 - Add MPRoktEvent class ([#369](https://github.com/mParticle/mparticle-apple-sdk/issues/369)) ([4a23378](https://github.com/mParticle/mparticle-apple-sdk/commit/4a23378339f36cb9be06d1d8b8f5e176d9c5be4a)) +- SQDSDKS-7421 - Add MPRoktEvent class ([#369](https://github.com/mParticle/mparticle-apple-sdk/issues/369)) ([4a23378](https://github.com/mParticle/mparticle-apple-sdk/commit/4a23378339f36cb9be06d1d8b8f5e176d9c5be4a)) ## [8.34.1](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.34.0...v8.34.1) (2025-06-17) - ### Bug Fixes -* Make selectPlacement Use The Message Queue ([#366](https://github.com/mParticle/mparticle-apple-sdk/issues/366)) ([ce1a284](https://github.com/mParticle/mparticle-apple-sdk/commit/ce1a284c7522e81c095308ec99a1bcd23602340e)) +- Make selectPlacement Use The Message Queue ([#366](https://github.com/mParticle/mparticle-apple-sdk/issues/366)) ([ce1a284](https://github.com/mParticle/mparticle-apple-sdk/commit/ce1a284c7522e81c095308ec99a1bcd23602340e)) # [8.34.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.33.0...v8.34.0) (2025-06-13) - ### Features -* Support setWrapperSDK for Kits ([#364](https://github.com/mParticle/mparticle-apple-sdk/issues/364)) ([dcaad47](https://github.com/mParticle/mparticle-apple-sdk/commit/dcaad47152bc284ed5fc4227b74e384ae9fc8482)) +- Support setWrapperSDK for Kits ([#364](https://github.com/mParticle/mparticle-apple-sdk/issues/364)) ([dcaad47](https://github.com/mParticle/mparticle-apple-sdk/commit/dcaad47152bc284ed5fc4227b74e384ae9fc8482)) # [8.33.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.32.0...v8.33.0) (2025-06-12) - ### Features -* Multiple select placements calls made ([#361](https://github.com/mParticle/mparticle-apple-sdk/issues/361)) ([f8d3ff8](https://github.com/mParticle/mparticle-apple-sdk/commit/f8d3ff865d5606a4c6c198511cfa21c5a04a87b7)) +- Multiple select placements calls made ([#361](https://github.com/mParticle/mparticle-apple-sdk/issues/361)) ([f8d3ff8](https://github.com/mParticle/mparticle-apple-sdk/commit/f8d3ff865d5606a4c6c198511cfa21c5a04a87b7)) # [8.32.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.31.2...v8.32.0) (2025-06-10) - ### Features -* Add MPRoktConfig Support ([#357](https://github.com/mParticle/mparticle-apple-sdk/issues/357)) ([abe04ea](https://github.com/mParticle/mparticle-apple-sdk/commit/abe04ea33dee15a080743f5e464300d76df6606f)) +- Add MPRoktConfig Support ([#357](https://github.com/mParticle/mparticle-apple-sdk/issues/357)) ([abe04ea](https://github.com/mParticle/mparticle-apple-sdk/commit/abe04ea33dee15a080743f5e464300d76df6606f)) ## [8.31.2](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.31.1...v8.31.2) (2025-06-06) - ### Bug Fixes -* Remove alreadySynchedUserIdentities ([#354](https://github.com/mParticle/mparticle-apple-sdk/issues/354)) ([3c9f235](https://github.com/mParticle/mparticle-apple-sdk/commit/3c9f235a2435f9b634aaf3b099f70bc155f40762)) +- Remove alreadySynchedUserIdentities ([#354](https://github.com/mParticle/mparticle-apple-sdk/issues/354)) ([3c9f235](https://github.com/mParticle/mparticle-apple-sdk/commit/3c9f235a2435f9b634aaf3b099f70bc155f40762)) ## [8.31.1](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.31.0...v8.31.1) (2025-06-03) - ### Bug Fixes -* Prevent Issue When NSUserActivity webpageURL is nil ([#356](https://github.com/mParticle/mparticle-apple-sdk/issues/356)) ([4305afa](https://github.com/mParticle/mparticle-apple-sdk/commit/4305afa622b3d9249de19fa1613052b53e0efa9d)) +- Prevent Issue When NSUserActivity webpageURL is nil ([#356](https://github.com/mParticle/mparticle-apple-sdk/issues/356)) ([4305afa](https://github.com/mParticle/mparticle-apple-sdk/commit/4305afa622b3d9249de19fa1613052b53e0efa9d)) # [8.31.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.30.3...v8.31.0) (2025-05-21) - ### Bug Fixes -* MPAppNotificationHandler webpageURL issue ([#353](https://github.com/mParticle/mparticle-apple-sdk/issues/353)) ([bebb504](https://github.com/mParticle/mparticle-apple-sdk/commit/bebb50446b73e16b3910e81457e470cd7ec2fa3a)) - +- MPAppNotificationHandler webpageURL issue ([#353](https://github.com/mParticle/mparticle-apple-sdk/issues/353)) ([bebb504](https://github.com/mParticle/mparticle-apple-sdk/commit/bebb50446b73e16b3910e81457e470cd7ec2fa3a)) ### Features -* Identify if Provided Email in Rokt SelectPlacements ([#351](https://github.com/mParticle/mparticle-apple-sdk/issues/351)) ([a0422bc](https://github.com/mParticle/mparticle-apple-sdk/commit/a0422bc37a64feba040cbe93737efd5c1fd7ed28)) +- Identify if Provided Email in Rokt SelectPlacements ([#351](https://github.com/mParticle/mparticle-apple-sdk/issues/351)) ([a0422bc](https://github.com/mParticle/mparticle-apple-sdk/commit/a0422bc37a64feba040cbe93737efd5c1fd7ed28)) ## [8.30.3](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.30.2...v8.30.3) (2025-05-02) - ### Bug Fixes -* Assign correct IDFV instead of random UUID ([#350](https://github.com/mParticle/mparticle-apple-sdk/issues/350)) ([c18b063](https://github.com/mParticle/mparticle-apple-sdk/commit/c18b0639b494ebcd73a154d97b6430be8dc6c6a8)) +- Assign correct IDFV instead of random UUID ([#350](https://github.com/mParticle/mparticle-apple-sdk/issues/350)) ([c18b063](https://github.com/mParticle/mparticle-apple-sdk/commit/c18b0639b494ebcd73a154d97b6430be8dc6c6a8)) ## [8.30.2](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.30.1...v8.30.2) (2025-04-29) - ### Bug Fixes -* Implement MPRoktEventCallback on Core ([#348](https://github.com/mParticle/mparticle-apple-sdk/issues/348)) ([d5fd11d](https://github.com/mParticle/mparticle-apple-sdk/commit/d5fd11d4de32082e20fc7a76436c444f66126b6f)) +- Implement MPRoktEventCallback on Core ([#348](https://github.com/mParticle/mparticle-apple-sdk/issues/348)) ([d5fd11d](https://github.com/mParticle/mparticle-apple-sdk/commit/d5fd11d4de32082e20fc7a76436c444f66126b6f)) ## [8.30.1](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.30.0...v8.30.1) (2025-04-24) - ### Bug Fixes -* Update placementAttributes to placementAttributesMapping ([#349](https://github.com/mParticle/mparticle-apple-sdk/issues/349)) ([13ec6a2](https://github.com/mParticle/mparticle-apple-sdk/commit/13ec6a2a9758f41d865c6db22d7eba82e37f1584)) +- Update placementAttributes to placementAttributesMapping ([#349](https://github.com/mParticle/mparticle-apple-sdk/issues/349)) ([13ec6a2](https://github.com/mParticle/mparticle-apple-sdk/commit/13ec6a2a9758f41d865c6db22d7eba82e37f1584)) # [8.30.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.29.0...v8.30.0) (2025-04-24) - ### Features -* Add disabledKits option to MParticleOptions ([#347](https://github.com/mParticle/mparticle-apple-sdk/issues/347)) ([f708431](https://github.com/mParticle/mparticle-apple-sdk/commit/f7084317345fc9fdf08b8142bdfa4a5220b0ac8a)) -* Add MPRoktEmbeddedView Class ([#345](https://github.com/mParticle/mparticle-apple-sdk/issues/345)) ([f4fb946](https://github.com/mParticle/mparticle-apple-sdk/commit/f4fb946dec2cc2ac190a3f62493f807df2c05cbb)) -* Add user attribute mapping ([#343](https://github.com/mParticle/mparticle-apple-sdk/issues/343)) ([50ce934](https://github.com/mParticle/mparticle-apple-sdk/commit/50ce934e88f9b30dc0889ef7475a4cb34210acc0)) -* Automatically include sandbox in MPRokt Attributes ([#344](https://github.com/mParticle/mparticle-apple-sdk/issues/344)) ([bdf4280](https://github.com/mParticle/mparticle-apple-sdk/commit/bdf4280cf326f40ce89f9f9ec12840525317add7)) +- Add disabledKits option to MParticleOptions ([#347](https://github.com/mParticle/mparticle-apple-sdk/issues/347)) ([f708431](https://github.com/mParticle/mparticle-apple-sdk/commit/f7084317345fc9fdf08b8142bdfa4a5220b0ac8a)) +- Add MPRoktEmbeddedView Class ([#345](https://github.com/mParticle/mparticle-apple-sdk/issues/345)) ([f4fb946](https://github.com/mParticle/mparticle-apple-sdk/commit/f4fb946dec2cc2ac190a3f62493f807df2c05cbb)) +- Add user attribute mapping ([#343](https://github.com/mParticle/mparticle-apple-sdk/issues/343)) ([50ce934](https://github.com/mParticle/mparticle-apple-sdk/commit/50ce934e88f9b30dc0889ef7475a4cb34210acc0)) +- Automatically include sandbox in MPRokt Attributes ([#344](https://github.com/mParticle/mparticle-apple-sdk/issues/344)) ([bdf4280](https://github.com/mParticle/mparticle-apple-sdk/commit/bdf4280cf326f40ce89f9f9ec12840525317add7)) # [8.29.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.28.1...v8.29.0) (2025-04-02) - ### Features -* Add Rokt First Party Kit Support ([#339](https://github.com/mParticle/mparticle-apple-sdk/issues/339)) ([9bb2e2d](https://github.com/mParticle/mparticle-apple-sdk/commit/9bb2e2de0d9280c25a076298c7c22c571a055e8f)) +- Add Rokt First Party Kit Support ([#339](https://github.com/mParticle/mparticle-apple-sdk/issues/339)) ([9bb2e2d](https://github.com/mParticle/mparticle-apple-sdk/commit/9bb2e2de0d9280c25a076298c7c22c571a055e8f)) ## [8.28.1](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.28.0...v8.28.1) (2025-03-25) - ### Bug Fixes -* Ensure UserDefaults has valid instance of Identity ([#340](https://github.com/mParticle/mparticle-apple-sdk/issues/340)) ([57be42c](https://github.com/mParticle/mparticle-apple-sdk/commit/57be42cb66fc35b5efa11121299d059658d651e8)) +- Ensure UserDefaults has valid instance of Identity ([#340](https://github.com/mParticle/mparticle-apple-sdk/issues/340)) ([57be42c](https://github.com/mParticle/mparticle-apple-sdk/commit/57be42cb66fc35b5efa11121299d059658d651e8)) # [8.28.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.27.5...v8.28.0) (2025-03-19) - ### Bug Fixes -* Issue when setting Identity Attributes to nil ([#336](https://github.com/mParticle/mparticle-apple-sdk/issues/336)) ([9a48cdd](https://github.com/mParticle/mparticle-apple-sdk/commit/9a48cdd8af281236dd527691778b030fbabffaa4)) - +- Issue when setting Identity Attributes to nil ([#336](https://github.com/mParticle/mparticle-apple-sdk/issues/336)) ([9a48cdd](https://github.com/mParticle/mparticle-apple-sdk/commit/9a48cdd8af281236dd527691778b030fbabffaa4)) ### Features -* implement audience logic ([#330](https://github.com/mParticle/mparticle-apple-sdk/issues/330)) ([3b9ad82](https://github.com/mParticle/mparticle-apple-sdk/commit/3b9ad82702193a8db45b5fb2e2d19c5efb24cfdb)) +- implement audience logic ([#330](https://github.com/mParticle/mparticle-apple-sdk/issues/330)) ([3b9ad82](https://github.com/mParticle/mparticle-apple-sdk/commit/3b9ad82702193a8db45b5fb2e2d19c5efb24cfdb)) ## [8.27.5](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.27.4...v8.27.5) (2025-03-06) - ### Bug Fixes -* Address firstInstall Edge Case ([#312](https://github.com/mParticle/mparticle-apple-sdk/issues/312)) ([04f6155](https://github.com/mParticle/mparticle-apple-sdk/commit/04f615571344bf10a85e98cd007daaaf53bd881b)) -* forward original event names to UI for kits with mapped events ([#301](https://github.com/mParticle/mparticle-apple-sdk/issues/301)) ([db286bc](https://github.com/mParticle/mparticle-apple-sdk/commit/db286bc1a1c0fe07aa957ff6fe53b044cb11798f)) +- Address firstInstall Edge Case ([#312](https://github.com/mParticle/mparticle-apple-sdk/issues/312)) ([04f6155](https://github.com/mParticle/mparticle-apple-sdk/commit/04f615571344bf10a85e98cd007daaaf53bd881b)) +- forward original event names to UI for kits with mapped events ([#301](https://github.com/mParticle/mparticle-apple-sdk/issues/301)) ([db286bc](https://github.com/mParticle/mparticle-apple-sdk/commit/db286bc1a1c0fe07aa957ff6fe53b044cb11798f)) ## [8.27.4](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.27.3...v8.27.4) (2024-11-04) - ### Bug Fixes -* Initialize Kits in Background Thread ([#308](https://github.com/mParticle/mparticle-apple-sdk/issues/308)) ([38d3ea7](https://github.com/mParticle/mparticle-apple-sdk/commit/38d3ea7408c7e6535a4f459ecade8881ef5c85e3)) +- Initialize Kits in Background Thread ([#308](https://github.com/mParticle/mparticle-apple-sdk/issues/308)) ([38d3ea7](https://github.com/mParticle/mparticle-apple-sdk/commit/38d3ea7408c7e6535a4f459ecade8881ef5c85e3)) ## [8.27.3](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.27.2...v8.27.3) (2024-10-22) - ### Bug Fixes -* Fix set opt out for kits ([#300](https://github.com/mParticle/mparticle-apple-sdk/issues/300)) ([74f71d8](https://github.com/mParticle/mparticle-apple-sdk/commit/74f71d8202debdc7de13394b0f24683b39618b77)) -* Return type of MPGDPRConsent copy method ([7966fd0](https://github.com/mParticle/mparticle-apple-sdk/commit/7966fd02f18b3338e1f07bb619bf72501a27b2db)) +- Fix set opt out for kits ([#300](https://github.com/mParticle/mparticle-apple-sdk/issues/300)) ([74f71d8](https://github.com/mParticle/mparticle-apple-sdk/commit/74f71d8202debdc7de13394b0f24683b39618b77)) +- Return type of MPGDPRConsent copy method ([7966fd0](https://github.com/mParticle/mparticle-apple-sdk/commit/7966fd02f18b3338e1f07bb619bf72501a27b2db)) ## [8.27.2](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.27.1...v8.27.2) (2024-10-10) - ### Bug Fixes -* Potential crash in MPStateMachine when entering foreground ([#299](https://github.com/mParticle/mparticle-apple-sdk/issues/299)) ([50ba03b](https://github.com/mParticle/mparticle-apple-sdk/commit/50ba03bb97e7f5c1a8a4213f359a00b73bf90f2a)) +- Potential crash in MPStateMachine when entering foreground ([#299](https://github.com/mParticle/mparticle-apple-sdk/issues/299)) ([50ba03b](https://github.com/mParticle/mparticle-apple-sdk/commit/50ba03bb97e7f5c1a8a4213f359a00b73bf90f2a)) ## [8.27.1](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.27.0...v8.27.1) (2024-09-17) - ### Bug Fixes -* Prevent Repeated Sessions on active Background ([#290](https://github.com/mParticle/mparticle-apple-sdk/issues/290)) ([9ead27d](https://github.com/mParticle/mparticle-apple-sdk/commit/9ead27d25cf2f31cbb97f7b26216524b48afdcae)) +- Prevent Repeated Sessions on active Background ([#290](https://github.com/mParticle/mparticle-apple-sdk/issues/290)) ([9ead27d](https://github.com/mParticle/mparticle-apple-sdk/commit/9ead27d25cf2f31cbb97f7b26216524b48afdcae)) # [8.27.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.26.0...v8.27.0) (2024-09-04) - ### Bug Fixes -* Properly attribute events when workspace switches on new launch ([#288](https://github.com/mParticle/mparticle-apple-sdk/issues/288)) ([407749a](https://github.com/mParticle/mparticle-apple-sdk/commit/407749abcb047c97b804592fcc3c5c553792d2f8)) - +- Properly attribute events when workspace switches on new launch ([#288](https://github.com/mParticle/mparticle-apple-sdk/issues/288)) ([407749a](https://github.com/mParticle/mparticle-apple-sdk/commit/407749abcb047c97b804592fcc3c5c553792d2f8)) ### Features -* Workspace switching improvements ([#287](https://github.com/mParticle/mparticle-apple-sdk/issues/287)) ([0c8da18](https://github.com/mParticle/mparticle-apple-sdk/commit/0c8da18dd1faa701186abd6f45820fc6c54fa71f)) +- Workspace switching improvements ([#287](https://github.com/mParticle/mparticle-apple-sdk/issues/287)) ([0c8da18](https://github.com/mParticle/mparticle-apple-sdk/commit/0c8da18dd1faa701186abd6f45820fc6c54fa71f)) # [8.26.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.25.1...v8.26.0) (2024-08-16) - ### Features -* Cert Pinning Update ([#286](https://github.com/mParticle/mparticle-apple-sdk/issues/286)) ([15cf961](https://github.com/mParticle/mparticle-apple-sdk/commit/15cf961cc9b9d4f31b68df3a0d58e8b5c478e5c0)) +- Cert Pinning Update ([#286](https://github.com/mParticle/mparticle-apple-sdk/issues/286)) ([15cf961](https://github.com/mParticle/mparticle-apple-sdk/commit/15cf961cc9b9d4f31b68df3a0d58e8b5c478e5c0)) ## [8.25.1](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.25.0...v8.25.1) (2024-07-29) - ### Bug Fixes -* Rename internal Swift.h header to avoid Expo conflicts ([#283](https://github.com/mParticle/mparticle-apple-sdk/issues/283)) ([36c6be4](https://github.com/mParticle/mparticle-apple-sdk/commit/36c6be4c015d0e4775267dd866d123589f221447)) +- Rename internal Swift.h header to avoid Expo conflicts ([#283](https://github.com/mParticle/mparticle-apple-sdk/issues/283)) ([36c6be4](https://github.com/mParticle/mparticle-apple-sdk/commit/36c6be4c015d0e4775267dd866d123589f221447)) # [8.25.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.24.3...v8.25.0) (2024-06-25) - ### Features -* Add Option to Disable Certificate Pinning ([#282](https://github.com/mParticle/mparticle-apple-sdk/issues/282)) ([3a42719](https://github.com/mParticle/mparticle-apple-sdk/commit/3a42719784330cdc56f3e831c24f90ca8a4c2901)) +- Add Option to Disable Certificate Pinning ([#282](https://github.com/mParticle/mparticle-apple-sdk/issues/282)) ([3a42719](https://github.com/mParticle/mparticle-apple-sdk/commit/3a42719784330cdc56f3e831c24f90ca8a4c2901)) ## [8.24.3](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.24.2...v8.24.3) (2024-06-10) - ### Bug Fixes -* Remove deprecated iAd framework ([#279](https://github.com/mParticle/mparticle-apple-sdk/issues/279)) ([31b283c](https://github.com/mParticle/mparticle-apple-sdk/commit/31b283c4e78a57d72dae195ad16491a510d3a13b)) +- Remove deprecated iAd framework ([#279](https://github.com/mParticle/mparticle-apple-sdk/issues/279)) ([31b283c](https://github.com/mParticle/mparticle-apple-sdk/commit/31b283c4e78a57d72dae195ad16491a510d3a13b)) ## [8.24.2](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.24.1...v8.24.2) (2024-06-10) - ### Bug Fixes -* Record PushRegistration Correctly in UI ([#280](https://github.com/mParticle/mparticle-apple-sdk/issues/280)) ([2d124ec](https://github.com/mParticle/mparticle-apple-sdk/commit/2d124ec089aa8625b8acb1c3360349903c4a6af4)) +- Record PushRegistration Correctly in UI ([#280](https://github.com/mParticle/mparticle-apple-sdk/issues/280)) ([2d124ec](https://github.com/mParticle/mparticle-apple-sdk/commit/2d124ec089aa8625b8acb1c3360349903c4a6af4)) ## [8.24.1](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.24.0...v8.24.1) (2024-05-15) - ### Bug Fixes -* Remove unnecessary badge number functionality ([#277](https://github.com/mParticle/mparticle-apple-sdk/issues/277)) ([266612f](https://github.com/mParticle/mparticle-apple-sdk/commit/266612fc86991a44c90dc97a09ca699dcd30a34f)) +- Remove unnecessary badge number functionality ([#277](https://github.com/mParticle/mparticle-apple-sdk/issues/277)) ([266612f](https://github.com/mParticle/mparticle-apple-sdk/commit/266612fc86991a44c90dc97a09ca699dcd30a34f)) # [8.24.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.23.1...v8.24.0) (2024-05-01) - ### Bug Fixes -* Allow Alias When Start and End Time Not Set ([#275](https://github.com/mParticle/mparticle-apple-sdk/issues/275)) ([241ecd4](https://github.com/mParticle/mparticle-apple-sdk/commit/241ecd4fef6c732f885100844c9ff8a24ffbe842)) - +- Allow Alias When Start and End Time Not Set ([#275](https://github.com/mParticle/mparticle-apple-sdk/issues/275)) ([241ecd4](https://github.com/mParticle/mparticle-apple-sdk/commit/241ecd4fef6c732f885100844c9ff8a24ffbe842)) ### Features -* Add Tracking Support for Custom Domains ([#274](https://github.com/mParticle/mparticle-apple-sdk/issues/274)) ([1584dae](https://github.com/mParticle/mparticle-apple-sdk/commit/1584daed11afabc94f9d6c1e08c1d718e088caee)) +- Add Tracking Support for Custom Domains ([#274](https://github.com/mParticle/mparticle-apple-sdk/issues/274)) ([1584dae](https://github.com/mParticle/mparticle-apple-sdk/commit/1584daed11afabc94f9d6c1e08c1d718e088caee)) ## [8.23.1](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.23.0...v8.23.1) (2024-04-30) - ### Bug Fixes -* Forwarding ATT status to kits ([#276](https://github.com/mParticle/mparticle-apple-sdk/issues/276)) ([9fd95f7](https://github.com/mParticle/mparticle-apple-sdk/commit/9fd95f72a7a88bc1e1ae30d33d261098cd5bc1ee)) +- Forwarding ATT status to kits ([#276](https://github.com/mParticle/mparticle-apple-sdk/issues/276)) ([9fd95f7](https://github.com/mParticle/mparticle-apple-sdk/commit/9fd95f72a7a88bc1e1ae30d33d261098cd5bc1ee)) # [8.23.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.22.0...v8.23.0) (2024-04-24) - ### Features -* Add max persistence age override option ([#273](https://github.com/mParticle/mparticle-apple-sdk/issues/273)) ([241e773](https://github.com/mParticle/mparticle-apple-sdk/commit/241e7734f6b26f617afb1a4aa51af37355f05de9)) +- Add max persistence age override option ([#273](https://github.com/mParticle/mparticle-apple-sdk/issues/273)) ([241e773](https://github.com/mParticle/mparticle-apple-sdk/commit/241e7734f6b26f617afb1a4aa51af37355f05de9)) # [8.22.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.21.1...v8.22.0) (2024-04-19) - ### Features -* Update mParticle-Apple-SDK.podspec for privacy manifest ([#271](https://github.com/mParticle/mparticle-apple-sdk/issues/271)) ([f4a4750](https://github.com/mParticle/mparticle-apple-sdk/commit/f4a4750a1a06766c3f35ef5d8a16c0b0ca4a1e40)) +- Update mParticle-Apple-SDK.podspec for privacy manifest ([#271](https://github.com/mParticle/mparticle-apple-sdk/issues/271)) ([f4a4750](https://github.com/mParticle/mparticle-apple-sdk/commit/f4a4750a1a06766c3f35ef5d8a16c0b0ca4a1e40)) ## [8.21.1](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.21.0...v8.21.1) (2024-04-17) - ### Bug Fixes -* Type hinting MPIdentityApiRequest.identities ([#270](https://github.com/mParticle/mparticle-apple-sdk/issues/270)) ([f56879f](https://github.com/mParticle/mparticle-apple-sdk/commit/f56879f77be87d46f9d44514983c6663451862d0)) +- Type hinting MPIdentityApiRequest.identities ([#270](https://github.com/mParticle/mparticle-apple-sdk/issues/270)) ([f56879f](https://github.com/mParticle/mparticle-apple-sdk/commit/f56879f77be87d46f9d44514983c6663451862d0)) # [8.21.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.20.0...v8.21.0) (2024-03-19) - ### Bug Fixes -* Correct threading around user notification log ([#261](https://github.com/mParticle/mparticle-apple-sdk/issues/261)) ([456160b](https://github.com/mParticle/mparticle-apple-sdk/commit/456160b845c656cc3359425375edb88b7070eac0)) -* Refactor MPUploadBuilder to attempt to eliminate rare crash in withLocation: method ([#262](https://github.com/mParticle/mparticle-apple-sdk/issues/262)) ([60cd0c8](https://github.com/mParticle/mparticle-apple-sdk/commit/60cd0c801e4b9da6a5a1c86efd230797391801ab)) - +- Correct threading around user notification log ([#261](https://github.com/mParticle/mparticle-apple-sdk/issues/261)) ([456160b](https://github.com/mParticle/mparticle-apple-sdk/commit/456160b845c656cc3359425375edb88b7070eac0)) +- Refactor MPUploadBuilder to attempt to eliminate rare crash in withLocation: method ([#262](https://github.com/mParticle/mparticle-apple-sdk/issues/262)) ([60cd0c8](https://github.com/mParticle/mparticle-apple-sdk/commit/60cd0c801e4b9da6a5a1c86efd230797391801ab)) ### Features -* Improve mParticle reset methods ([#263](https://github.com/mParticle/mparticle-apple-sdk/issues/263)) ([cde71a2](https://github.com/mParticle/mparticle-apple-sdk/commit/cde71a273318a64a7a76279dc5e67c6405fcf0e5)) +- Improve mParticle reset methods ([#263](https://github.com/mParticle/mparticle-apple-sdk/issues/263)) ([cde71a2](https://github.com/mParticle/mparticle-apple-sdk/commit/cde71a273318a64a7a76279dc5e67c6405fcf0e5)) # [8.20.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.19.0...v8.20.0) (2024-03-05) - ### Features -* Switch workspaces without restarting app ([#258](https://github.com/mParticle/mparticle-apple-sdk/issues/258)) ([8f0a027](https://github.com/mParticle/mparticle-apple-sdk/commit/8f0a0276a3008b3a848630d125cc41a60addaef9)) +- Switch workspaces without restarting app ([#258](https://github.com/mParticle/mparticle-apple-sdk/issues/258)) ([8f0a027](https://github.com/mParticle/mparticle-apple-sdk/commit/8f0a0276a3008b3a848630d125cc41a60addaef9)) # [8.19.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.18.0...v8.19.0) (2024-02-23) - ### Features -* Add Privacy Manifest and Tracking Domain Logic ([#249](https://github.com/mParticle/mparticle-apple-sdk/issues/249)) ([d88acde](https://github.com/mParticle/mparticle-apple-sdk/commit/d88acdee70daa690374f2359fbc3efed7e46744d)), closes [#248](https://github.com/mParticle/mparticle-apple-sdk/issues/248) -* Add privacy manifest to build artifacts ([#255](https://github.com/mParticle/mparticle-apple-sdk/issues/255)) ([aaeb8e4](https://github.com/mParticle/mparticle-apple-sdk/commit/aaeb8e44ab0aea152ad8704093543289801e7490)) +- Add Privacy Manifest and Tracking Domain Logic ([#249](https://github.com/mParticle/mparticle-apple-sdk/issues/249)) ([d88acde](https://github.com/mParticle/mparticle-apple-sdk/commit/d88acdee70daa690374f2359fbc3efed7e46744d)), closes [#248](https://github.com/mParticle/mparticle-apple-sdk/issues/248) +- Add privacy manifest to build artifacts ([#255](https://github.com/mParticle/mparticle-apple-sdk/issues/255)) ([aaeb8e4](https://github.com/mParticle/mparticle-apple-sdk/commit/aaeb8e44ab0aea152ad8704093543289801e7490)) # [8.18.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.17.0...v8.18.0) (2024-01-16) - ### Bug Fixes -* Rare arithmetic overflow crash in MPIHasher ([#246](https://github.com/mParticle/mparticle-apple-sdk/issues/246)) ([65fad25](https://github.com/mParticle/mparticle-apple-sdk/commit/65fad255cb454e7f90c2c44c49890c709239fced)) - +- Rare arithmetic overflow crash in MPIHasher ([#246](https://github.com/mParticle/mparticle-apple-sdk/issues/246)) ([65fad25](https://github.com/mParticle/mparticle-apple-sdk/commit/65fad255cb454e7f90c2c44c49890c709239fced)) ### Features -* Identity API response caching ([#244](https://github.com/mParticle/mparticle-apple-sdk/issues/244)) ([9eaa0ea](https://github.com/mParticle/mparticle-apple-sdk/commit/9eaa0ea535b61bfb8d50ff447c0cc4fa505239da)) +- Identity API response caching ([#244](https://github.com/mParticle/mparticle-apple-sdk/issues/244)) ([9eaa0ea](https://github.com/mParticle/mparticle-apple-sdk/commit/9eaa0ea535b61bfb8d50ff447c0cc4fa505239da)) # [8.17.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.16.0...v8.17.0) (2023-11-30) - ### Bug Fixes -* CFNetwork upload warning setting body twice ([#240](https://github.com/mParticle/mparticle-apple-sdk/issues/240)) ([0a177f9](https://github.com/mParticle/mparticle-apple-sdk/commit/0a177f960e1b3874e1a7e6709364f2504335ba5f)) - +- CFNetwork upload warning setting body twice ([#240](https://github.com/mParticle/mparticle-apple-sdk/issues/240)) ([0a177f9](https://github.com/mParticle/mparticle-apple-sdk/commit/0a177f960e1b3874e1a7e6709364f2504335ba5f)) ### Features -* 5343 Refactor Kit Filter Hash Functions ([#228](https://github.com/mParticle/mparticle-apple-sdk/issues/228)) ([5c26a9e](https://github.com/mParticle/mparticle-apple-sdk/commit/5c26a9efb4e86b8cc31b9908dc1967a75a07e3db)) -* Begin Implementation MPSideloadedKit Filtering Methods ([#231](https://github.com/mParticle/mparticle-apple-sdk/issues/231)) ([ad543fb](https://github.com/mParticle/mparticle-apple-sdk/commit/ad543fb4875700a8ad6a1b23ad318b17aa6c4533)) -* Finish Implementation of MPSideLoadedKits ([#239](https://github.com/mParticle/mparticle-apple-sdk/issues/239)) ([96e62f5](https://github.com/mParticle/mparticle-apple-sdk/commit/96e62f5763b524dcf6ddfde6037278053fd4707d)) -* Improve background batch uploading and session management ([#238](https://github.com/mParticle/mparticle-apple-sdk/issues/238)) ([dc6a9cb](https://github.com/mParticle/mparticle-apple-sdk/commit/dc6a9cb670144ebffb9cac4c28384fb75ab4e68e)) +- 5343 Refactor Kit Filter Hash Functions ([#228](https://github.com/mParticle/mparticle-apple-sdk/issues/228)) ([5c26a9e](https://github.com/mParticle/mparticle-apple-sdk/commit/5c26a9efb4e86b8cc31b9908dc1967a75a07e3db)) +- Begin Implementation MPSideloadedKit Filtering Methods ([#231](https://github.com/mParticle/mparticle-apple-sdk/issues/231)) ([ad543fb](https://github.com/mParticle/mparticle-apple-sdk/commit/ad543fb4875700a8ad6a1b23ad318b17aa6c4533)) +- Finish Implementation of MPSideLoadedKits ([#239](https://github.com/mParticle/mparticle-apple-sdk/issues/239)) ([96e62f5](https://github.com/mParticle/mparticle-apple-sdk/commit/96e62f5763b524dcf6ddfde6037278053fd4707d)) +- Improve background batch uploading and session management ([#238](https://github.com/mParticle/mparticle-apple-sdk/issues/238)) ([dc6a9cb](https://github.com/mParticle/mparticle-apple-sdk/commit/dc6a9cb670144ebffb9cac4c28384fb75ab4e68e)) # [8.16.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.15.1...v8.16.0) (2023-10-11) - ### Features -* Direct routing to correct pod ([#223](https://github.com/mParticle/mparticle-apple-sdk/issues/223)) ([#229](https://github.com/mParticle/mparticle-apple-sdk/issues/229)) ([#230](https://github.com/mParticle/mparticle-apple-sdk/issues/230)) ([14168f9](https://github.com/mParticle/mparticle-apple-sdk/commit/14168f9167f15f8b850b93ea1004273cf927bd0e)) +- Direct routing to correct pod ([#223](https://github.com/mParticle/mparticle-apple-sdk/issues/223)) ([#229](https://github.com/mParticle/mparticle-apple-sdk/issues/229)) ([#230](https://github.com/mParticle/mparticle-apple-sdk/issues/230)) ([14168f9](https://github.com/mParticle/mparticle-apple-sdk/commit/14168f9167f15f8b850b93ea1004273cf927bd0e)) ## [8.15.1](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.15.0...v8.15.1) (2023-10-04) - ### Bug Fixes -* Push Registration events to show forwarded for kits ([#208](https://github.com/mParticle/mparticle-apple-sdk/issues/208)) ([705e568](https://github.com/mParticle/mparticle-apple-sdk/commit/705e568f68484ab0f41430832f9ed66c42a72395)) +- Push Registration events to show forwarded for kits ([#208](https://github.com/mParticle/mparticle-apple-sdk/issues/208)) ([705e568](https://github.com/mParticle/mparticle-apple-sdk/commit/705e568f68484ab0f41430832f9ed66c42a72395)) # [8.15.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.14.2...v8.15.0) (2023-09-07) - ### Features -* Remove Disk Space API Usage ([#221](https://github.com/mParticle/mparticle-apple-sdk/issues/221)) ([8bdf935](https://github.com/mParticle/mparticle-apple-sdk/commit/8bdf9351ff53847f54192e7d5182ea77b5ceb0c8)) +- Remove Disk Space API Usage ([#221](https://github.com/mParticle/mparticle-apple-sdk/issues/221)) ([8bdf935](https://github.com/mParticle/mparticle-apple-sdk/commit/8bdf9351ff53847f54192e7d5182ea77b5ceb0c8)) ## [8.14.2](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.14.1...v8.14.2) (2023-07-31) - ### Bug Fixes -* Update imports for react native compatibility ([#212](https://github.com/mParticle/mparticle-apple-sdk/issues/212)) ([c22e2f1](https://github.com/mParticle/mparticle-apple-sdk/commit/c22e2f12d87ae826697bffdbbbfa176e69219afa)) +- Update imports for react native compatibility ([#212](https://github.com/mParticle/mparticle-apple-sdk/issues/212)) ([c22e2f1](https://github.com/mParticle/mparticle-apple-sdk/commit/c22e2f12d87ae826697bffdbbbfa176e69219afa)) ## [8.14.1](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.14.0...v8.14.1) (2023-07-06) - ### Bug Fixes -* crash in userIdentitiesForUserId with multiple invalid identity types ([#205](https://github.com/mParticle/mparticle-apple-sdk/issues/205)) ([9d88bcc](https://github.com/mParticle/mparticle-apple-sdk/commit/9d88bcc89cd0cb2cd8b1c58e0544c3204fe31457)) +- crash in userIdentitiesForUserId with multiple invalid identity types ([#205](https://github.com/mParticle/mparticle-apple-sdk/issues/205)) ([9d88bcc](https://github.com/mParticle/mparticle-apple-sdk/commit/9d88bcc89cd0cb2cd8b1c58e0544c3204fe31457)) # [8.14.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.13.0...v8.14.0) (2023-06-27) - ### Bug Fixes -* Prevent Unplanned User Identities ([#190](https://github.com/mParticle/mparticle-apple-sdk/issues/190)) ([f870b20](https://github.com/mParticle/mparticle-apple-sdk/commit/f870b2075ba587827a3fc0e4b0e0602f869ea83d)) - +- Prevent Unplanned User Identities ([#190](https://github.com/mParticle/mparticle-apple-sdk/issues/190)) ([f870b20](https://github.com/mParticle/mparticle-apple-sdk/commit/f870b2075ba587827a3fc0e4b0e0602f869ea83d)) ### Features -* Add Sideloaded Kit Filtering Support to API ([#202](https://github.com/mParticle/mparticle-apple-sdk/issues/202)) ([6f0339c](https://github.com/mParticle/mparticle-apple-sdk/commit/6f0339cceb1afd25732e9538d0039a6935dd7e7b)) -* Add Sideloaded Kit flag to Batches ([#200](https://github.com/mParticle/mparticle-apple-sdk/issues/200)) ([6756d8a](https://github.com/mParticle/mparticle-apple-sdk/commit/6756d8a8dd3be806b556a026a725bbfc9c13f87e)) -* Upload build artifacts to S3 for SPM ([#199](https://github.com/mParticle/mparticle-apple-sdk/issues/199)) ([923838a](https://github.com/mParticle/mparticle-apple-sdk/commit/923838a4abbaced4da2ae1e868f2babb26366c6d)) +- Add Sideloaded Kit Filtering Support to API ([#202](https://github.com/mParticle/mparticle-apple-sdk/issues/202)) ([6f0339c](https://github.com/mParticle/mparticle-apple-sdk/commit/6f0339cceb1afd25732e9538d0039a6935dd7e7b)) +- Add Sideloaded Kit flag to Batches ([#200](https://github.com/mParticle/mparticle-apple-sdk/issues/200)) ([6756d8a](https://github.com/mParticle/mparticle-apple-sdk/commit/6756d8a8dd3be806b556a026a725bbfc9c13f87e)) +- Upload build artifacts to S3 for SPM ([#199](https://github.com/mParticle/mparticle-apple-sdk/issues/199)) ([923838a](https://github.com/mParticle/mparticle-apple-sdk/commit/923838a4abbaced4da2ae1e868f2babb26366c6d)) # [8.13.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.12.0...v8.13.0) (2023-04-24) - ### Features -* Port first Obj-C file to Swift ([#186](https://github.com/mParticle/mparticle-apple-sdk/issues/186)) ([18b1e1c](https://github.com/mParticle/mparticle-apple-sdk/commit/18b1e1cb027c2624387aa7056196d2fe28e8d034)) -* Use Apple Search Ads for Attribution ([#187](https://github.com/mParticle/mparticle-apple-sdk/issues/187)) ([e2bb3bc](https://github.com/mParticle/mparticle-apple-sdk/commit/e2bb3bcf14b1fc30a6323848b4576246cecb8261)) -* Use SPM binary targets and update release scripts ([#188](https://github.com/mParticle/mparticle-apple-sdk/issues/188)) ([e482df0](https://github.com/mParticle/mparticle-apple-sdk/commit/e482df0c9496d47e73276655afd72a4f483b2d66)) +- Port first Obj-C file to Swift ([#186](https://github.com/mParticle/mparticle-apple-sdk/issues/186)) ([18b1e1c](https://github.com/mParticle/mparticle-apple-sdk/commit/18b1e1cb027c2624387aa7056196d2fe28e8d034)) +- Use Apple Search Ads for Attribution ([#187](https://github.com/mParticle/mparticle-apple-sdk/issues/187)) ([e2bb3bc](https://github.com/mParticle/mparticle-apple-sdk/commit/e2bb3bcf14b1fc30a6323848b4576246cecb8261)) +- Use SPM binary targets and update release scripts ([#188](https://github.com/mParticle/mparticle-apple-sdk/issues/188)) ([e482df0](https://github.com/mParticle/mparticle-apple-sdk/commit/e482df0c9496d47e73276655afd72a4f483b2d66)) # [8.12.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.11.2...v8.12.0) (2023-03-14) - ### Bug Fixes -* Limit Currency Values to 2 Decimal Points ([#183](https://github.com/mParticle/mparticle-apple-sdk/issues/183)) ([de70c03](https://github.com/mParticle/mparticle-apple-sdk/commit/de70c03fb6127795f0190ee3c4307bbe2f63dedc)) - +- Limit Currency Values to 2 Decimal Points ([#183](https://github.com/mParticle/mparticle-apple-sdk/issues/183)) ([de70c03](https://github.com/mParticle/mparticle-apple-sdk/commit/de70c03fb6127795f0190ee3c4307bbe2f63dedc)) ### Features -* Custom local kit loading aka kit sideloading ([#185](https://github.com/mParticle/mparticle-apple-sdk/issues/185)) ([a279cb0](https://github.com/mParticle/mparticle-apple-sdk/commit/a279cb0389242b1823a953bd2b4911c51e76c1b4)) +- Custom local kit loading aka kit sideloading ([#185](https://github.com/mParticle/mparticle-apple-sdk/issues/185)) ([a279cb0](https://github.com/mParticle/mparticle-apple-sdk/commit/a279cb0389242b1823a953bd2b4911c51e76c1b4)) ## [8.11.2](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.11.1...v8.11.2) (2023-02-10) - ### Bug Fixes -* Add missing MPIdentityErrorResponseCode values ([#181](https://github.com/mParticle/mparticle-apple-sdk/issues/181)) ([7afd66a](https://github.com/mParticle/mparticle-apple-sdk/commit/7afd66a13033407a83dac0c206ab4ec622e9fdf5)) -* Add missing no location target for SPM ([#182](https://github.com/mParticle/mparticle-apple-sdk/issues/182)) ([d265e8a](https://github.com/mParticle/mparticle-apple-sdk/commit/d265e8addb1798480202779df2af093d250fa3cd)) +- Add missing MPIdentityErrorResponseCode values ([#181](https://github.com/mParticle/mparticle-apple-sdk/issues/181)) ([7afd66a](https://github.com/mParticle/mparticle-apple-sdk/commit/7afd66a13033407a83dac0c206ab4ec622e9fdf5)) +- Add missing no location target for SPM ([#182](https://github.com/mParticle/mparticle-apple-sdk/issues/182)) ([d265e8a](https://github.com/mParticle/mparticle-apple-sdk/commit/d265e8addb1798480202779df2af093d250fa3cd)) ## [8.11.1](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.11.0...v8.11.1) (2023-02-07) - ### Bug Fixes -* Disable All Location Code with Flag ([#180](https://github.com/mParticle/mparticle-apple-sdk/issues/180)) ([3c28771](https://github.com/mParticle/mparticle-apple-sdk/commit/3c28771451c38777f8ac8d6e90c4c1511f013e56)) +- Disable All Location Code with Flag ([#180](https://github.com/mParticle/mparticle-apple-sdk/issues/180)) ([3c28771](https://github.com/mParticle/mparticle-apple-sdk/commit/3c28771451c38777f8ac8d6e90c4c1511f013e56)) # [8.11.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.10.0...v8.11.0) (2023-01-23) - ### Bug Fixes -* Identify API call using CNAME domain ([#179](https://github.com/mParticle/mparticle-apple-sdk/issues/179)) ([0aae9af](https://github.com/mParticle/mparticle-apple-sdk/commit/0aae9af3ca49b21d9f50197114a26820105e4ec9)) - +- Identify API call using CNAME domain ([#179](https://github.com/mParticle/mparticle-apple-sdk/issues/179)) ([0aae9af](https://github.com/mParticle/mparticle-apple-sdk/commit/0aae9af3ca49b21d9f50197114a26820105e4ec9)) ### Features -* Block writes on invalid API key based on Identity/Config responses ([#176](https://github.com/mParticle/mparticle-apple-sdk/issues/176)) ([d116872](https://github.com/mParticle/mparticle-apple-sdk/commit/d1168722da6363d5a6c41fe0fa26d27b816b98e9)) +- Block writes on invalid API key based on Identity/Config responses ([#176](https://github.com/mParticle/mparticle-apple-sdk/issues/176)) ([d116872](https://github.com/mParticle/mparticle-apple-sdk/commit/d1168722da6363d5a6c41fe0fa26d27b816b98e9)) # [8.10.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.9.2...v8.10.0) (2023-01-10) - ### Features -* Add wrapper sdk info setter ([#174](https://github.com/mParticle/mparticle-apple-sdk/issues/174)) ([c2ca247](https://github.com/mParticle/mparticle-apple-sdk/commit/c2ca2476ea96c9636b6684e6a3a57df44d37a0a1)) -* Allow uploadInterval to be set manually ([#175](https://github.com/mParticle/mparticle-apple-sdk/issues/175)) ([8d2c5cf](https://github.com/mParticle/mparticle-apple-sdk/commit/8d2c5cfdf701dfcec4494535714e9d3b8faaedf3)) +- Add wrapper sdk info setter ([#174](https://github.com/mParticle/mparticle-apple-sdk/issues/174)) ([c2ca247](https://github.com/mParticle/mparticle-apple-sdk/commit/c2ca2476ea96c9636b6684e6a3a57df44d37a0a1)) +- Allow uploadInterval to be set manually ([#175](https://github.com/mParticle/mparticle-apple-sdk/issues/175)) ([8d2c5cf](https://github.com/mParticle/mparticle-apple-sdk/commit/8d2c5cfdf701dfcec4494535714e9d3b8faaedf3)) ## [8.9.2](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.9.1...v8.9.2) (2022-12-06) - ### Bug Fixes -* Roll back min deployment target to iOS/tvOS 9 ([#172](https://github.com/mParticle/mparticle-apple-sdk/issues/172)) ([dd32132](https://github.com/mParticle/mparticle-apple-sdk/commit/dd321329c7b460a3d92873ea8292dcba60fbb84b)) +- Roll back min deployment target to iOS/tvOS 9 ([#172](https://github.com/mParticle/mparticle-apple-sdk/issues/172)) ([dd32132](https://github.com/mParticle/mparticle-apple-sdk/commit/dd321329c7b460a3d92873ea8292dcba60fbb84b)) # [8.9.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.8.1...v8.9.0) (2022-11-30) - ### Bug Fixes -* Add class checks to initialize methods ([#165](https://github.com/mParticle/mparticle-apple-sdk/issues/165)) ([065df46](https://github.com/mParticle/mparticle-apple-sdk/commit/065df46394ccc21f1fbd2ed23d0d0c33b910f307)) -* Add Hash Methods where isEqual called ([#167](https://github.com/mParticle/mparticle-apple-sdk/issues/167)) ([7302e0d](https://github.com/mParticle/mparticle-apple-sdk/commit/7302e0dd79012e120c90e0ce78a84ffac7b781d5)) -* Allow null event attributes ([#163](https://github.com/mParticle/mparticle-apple-sdk/issues/163)) ([5fd25c6](https://github.com/mParticle/mparticle-apple-sdk/commit/5fd25c6ecd1e291452728748399d722d9d1e61f0)) -* Move dyld register callback to initialize ([#170](https://github.com/mParticle/mparticle-apple-sdk/issues/170)) ([49d3660](https://github.com/mParticle/mparticle-apple-sdk/commit/49d36609e0873b3957846a9153eab936da684098)) -* Remove unnecessary calls to removeObserver ([#168](https://github.com/mParticle/mparticle-apple-sdk/issues/168)) ([a288ba4](https://github.com/mParticle/mparticle-apple-sdk/commit/a288ba469da18690381d0a098c1a2734031b7cc6)) -* Remove Unnecessary Synchronize in Dealloc ([#169](https://github.com/mParticle/mparticle-apple-sdk/issues/169)) ([624891b](https://github.com/mParticle/mparticle-apple-sdk/commit/624891bc5771a1a92f24ef88b669eb06a2acf1c2)) - +- Add class checks to initialize methods ([#165](https://github.com/mParticle/mparticle-apple-sdk/issues/165)) ([065df46](https://github.com/mParticle/mparticle-apple-sdk/commit/065df46394ccc21f1fbd2ed23d0d0c33b910f307)) +- Add Hash Methods where isEqual called ([#167](https://github.com/mParticle/mparticle-apple-sdk/issues/167)) ([7302e0d](https://github.com/mParticle/mparticle-apple-sdk/commit/7302e0dd79012e120c90e0ce78a84ffac7b781d5)) +- Allow null event attributes ([#163](https://github.com/mParticle/mparticle-apple-sdk/issues/163)) ([5fd25c6](https://github.com/mParticle/mparticle-apple-sdk/commit/5fd25c6ecd1e291452728748399d722d9d1e61f0)) +- Move dyld register callback to initialize ([#170](https://github.com/mParticle/mparticle-apple-sdk/issues/170)) ([49d3660](https://github.com/mParticle/mparticle-apple-sdk/commit/49d36609e0873b3957846a9153eab936da684098)) +- Remove unnecessary calls to removeObserver ([#168](https://github.com/mParticle/mparticle-apple-sdk/issues/168)) ([a288ba4](https://github.com/mParticle/mparticle-apple-sdk/commit/a288ba469da18690381d0a098c1a2734031b7cc6)) +- Remove Unnecessary Synchronize in Dealloc ([#169](https://github.com/mParticle/mparticle-apple-sdk/issues/169)) ([624891b](https://github.com/mParticle/mparticle-apple-sdk/commit/624891bc5771a1a92f24ef88b669eb06a2acf1c2)) ### Features -* match android type support for custom attributes ([#157](https://github.com/mParticle/mparticle-apple-sdk/issues/157)) ([c9a34cd](https://github.com/mParticle/mparticle-apple-sdk/commit/c9a34cd2aab955cf81994a59ebcaa6958f9370d7)) -* Remove depreciate MPSegment code ([#171](https://github.com/mParticle/mparticle-apple-sdk/issues/171)) ([1c04262](https://github.com/mParticle/mparticle-apple-sdk/commit/1c04262a6144bd292d364873ca1701b0a3793136)) -* Update Sample App for iOS 16 ([#158](https://github.com/mParticle/mparticle-apple-sdk/issues/158)) ([fed8131](https://github.com/mParticle/mparticle-apple-sdk/commit/fed81319e196a43f83fc284e022f94713d32cd82)) +- match android type support for custom attributes ([#157](https://github.com/mParticle/mparticle-apple-sdk/issues/157)) ([c9a34cd](https://github.com/mParticle/mparticle-apple-sdk/commit/c9a34cd2aab955cf81994a59ebcaa6958f9370d7)) +- Remove depreciate MPSegment code ([#171](https://github.com/mParticle/mparticle-apple-sdk/issues/171)) ([1c04262](https://github.com/mParticle/mparticle-apple-sdk/commit/1c04262a6144bd292d364873ca1701b0a3793136)) +- Update Sample App for iOS 16 ([#158](https://github.com/mParticle/mparticle-apple-sdk/issues/158)) ([fed8131](https://github.com/mParticle/mparticle-apple-sdk/commit/fed81319e196a43f83fc284e022f94713d32cd82)) ## [8.8.1](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.8.0...v8.8.1) (2022-07-15) - ### Bug Fixes -* Add filtering check to legacy code path ([#155](https://github.com/mParticle/mparticle-apple-sdk/issues/155)) ([0212944](https://github.com/mParticle/mparticle-apple-sdk/commit/0212944ef6f3ed1849b269fcd355abdac5a4930b)) -* remove undefined hasher behavior ([#152](https://github.com/mParticle/mparticle-apple-sdk/issues/152)) ([a82b928](https://github.com/mParticle/mparticle-apple-sdk/commit/a82b9285c2844ac32638c6692fc651184b6fea81)) +- Add filtering check to legacy code path ([#155](https://github.com/mParticle/mparticle-apple-sdk/issues/155)) ([0212944](https://github.com/mParticle/mparticle-apple-sdk/commit/0212944ef6f3ed1849b269fcd355abdac5a4930b)) +- remove undefined hasher behavior ([#152](https://github.com/mParticle/mparticle-apple-sdk/issues/152)) ([a82b928](https://github.com/mParticle/mparticle-apple-sdk/commit/a82b9285c2844ac32638c6692fc651184b6fea81)) # [8.8.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.7.0...v8.8.0) (2022-05-17) - ### Bug Fixes -* Fix Dereferenced Garbage Pointer ([#148](https://github.com/mParticle/mparticle-apple-sdk/issues/148)) ([d2c58e1](https://github.com/mParticle/mparticle-apple-sdk/commit/d2c58e10559bc38999dca82a2910f478d2250142)) -* property memory annotations ([#146](https://github.com/mParticle/mparticle-apple-sdk/issues/146)) ([c95ddf6](https://github.com/mParticle/mparticle-apple-sdk/commit/c95ddf6da15a6e8ba381a717ec0a5b18c24e749c)) -* update active kits header ([#147](https://github.com/mParticle/mparticle-apple-sdk/issues/147)) ([d196723](https://github.com/mParticle/mparticle-apple-sdk/commit/d1967233a2cf9542f5a3c8e7c9fabd854acf4189)) - +- Fix Dereferenced Garbage Pointer ([#148](https://github.com/mParticle/mparticle-apple-sdk/issues/148)) ([d2c58e1](https://github.com/mParticle/mparticle-apple-sdk/commit/d2c58e10559bc38999dca82a2910f478d2250142)) +- property memory annotations ([#146](https://github.com/mParticle/mparticle-apple-sdk/issues/146)) ([c95ddf6](https://github.com/mParticle/mparticle-apple-sdk/commit/c95ddf6da15a6e8ba381a717ec0a5b18c24e749c)) +- update active kits header ([#147](https://github.com/mParticle/mparticle-apple-sdk/issues/147)) ([d196723](https://github.com/mParticle/mparticle-apple-sdk/commit/d1967233a2cf9542f5a3c8e7c9fabd854acf4189)) ### Features -* add conformsToProtocol forwarding to MPAppDelegateProxy ([#144](https://github.com/mParticle/mparticle-apple-sdk/issues/144)) ([40e517a](https://github.com/mParticle/mparticle-apple-sdk/commit/40e517aa0bff4ecd2368c095a1c7d35b5745ffd1)) -* add support for client side rules ([#151](https://github.com/mParticle/mparticle-apple-sdk/issues/151)) ([6a93096](https://github.com/mParticle/mparticle-apple-sdk/commit/6a93096d285546be9eda62c24bea72d2853033b0)) +- add conformsToProtocol forwarding to MPAppDelegateProxy ([#144](https://github.com/mParticle/mparticle-apple-sdk/issues/144)) ([40e517a](https://github.com/mParticle/mparticle-apple-sdk/commit/40e517aa0bff4ecd2368c095a1c7d35b5745ffd1)) +- add support for client side rules ([#151](https://github.com/mParticle/mparticle-apple-sdk/issues/151)) ([6a93096](https://github.com/mParticle/mparticle-apple-sdk/commit/6a93096d285546be9eda62c24bea72d2853033b0)) # [8.7.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.6.0...v8.7.0) (2022-01-31) - ### Bug Fixes -* custom mapping to transaction attributes not to be null-ed for ecom events ([#141](https://github.com/mParticle/mparticle-apple-sdk/issues/141)) ([19ca3b0](https://github.com/mParticle/mparticle-apple-sdk/commit/19ca3b09e907f343bfe14869df2e2f0a9fb4ef92)) - +- custom mapping to transaction attributes not to be null-ed for ecom events ([#141](https://github.com/mParticle/mparticle-apple-sdk/issues/141)) ([19ca3b0](https://github.com/mParticle/mparticle-apple-sdk/commit/19ca3b09e907f343bfe14869df2e2f0a9fb4ef92)) ### Features -* Add configMaxAgeSeconds to MParticleOptions ([cbf9464](https://github.com/mParticle/mparticle-apple-sdk/commit/cbf94640739f76513c910b96fe3fbf00428e5c3c)) -* add custom logger ([62e830d](https://github.com/mParticle/mparticle-apple-sdk/commit/62e830d6306750cad44c97c3c8d448517c5e0482)) -* add MPKitInstance enum value for GA4 kit ([a81c871](https://github.com/mParticle/mparticle-apple-sdk/commit/a81c87157817f382d5c2e5df23cb3e633191653e)) +- Add configMaxAgeSeconds to MParticleOptions ([cbf9464](https://github.com/mParticle/mparticle-apple-sdk/commit/cbf94640739f76513c910b96fe3fbf00428e5c3c)) +- add custom logger ([62e830d](https://github.com/mParticle/mparticle-apple-sdk/commit/62e830d6306750cad44c97c3c8d448517c5e0482)) +- add MPKitInstance enum value for GA4 kit ([a81c871](https://github.com/mParticle/mparticle-apple-sdk/commit/a81c87157817f382d5c2e5df23cb3e633191653e)) # [8.6.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.5.4...v8.6.0) (2022-01-13) - ### Bug Fixes -* remove infinite values from message data ([#138](https://github.com/mParticle/mparticle-apple-sdk/issues/138)) ([3ea7370](https://github.com/mParticle/mparticle-apple-sdk/commit/3ea7370c1bc42c09e59fb027f7c0e36dd8878d88)) -* update reusable workflow urls ([0d1dc43](https://github.com/mParticle/mparticle-apple-sdk/commit/0d1dc431e4668e5a103fe70054f3c29f89d96f85)) - +- remove infinite values from message data ([#138](https://github.com/mParticle/mparticle-apple-sdk/issues/138)) ([3ea7370](https://github.com/mParticle/mparticle-apple-sdk/commit/3ea7370c1bc42c09e59fb027f7c0e36dd8878d88)) +- update reusable workflow urls ([0d1dc43](https://github.com/mParticle/mparticle-apple-sdk/commit/0d1dc431e4668e5a103fe70054f3c29f89d96f85)) ### Features -* add upload bypass support to logscreenevent ([#137](https://github.com/mParticle/mparticle-apple-sdk/issues/137)) ([1bfd098](https://github.com/mParticle/mparticle-apple-sdk/commit/1bfd09862360f626f4041c3d12bd11ed9667d541)) +- add upload bypass support to logscreenevent ([#137](https://github.com/mParticle/mparticle-apple-sdk/issues/137)) ([1bfd098](https://github.com/mParticle/mparticle-apple-sdk/commit/1bfd09862360f626f4041c3d12bd11ed9667d541)) ## [8.5.4](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.5.3...v8.5.4) (2021-10-04) - ### Bug Fixes -* Expose session start time ([#134](https://github.com/mParticle/mparticle-apple-sdk/issues/134)) ([8a3437f](https://github.com/mParticle/mparticle-apple-sdk/commit/8a3437ff0f34b8cf99faf45768c3157a54804379)) -* Prevent Infinite Values in Message Data ([#39](https://github.com/mParticle/mparticle-apple-sdk/issues/39)) ([d19d785](https://github.com/mParticle/mparticle-apple-sdk/commit/d19d785916b6169b90454b897c5037f5423cfa9e)) +- Expose session start time ([#134](https://github.com/mParticle/mparticle-apple-sdk/issues/134)) ([8a3437f](https://github.com/mParticle/mparticle-apple-sdk/commit/8a3437ff0f34b8cf99faf45768c3157a54804379)) +- Prevent Infinite Values in Message Data ([#39](https://github.com/mParticle/mparticle-apple-sdk/issues/39)) ([d19d785](https://github.com/mParticle/mparticle-apple-sdk/commit/d19d785916b6169b90454b897c5037f5423cfa9e)) ## [8.5.3](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.5.2...v8.5.3) (2021-09-20) - ### Bug Fixes -* Calling -[MParticle reset] doesn't clean up our app delegate proxy ([d7932da](https://github.com/mParticle/mparticle-apple-sdk/commit/d7932da84ae428485628e55d001b5336a3780ef7)) -* Mapped screen events forwarding to kits ([86e7c75](https://github.com/mParticle/mparticle-apple-sdk/commit/86e7c75e38db7bc4375ca899dac7c058ebb4825d)) +- Calling -[MParticle reset] doesn't clean up our app delegate proxy ([d7932da](https://github.com/mParticle/mparticle-apple-sdk/commit/d7932da84ae428485628e55d001b5336a3780ef7)) +- Mapped screen events forwarding to kits ([86e7c75](https://github.com/mParticle/mparticle-apple-sdk/commit/86e7c75e38db7bc4375ca899dac7c058ebb4825d)) ## [8.5.2](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.5.1...v8.5.2) (2021-09-10) - ### Bug Fixes -* Revert commit e91a9a3 Update Conversion for Number Value in NSDictionary helper class ([a2280fe](https://github.com/mParticle/mparticle-apple-sdk/commit/a2280fefe187a16f1834310b1001023f078a2d16)) +- Revert commit e91a9a3 Update Conversion for Number Value in NSDictionary helper class ([a2280fe](https://github.com/mParticle/mparticle-apple-sdk/commit/a2280fefe187a16f1834310b1001023f078a2d16)) ## [8.5.1](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.5.0...v8.5.1) (2021-09-09) - ### Bug Fixes -* Gracefully Handle Invalid Message Data ([b618e5b](https://github.com/mParticle/mparticle-apple-sdk/commit/b618e5ba9e29805c9d1e3b0378604a0a4bb0471a)) -* Preserve attributes when mapping commerce events ([0ff8414](https://github.com/mParticle/mparticle-apple-sdk/commit/0ff84147dc31e8c4ba64123acd5f0d99d21503c8)) -* Remove duplicate key in dictionary literal ([b1ecb17](https://github.com/mParticle/mparticle-apple-sdk/commit/b1ecb172f2204959f3dfd1153bc360d6c01a4dae)) +- Gracefully Handle Invalid Message Data ([b618e5b](https://github.com/mParticle/mparticle-apple-sdk/commit/b618e5ba9e29805c9d1e3b0378604a0a4bb0471a)) +- Preserve attributes when mapping commerce events ([0ff8414](https://github.com/mParticle/mparticle-apple-sdk/commit/0ff84147dc31e8c4ba64123acd5f0d99d21503c8)) +- Remove duplicate key in dictionary literal ([b1ecb17](https://github.com/mParticle/mparticle-apple-sdk/commit/b1ecb172f2204959f3dfd1153bc360d6c01a4dae)) # [8.5.0](https://github.com/mParticle/mparticle-apple-sdk/compare/v8.4.0...v8.5.0) (2021-07-29) - ### Bug Fixes -* Ensure accurate app/device info after restart (match Android SDK behavior) ([e1fdc94](https://github.com/mParticle/mparticle-apple-sdk/commit/e1fdc94784667fd30e7fee0f54234934d0bd8cd4)) -* Transaction attributes revenue logic differs from Android ([c274e42](https://github.com/mParticle/mparticle-apple-sdk/commit/c274e42171b09ddf55d800020c7434054202ac82)) - +- Ensure accurate app/device info after restart (match Android SDK behavior) ([e1fdc94](https://github.com/mParticle/mparticle-apple-sdk/commit/e1fdc94784667fd30e7fee0f54234934d0bd8cd4)) +- Transaction attributes revenue logic differs from Android ([c274e42](https://github.com/mParticle/mparticle-apple-sdk/commit/c274e42171b09ddf55d800020c7434054202ac82)) ### Features -* Event upload bypass option ([e58ae23](https://github.com/mParticle/mparticle-apple-sdk/commit/e58ae230acdcfb7a6fee16424e7fd9b85ab157f7)) +- Event upload bypass option ([e58ae23](https://github.com/mParticle/mparticle-apple-sdk/commit/e58ae230acdcfb7a6fee16424e7fd9b85ab157f7)) # mParticle Apple SDK CHANGELOG @@ -654,7 +571,7 @@ This release includes a number of bugfixes: ## 8.1.1 - Fix Other6 Identity Login Issue -This resolves an issue where identity login requests that included certain MPIdentities were always returning a 400 response. + This resolves an issue where identity login requests that included certain MPIdentities were always returning a 400 response. ## 8.1.0 @@ -703,18 +620,18 @@ Important behavioral and API changes: - Introduction of the `MPIdentity` enum, allowing for both device and user identities to be supplied to the identity API - Kits have been updated to use the latest iOS 14 betas of their respective SDKs: - | Partner SDK | Apple SDK v7 | Apple SDK v8 | - |-------------|--------------|--------------| - | Airship | ~> 12.0 | ~> 14.0.0 | - | AppsFlyer | ~> 5.0 | ~> 6.0 | - | Apptentive | ~> 5.2 | ~> 5.3 | - | Apptimize | ~> 3.0 | ~> 3.2 | - | Branch | ~> 0.31.2 | ~> 0.35 | - | Braze | ~> 3.20 | ~> 3.27 | - | Crittercism | '5.6.7' | ~> 5.0 | - | Leanplum | ~> 2.6 | ~> 3.0 | - | Localytics | ~> 5.2 | ~> 6.0 | - | Primer | '3.2.3' | ~> 3.6 | + | Partner SDK | Apple SDK v7 | Apple SDK v8 | + | ----------- | ------------ | ------------ | + | Airship | ~> 12.0 | ~> 14.0.0 | + | AppsFlyer | ~> 5.0 | ~> 6.0 | + | Apptentive | ~> 5.2 | ~> 5.3 | + | Apptimize | ~> 3.0 | ~> 3.2 | + | Branch | ~> 0.31.2 | ~> 0.35 | + | Braze | ~> 3.20 | ~> 3.27 | + | Crittercism | '5.6.7' | ~> 5.0 | + | Leanplum | ~> 2.6 | ~> 3.0 | + | Localytics | ~> 5.2 | ~> 6.0 | + | Primer | '3.2.3' | ~> 3.6 | - The above are using wildcard dependencies, see here for how to interpret these: https://guides.cocoapods.org/using/the-podfile.html#specifying-pod-versions - If you don't see a kit listed here, it was probably already using a wildcard dependency. It has been released as is, as version 8.0.1, and will automatically pull in the latest version of the partner's SDK. @@ -970,6 +887,7 @@ Also included is a change to allow user agent collection in iOS extensions. ### Core #### User Agent Collection + - This release restores support for automatic collection of browser user agent by the SDK. - This release also deprecates the Cart API. The Cart API was originally designed to maintain and hold on to product objects to be appended automatically to Commerce events. Over time we have found it to be better practice for the hosting app to maintain shopping cart state rather than the mParticle SDK. In place of the Cart API, please include all of the applicable product objects with each Commerce event. @@ -1017,10 +935,13 @@ For more details, see the Media SDK repository: https://github.com/mParticle/mpa ## 7.11.0 ## iOS 13 Official Support + ### Push Registration -If you are collecting push registration tokens and using them for server-side integrations, this is a *critical update*. If you are only registering for push via kits (such as Braze), you can use iOS Braze kit 7.10.7 or later with iOS 13. + +If you are collecting push registration tokens and using them for server-side integrations, this is a _critical update_. If you are only registering for push via kits (such as Braze), you can use iOS Braze kit 7.10.7 or later with iOS 13. ### UIWebView and User Agent Collection + Support for UIWebView has been removed. User agent collection has been disabled in this release. You may manually supply the user agent to the MParticleOptions object on SDK initialization if required. ## 7.10.5 @@ -1204,10 +1125,9 @@ This release helps make our AppDelegate proxy mechanism more transparent by allo ## Core - Add new and updated existing integration attribute APIs - - - Allow integration attributes to be set for any ID (not just known kit IDs) - - Add a public query API for specific integration attributes by ID - - Rename the private usages and APIs from kitCode to integrationId + - Allow integration attributes to be set for any ID (not just known kit IDs) + - Add a public query API for specific integration attributes by ID + - Rename the private usages and APIs from kitCode to integrationId - Fix a potential hang that could occur if Apple Search Ads timed out @@ -1331,6 +1251,7 @@ You can now control which kits are enabled and disabled based on a user's "logge ## Kit Updates ### Kochava + - Ensure log level from config is always respected, not overridden by environment - Don't set Kochava delegate unless retrieveAttribution setting is turned on - Remove use of undocumented isNewUser flag @@ -1448,7 +1369,7 @@ This release updates the SDK to handle several changes present in the latest bet ## 7.4.2 -- This releases addresses several synchronization issues with internal SDK properties that could lead to crashes. +- This releases addresses several synchronization issues with internal SDK properties that could lead to crashes. ## 7.4.1 @@ -1469,7 +1390,7 @@ This release updates the SDK to handle several changes present in the latest bet ## 7.3.11 -- This release ensures that kits are always started on the main thread rather than the SDK's internal serial queue. Kits will still not be started sychronously when calling `MParticle.start`, but they will be initialized on the main thread on a later run-loop. +- This release ensures that kits are always started on the main thread rather than the SDK's internal serial queue. Kits will still not be started sychronously when calling `MParticle.start`, but they will be initialized on the main thread on a later run-loop. ## 7.3.10 @@ -1516,7 +1437,7 @@ The SDK can now dynamically enable and disable kits based on the current user's - This release fixes potential SQLite crashes caused by multi-threaded SQLite access caused by the SDK's significant time-change listener. - This release addresses a potential crash or error log caused by kits that implement the attribution API and return a nil attribution result. -## 7.3.4 +## 7.3.4 - This is a **critical** bug fix release. Prior to this, the SDK would upload duplicate kit forwarding statistics. These statistic do not impact forwarding - but they populate the mParticle Event Forwarding dashboard. This change is crucial for proper reporting as well as reducing the amount of SDK SQL storage and upload payload size. @@ -1557,7 +1478,8 @@ Here are a few important notes about this release: ## 7.2.0 -This is a *high priority* update for all users of SDK v7. This update: +This is a _high priority_ update for all users of SDK v7. This update: + - Ensures database migrations from v6 to v7 occur on a background thread. - Reduces the amount of data that is migrated. - Simplifies batch upload creation and session deletion logic to ensure the SDK's database is fully cleared when appropriate. @@ -1630,14 +1552,14 @@ This release fixes a bug where the SDK could trigger a call to config before sta Version 7.1.0 is the first non-beta release of the new mParticle IDSync framework. It contains many new features as well as breaking changes: -- New Identity APIs allowing custom IDSync "strategies" per customer. +- New Identity APIs allowing custom IDSync "strategies" per customer. - Included in the new APIs is a `MParticleUser` object, as well as the new APIs for `login`, `logout`, `modify`, and more! [You can read more about the new Identity APIs here](https://docs.mparticle.com/developers/sdk/ios/identity). - `MParticleOptions` object for explicit SDK configuration. - New "Attribution" API, which replaces the former "deferred deeplink" API. ## Migrating from SDK v6 -Prior to upgrading to version 7, your mParticle org **must** be provisioned with an Identity Strategy. Please contact the mParticle Customer Success team at support@mparticle.com. +Prior to upgrading to version 7, your mParticle org **must** be provisioned with an Identity Strategy. Please contact the mParticle Customer Success team at support@mparticle.com. The new SDK contains multiple breaking API changes. To learn how to migrate your existing code, please [reference the iOS migration guide](https://docs.mparticle.com/developers/sdk/ios/getting-started#upgrade-to-version-7-of-the-sdk). @@ -1660,36 +1582,36 @@ This release updates MPIdentityApiRequest by removing the copyUserAttributes set ## 7.0.8 -* [NEW] Introduce new deeplinking API +- [NEW] Introduce new deeplinking API ## 7.0.7 -* [FIX] Allow concurrent internal modify requests +- [FIX] Allow concurrent internal modify requests ## 7.0.6 -* [FIX] Ensure Identifying flag is flipped on API timeout +- [FIX] Ensure Identifying flag is flipped on API timeout ## 7.0.5 -* [FIX] Fixes and enhancements to Identity API error callbacks +- [FIX] Fixes and enhancements to Identity API error callbacks ## 7.0.4 -* [FIX] Remove MPUtils.h/m +- [FIX] Remove MPUtils.h/m ## 7.0.3 -* [FIX] Ensure the correct mpid is used in batches -* [FIX] Fix device application stamp +- [FIX] Ensure the correct mpid is used in batches +- [FIX] Fix device application stamp ## 7.0.2 -* [FIX] Propagate Identity API errors to original caller +- [FIX] Propagate Identity API errors to original caller ## 7.0.0 -* [NEW] New identity APIs +- [NEW] New identity APIs ## 6.15.12 @@ -1792,347 +1714,348 @@ This release updates MPIdentityApiRequest by removing the copyUserAttributes set ## 6.14.5 -* [FIX] Fixes for Xcode 9 / iOS 11 and main thread checker -* [NEW] Remove category on NSUserDefaults +- [FIX] Fixes for Xcode 9 / iOS 11 and main thread checker +- [NEW] Remove category on NSUserDefaults ## 6.14.4 -* [FIX] Ensure all server-side configuration settings are reloaded on every app-launch +- [FIX] Ensure all server-side configuration settings are reloaded on every app-launch ## 6.14.3 -* [FIX] Revert main thread error fix +- [FIX] Revert main thread error fix ## 6.14.2 -* [FIX] Fix main thread error -* [FIX] Fix clang pragma -* [FIX] Remove check for notification hash +- [FIX] Fix main thread error +- [FIX] Fix clang pragma +- [FIX] Remove check for notification hash ## 6.14.1 -* [FIX] Retry and increase timeout for search ads +- [FIX] Retry and increase timeout for search ads ## 6.14.0 -* [NEW] Add support for Skyhook -* [NEW] Add support for Iterable +- [NEW] Add support for Skyhook +- [NEW] Add support for Iterable ## 6.13.3 -* [FIX] Capture user agent in start, never in background +- [FIX] Capture user agent in start, never in background ## 6.13.2 -* [FIX] Fix clang static analyzer warnings +- [FIX] Fix clang static analyzer warnings ## 6.13.1 -* [FIX] Support for [Radar](https://www.onradar.com) as a kit -* [FIX] Support for forcing SDK Environment on start-up +- [FIX] Support for [Radar](https://www.onradar.com) as a kit +- [FIX] Support for forcing SDK Environment on start-up ## 6.13.0 -* [NEW] Handle eCommerce events from embedded js sdk -* [NEW] Optimize user identity and user attribute change messages -* [NEW] Sync user attributes and identities only once per kit +- [NEW] Handle eCommerce events from embedded js sdk +- [NEW] Optimize user identity and user attribute change messages +- [NEW] Sync user attributes and identities only once per kit ## 6.12.6 -* [FIX] Force refresh the config cache when a kit configuration is absent +- [FIX] Force refresh the config cache when a kit configuration is absent ## 6.12.5 -* [NEW] Use mutable copy of string when setting a user attribute key +- [NEW] Use mutable copy of string when setting a user attribute key ## 6.12.4 -* [NEW] Include latitude and longitude in session start events -* [NEW] Allow for environment override even for prod apps -* [FIX] Reporting of commerce events when originated from a custom mapping +- [NEW] Include latitude and longitude in session start events +- [NEW] Allow for environment override even for prod apps +- [FIX] Reporting of commerce events when originated from a custom mapping ## 6.12.3 -* [FIX] Execute projection when the commerce event has no mapped attributes +- [FIX] Execute projection when the commerce event has no mapped attributes ## 6.12.2 -* [NEW] Remove eTag when app version or build changes -* [FIX] Enumeration to generate upload batches is done non-concurrently +- [NEW] Remove eTag when app version or build changes +- [FIX] Enumeration to generate upload batches is done non-concurrently ## 6.12.1 -* [FIX] A try/catch block added to serialization of MPMessage. Moreover, further conditions were added to assure the values being handled by the MPUploadBuilder are valid +- [FIX] A try/catch block added to serialization of MPMessage. Moreover, further conditions were added to assure the values being handled by the MPUploadBuilder are valid ## 6.12.0 -* [NEW] Support for [Radar](https://www.onradar.com) as a kit -* [NEW] Retrieve kit instance asynchronously with a block. Use `- (void)kitInstance:(NSNumber *)kitCode completionHandler:(void (^)(id _Nullable kitInstance))completionHandler;` to retrieve a kit instance. The block will be called immediately if the kit is already initialized, or will be called asynchronously as soon as the kit becomes initialized -* [NEW] Lighter SDK. New Year, new resolution, the core SDK has gone on a diet. Stay tuned, more to come -* [FIX] Fix location getter and nullability notation +- [NEW] Support for [Radar](https://www.onradar.com) as a kit +- [NEW] Retrieve kit instance asynchronously with a block. Use `- (void)kitInstance:(NSNumber *)kitCode completionHandler:(void (^)(id _Nullable kitInstance))completionHandler;` to retrieve a kit instance. The block will be called immediately if the kit is already initialized, or will be called asynchronously as soon as the kit becomes initialized +- [NEW] Lighter SDK. New Year, new resolution, the core SDK has gone on a diet. Stay tuned, more to come +- [FIX] Fix location getter and nullability notation ## 6.11.2 -* [NEW] Set location without the need to call `beginLocationTracking` -* [FIX] Upload data immediately on first application launch +- [NEW] Set location without the need to call `beginLocationTracking` +- [FIX] Upload data immediately on first application launch ## 6.11.1 -* [NEW] Queue launch parameters. The app notification handler now takes advantage of the forwarding queue mechanism. If kits have not been initialized yet (config not received from server), the data will be held in a queue and once the configuration has been received and kits initialized, the queued items are replayed to kits +- [NEW] Queue launch parameters. The app notification handler now takes advantage of the forwarding queue mechanism. If kits have not been initialized yet (config not received from server), the data will be held in a queue and once the configuration has been received and kits initialized, the queued items are replayed to kits ## 6.11.0 -* [NEW] Support for [Reveal Mobile](http://www.revealmobile.com/) as a kit -* [NEW] Wrap the capture of the user-agent in a try/catch -* [FIX] Adjust CommerceEvent property serialization: currency, screen name, and non-interactive are now located at the root of serialized CommerceEvent messages -* [FIX] Simplify session management when app becomes active +- [NEW] Support for [Reveal Mobile](http://www.revealmobile.com/) as a kit +- [NEW] Wrap the capture of the user-agent in a try/catch +- [FIX] Adjust CommerceEvent property serialization: currency, screen name, and non-interactive are now located at the root of serialized CommerceEvent messages +- [FIX] Simplify session management when app becomes active ## 6.10.5 -* [FIX] Increment user attribute when not set previously -* [FIX] Runtime iOS 10 verification of push notifications +- [FIX] Increment user attribute when not set previously +- [FIX] Runtime iOS 10 verification of push notifications ## 6.10.4 -* [FIX] Fix potential race condition beginning sessions -* [FIX] End background task when batches are finished +- [FIX] Fix potential race condition beginning sessions +- [FIX] End background task when batches are finished ## 6.10.3 -* [FIX] Fix crash when an app is being force quit. +- [FIX] Fix crash when an app is being force quit. ## 6.10.2 -* [FIX] Remove the use of generics from the `checkForDeferredDeepLinkWithCompletionHandler:` method. The received parameter signature is now `NSDictionary`, previously it was `NSDictionary` +- [FIX] Remove the use of generics from the `checkForDeferredDeepLinkWithCompletionHandler:` method. The received parameter signature is now `NSDictionary`, previously it was `NSDictionary` ## 6.10.0 -* [NEW] Collect attribute details from search ads -* [FIX] Compare custom mapping keys in a case insensitive manner -* [FIX] Convert event attributes to prior to matching custom mappings -* [FIX] Generate the upload batch when the app is terminated by the user or OS. This way app version and build will always be correctly attributed to app events +- [NEW] Collect attribute details from search ads +- [FIX] Compare custom mapping keys in a case insensitive manner +- [FIX] Convert event attributes to prior to matching custom mappings +- [FIX] Generate the upload batch when the app is terminated by the user or OS. This way app version and build will always be correctly attributed to app events ## 6.9.0 -* [NEW] Support for [Apptimize](https://apptimize.com) as a kit -* [NEW] Collect whether Daylight Savings Time is enabled -* [NEW] Add notification for when the SDK has finished initializing. Add a flag property indicating whether the SDK has been initialized (KVO compatible) +- [NEW] Support for [Apptimize](https://apptimize.com) as a kit +- [NEW] Collect whether Daylight Savings Time is enabled +- [NEW] Add notification for when the SDK has finished initializing. Add a flag property indicating whether the SDK has been initialized (KVO compatible) ## 6.8.0 -* [NEW] Support for [Leanplum](https://www.leanplum.com) as a kit -* [NEW] When a user identity changes a new type of message is added to the batch to be uploaded to the server. This allows for greater control to inform partners about which user identities were set/present at the moment an app event is logged +- [NEW] Support for [Leanplum](https://www.leanplum.com) as a kit +- [NEW] When a user identity changes a new type of message is added to the batch to be uploaded to the server. This allows for greater control to inform partners about which user identities were set/present at the moment an app event is logged > You will need for this SDK update: -> * Xcode 8 or later -> * CocoaPods 1.1.0.rc.2 or later +> +> - Xcode 8 or later +> - CocoaPods 1.1.0.rc.2 or later ## 6.7.2 -* [FIX] When a user attribute changes (new, update, or delete) a new type of message is added to the batch to be uploaded to the server. This allows for greater control to inform partners about which user attributes were set/present at the moment an app event is logged +- [FIX] When a user attribute changes (new, update, or delete) a new type of message is added to the batch to be uploaded to the server. This allows for greater control to inform partners about which user attributes were set/present at the moment an app event is logged ## 6.7.1 -* [FIX] Timing of logged events: Events (both app events and commerce events) now have a timestamp property, which gets populated automatically by the SDK, when an event is logged prior to the SDK being fully initialized. If set, this property will override the timestamp of messages when they are about to be persisted +- [FIX] Timing of logged events: Events (both app events and commerce events) now have a timestamp property, which gets populated automatically by the SDK, when an event is logged prior to the SDK being fully initialized. If set, this property will override the timestamp of messages when they are about to be persisted ## 6.7.0 -* [NEW] Custom mappings now support more advanced matching schemes -* [NEW] Support for [Urban Airship](https://www.urbanairship.com) as a kit +- [NEW] Custom mappings now support more advanced matching schemes +- [NEW] Support for [Urban Airship](https://www.urbanairship.com) as a kit ## 6.6.1 -* [FIX] A newly introduced class was missing from the tvOS Xcode target +- [FIX] A newly introduced class was missing from the tvOS Xcode target ## 6.6.0 -* [NEW] Kits can now pass integration attributes back to the core SDK +- [NEW] Kits can now pass integration attributes back to the core SDK ## 6.5.0 -* [NEW] Support for [Primer](https://goprimer.com) as a kit +- [NEW] Support for [Primer](https://goprimer.com) as a kit ## 6.4.0 -* [NEW] Support for [Apptentive](http://www.apptentive.com) as a kit -* [NEW] MParticleConfig.plist option to opt in/out of automatic silent notification registration. See [mParticle Docs](http://docs.mparticle.com/#apple) for details +- [NEW] Support for [Apptentive](http://www.apptentive.com) as a kit +- [NEW] MParticleConfig.plist option to opt in/out of automatic silent notification registration. See [mParticle Docs](http://docs.mparticle.com/#apple) for details ## 6.3.0 -* [NEW] Add the customerId user identity as an event attribute when forwarding to AppsFlyer -* [NEW] Add new methods to the kit protocol to forward user notification related info to kits -* [NEW] Config optional flag to send the session history batch (reducing the amount of data sent over to mParticle) -* [NEW] Opt-in to always try to collect the IDFA -* [NEW] Add continueUserActivity to the public SDK API (Pull Request submitted by twobitlabs) -* [FIX] Guarantee that launch options in AST messages to contain only string parameters +- [NEW] Add the customerId user identity as an event attribute when forwarding to AppsFlyer +- [NEW] Add new methods to the kit protocol to forward user notification related info to kits +- [NEW] Config optional flag to send the session history batch (reducing the amount of data sent over to mParticle) +- [NEW] Opt-in to always try to collect the IDFA +- [NEW] Add continueUserActivity to the public SDK API (Pull Request submitted by twobitlabs) +- [FIX] Guarantee that launch options in AST messages to contain only string parameters ## 6.2.0 -* [NEW] Support for [Button](https://www.usebutton.com) as a kit -* [FIX] Server configuration override of crash report initialization is restored +- [NEW] Support for [Button](https://www.usebutton.com) as a kit +- [FIX] Server configuration override of crash report initialization is restored ## 6.1.0 -* [NEW] User attributes can now take arrays as values. The array of values is associated with a user attribute key. The list of all user attributes can be retrieved using the new `userAttributes` property +- [NEW] User attributes can now take arrays as values. The array of values is associated with a user attribute key. The list of all user attributes can be retrieved using the new `userAttributes` property ## 6.0.7 -* [FIX] Filter transaction attributes in commerce events -* [FIX] Expand the scope of MPAppDelegateProxy to handle protocol conformance and class hierarchy matching -* [FIX] Fix static analysis flags -* [FIX] Add clang pragmas to remove warnings +- [FIX] Filter transaction attributes in commerce events +- [FIX] Expand the scope of MPAppDelegateProxy to handle protocol conformance and class hierarchy matching +- [FIX] Fix static analysis flags +- [FIX] Add clang pragmas to remove warnings ## 6.0.6 -* [FIX] Using a string constant (iOS 9 or above) or a string literal (iOS 8 or below) to log a deep-linking event +- [FIX] Using a string constant (iOS 9 or above) or a string literal (iOS 8 or below) to log a deep-linking event ## 6.0.5 -* [FIX] Add additional checks for iOS 9 symbols +- [FIX] Add additional checks for iOS 9 symbols ## 6.0.4 -* [FIX] More consistent handling of kit initialization and sampling +- [FIX] More consistent handling of kit initialization and sampling ## 6.0.3 -* [FIX] Expose some files for use by kits -* [FIX] Add nil check and prevent modifying while enumerating +- [FIX] Expose some files for use by kits +- [FIX] Add nil check and prevent modifying while enumerating ## 6.0.2 -* [FIX] Set the kits initialized flag only if persisted kits have been initialized +- [FIX] Set the kits initialized flag only if persisted kits have been initialized ## 6.0.1 -* [FIX] Correct a condition determining whether variables were valid +- [FIX] Correct a condition determining whether variables were valid ## 6.0.0 -* [NEW] We are introducing the ability to implement extensions for the mParticle SDK. Kits have been the first component to take advantage of this new and more powerful architecture -* [NEW] A queue was added to hold events to be forwarded to kits until the first configuration is received from the server and kits are initialized -* [NEW] Added support for Carthage -* [NEW] Maximum user attribute value length has been extended to 4096 characters -* [FIX] Restored unit tests for each of the platforms +- [NEW] We are introducing the ability to implement extensions for the mParticle SDK. Kits have been the first component to take advantage of this new and more powerful architecture +- [NEW] A queue was added to hold events to be forwarded to kits until the first configuration is received from the server and kits are initialized +- [NEW] Added support for Carthage +- [NEW] Maximum user attribute value length has been extended to 4096 characters +- [FIX] Restored unit tests for each of the platforms ## 5.5.2 -* [NEW] Stripping `$` from event attributes when forwarding to Appboy -* [FIX] Updated the `podspec` to include paths and flags required to build kits +- [NEW] Stripping `$` from event attributes when forwarding to Appboy +- [FIX] Updated the `podspec` to include paths and flags required to build kits ## 5.5.1 -* [NEW] Added Branch Metrics support for received push notifications -* [NEW] Renamed the `MPLogLevel` enum to `MPILogLevel`. The renamed values are: `MPILogLevelNone`, `MPILogLevelError`, `MPILogLevelWarning`, `MPILogLevelDebug`, and `MPILogLevelVerbose` +- [NEW] Added Branch Metrics support for received push notifications +- [NEW] Renamed the `MPLogLevel` enum to `MPILogLevel`. The renamed values are: `MPILogLevelNone`, `MPILogLevelError`, `MPILogLevelWarning`, `MPILogLevelDebug`, and `MPILogLevelVerbose` ## 5.5.0 -* [NEW] Unification of the SDKs. Now the iOS and tvOS SDKs are combined into one single SDK. Support for more platforms will be coming in the future -* [NEW] Updated Kahuna kit -* [NEW] Conforming to the RFC 6585 HTTP status code 429, `Retry-After` response header +- [NEW] Unification of the SDKs. Now the iOS and tvOS SDKs are combined into one single SDK. Support for more platforms will be coming in the future +- [NEW] Updated Kahuna kit +- [NEW] Conforming to the RFC 6585 HTTP status code 429, `Retry-After` response header ## 5.4.2 -* [NEW] Validating the data type in event custom flags. Making sure that the array of flags is an array and that it only contains string items in it -* [FIX] Do not forward push information to Kahuna if the app was launched as a result of a user tapping on a push notification, since their SDK is already capturing the contents of the notification. There is no impact on data forwarding/counting/reporting, this just prevents a Kahuna delegate method from being called twice +- [NEW] Validating the data type in event custom flags. Making sure that the array of flags is an array and that it only contains string items in it +- [FIX] Do not forward push information to Kahuna if the app was launched as a result of a user tapping on a push notification, since their SDK is already capturing the contents of the notification. There is no impact on data forwarding/counting/reporting, this just prevents a Kahuna delegate method from being called twice ## 5.4.1 -* [NEW] Expanded the Branch Metrics kit to handle `openURL` and `continueUserActivity` -* [NEW] Custom mapping between mParticle and Appboy user attributes -* [FIX] Fixed duplicate forwarding of a push notification when launching an app by tapping on a remote notification -* [FIX] Fixed the representation of custom attributes in commerce event product impressions -* [FIX] Fixed the predicate filtering active kits -* [FIX] Fixed the formatting of event attributes in `logError` -* [FIX] Correct the expected data type for configuring custom dimensions in Localytics +- [NEW] Expanded the Branch Metrics kit to handle `openURL` and `continueUserActivity` +- [NEW] Custom mapping between mParticle and Appboy user attributes +- [FIX] Fixed duplicate forwarding of a push notification when launching an app by tapping on a remote notification +- [FIX] Fixed the representation of custom attributes in commerce event product impressions +- [FIX] Fixed the predicate filtering active kits +- [FIX] Fixed the formatting of event attributes in `logError` +- [FIX] Correct the expected data type for configuring custom dimensions in Localytics ## 5.4.0 -* Support for [Tune](https://www.tune.com/) as a kit -* Verifying whether obtained 3rd party custom module values are a supported data type +- Support for [Tune](https://www.tune.com/) as a kit +- Verifying whether obtained 3rd party custom module values are a supported data type ## 5.3.2 -* Updated the nullability notation for handleActionWithIdentifier -* Deferring the execution of the code in the ApplicationDidFinishLaunching to the next run-loop as a workaround to a bug in the Sqlite implementation +- Updated the nullability notation for handleActionWithIdentifier +- Deferring the execution of the code in the ApplicationDidFinishLaunching to the next run-loop as a workaround to a bug in the Sqlite implementation ## 5.3.1 -* Determining whether to forward an app delegate call to the old deep-linking method -* Forwarding event attributes as user attributes to Appboy +- Determining whether to forward an app delegate call to the old deep-linking method +- Forwarding event attributes as user attributes to Appboy ## 5.3.0 -* Support for [AppsFlyer](https://www.appsflyer.com) as a kit -* Implementation of filter by event attribute value -* Preventing session history batch being sent when data is ramped +- Support for [AppsFlyer](https://www.appsflyer.com) as a kit +- Implementation of filter by event attribute value +- Preventing session history batch being sent when data is ramped ## 5.2.3 -* Indirect instantiation of Kochava to allow it to work in the mParticle SDK with dynamically linked frameworks, `use_frameworks!`, bitcode, and static libraries +- Indirect instantiation of Kochava to allow it to work in the mParticle SDK with dynamically linked frameworks, `use_frameworks!`, bitcode, and static libraries ## 5.2.2 -* Updated the podspec and README to allow for the utilization of `use_frameworks!` and the mParticle SDK -* Fixed an overloaded start method that was overriding the running environment parameter +- Updated the podspec and README to allow for the utilization of `use_frameworks!` and the mParticle SDK +- Fixed an overloaded start method that was overriding the running environment parameter ## 5.2.1 -* Fixing the location of the Wootric subspec +- Fixing the location of the Wootric subspec ## 5.2.0 -* Support for [Wootric](https://www.wootric.com) as a kit -* Broadcast of the session start notification may incur a delay if the SDK is being started -* Renamed MPConstants to MPIConstants +- Support for [Wootric](https://www.wootric.com) as a kit +- Broadcast of the session start notification may incur a delay if the SDK is being started +- Renamed MPConstants to MPIConstants ## 5.1.6 -* Verifying the boundaries of eCommerce currency values to avoid numbers represented using scientific notation -* Early detection of kit configuration change when migrating from SDK 4.x to 5.x -* Reporting the app key in the request header +- Verifying the boundaries of eCommerce currency values to avoid numbers represented using scientific notation +- Early detection of kit configuration change when migrating from SDK 4.x to 5.x +- Reporting the app key in the request header ## 5.1.5 -* Replaced NSTimer with dispatch_source_t with positive results minimizing the use of energy -* Refactored class files adding the MP prefix +- Replaced NSTimer with dispatch_source_t with positive results minimizing the use of energy +- Refactored class files adding the MP prefix ## 5.1.4 -* Adopted Lightweight Generics -* Fixed a bug reporting active kits -* Enforcing the data type of eCommerce numeric values +- Adopted Lightweight Generics +- Fixed a bug reporting active kits +- Enforcing the data type of eCommerce numeric values ## 5.1.3 -* Adopted the Objective-C Nullability syntax -* Serializing kit configurations rather than kit instances -* Defined default subspecs -* New and updated unit tests +- Adopted the Objective-C Nullability syntax +- Serializing kit configurations rather than kit instances +- Defined default subspecs +- New and updated unit tests ## 5.1.2 -* Using asynchronous validation for authenticity of certificates +- Using asynchronous validation for authenticity of certificates ## 5.1.1 -* Each commerce event action is dealt with in an action-by-action basis for Kahuna -* Fixed a bug expanding and forwarding events to kits with no support to eCommerce events +- Each commerce event action is dealt with in an action-by-action basis for Kahuna +- Fixed a bug expanding and forwarding events to kits with no support to eCommerce events ## 5.1.0 -* Support for [Crittercism](http://www.crittercism.com) as a kit -* Crash reporter has been implemented as an optional subspec -* Validating the authenticity of network requests by alternative means to avoid errors raised by 3rd party SDKs mutating and proxying mParticle's original object performing the request -* Removed legacy semaphores from network connections -* Fixed a bug referencing commerce event names +- Support for [Crittercism](http://www.crittercism.com) as a kit +- Crash reporter has been implemented as an optional subspec +- Validating the authenticity of network requests by alternative means to avoid errors raised by 3rd party SDKs mutating and proxying mParticle's original object performing the request +- Removed legacy semaphores from network connections +- Fixed a bug referencing commerce event names ## 5.0.2 -* Fixed a bug about events with no attributes not being forwarded to kits +- Fixed a bug about events with no attributes not being forwarded to kits ## 5.0.1 -* Migrated Unit Tests from SDK version 4.x to 5.x -* Added support to the new iOS 9 application:openURL:options: app delegate method -* Fixed a bug migrating data when the database structure changes +- Migrated Unit Tests from SDK version 4.x to 5.x +- Added support to the new iOS 9 application:openURL:options: app delegate method +- Fixed a bug migrating data when the database structure changes diff --git a/Example/mParticleExample/Assets.xcassets/AppIcon.appiconset/Contents.json b/Example/mParticleExample/Assets.xcassets/AppIcon.appiconset/Contents.json index d8db8d65f..c950192fe 100644 --- a/Example/mParticleExample/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/Example/mParticleExample/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,98 +1,98 @@ { - "images" : [ + "images": [ { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "2x" + "idiom": "iphone", + "size": "20x20", + "scale": "2x" }, { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "3x" + "idiom": "iphone", + "size": "20x20", + "scale": "3x" }, { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x" + "idiom": "iphone", + "size": "29x29", + "scale": "2x" }, { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "3x" + "idiom": "iphone", + "size": "29x29", + "scale": "3x" }, { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "2x" + "idiom": "iphone", + "size": "40x40", + "scale": "2x" }, { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "3x" + "idiom": "iphone", + "size": "40x40", + "scale": "3x" }, { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "2x" + "idiom": "iphone", + "size": "60x60", + "scale": "2x" }, { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "3x" + "idiom": "iphone", + "size": "60x60", + "scale": "3x" }, { - "idiom" : "ipad", - "size" : "20x20", - "scale" : "1x" + "idiom": "ipad", + "size": "20x20", + "scale": "1x" }, { - "idiom" : "ipad", - "size" : "20x20", - "scale" : "2x" + "idiom": "ipad", + "size": "20x20", + "scale": "2x" }, { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "1x" + "idiom": "ipad", + "size": "29x29", + "scale": "1x" }, { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "2x" + "idiom": "ipad", + "size": "29x29", + "scale": "2x" }, { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "1x" + "idiom": "ipad", + "size": "40x40", + "scale": "1x" }, { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "2x" + "idiom": "ipad", + "size": "40x40", + "scale": "2x" }, { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "1x" + "idiom": "ipad", + "size": "76x76", + "scale": "1x" }, { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "2x" + "idiom": "ipad", + "size": "76x76", + "scale": "2x" }, { - "idiom" : "ipad", - "size" : "83.5x83.5", - "scale" : "2x" + "idiom": "ipad", + "size": "83.5x83.5", + "scale": "2x" }, { - "idiom" : "ios-marketing", - "size" : "1024x1024", - "scale" : "1x" + "idiom": "ios-marketing", + "size": "1024x1024", + "scale": "1x" } ], - "info" : { - "version" : 1, - "author" : "xcode" + "info": { + "version": 1, + "author": "xcode" } -} \ No newline at end of file +} diff --git a/Example/mParticleExample/Assets.xcassets/Contents.json b/Example/mParticleExample/Assets.xcassets/Contents.json index da4a164c9..97a8662eb 100644 --- a/Example/mParticleExample/Assets.xcassets/Contents.json +++ b/Example/mParticleExample/Assets.xcassets/Contents.json @@ -1,6 +1,6 @@ { - "info" : { - "version" : 1, - "author" : "xcode" + "info": { + "version": 1, + "author": "xcode" } -} \ No newline at end of file +} diff --git a/Example/mParticleExample/Dummy.swift b/Example/mParticleExample/Dummy.swift index 90426c56c..632082624 100644 --- a/Example/mParticleExample/Dummy.swift +++ b/Example/mParticleExample/Dummy.swift @@ -1,5 +1,3 @@ import UIKit -class Dummy: NSObject { - -} +class Dummy: NSObject {} diff --git a/Package.swift b/Package.swift index 13f2618d9..5c38b0ab9 100644 --- a/Package.swift +++ b/Package.swift @@ -5,19 +5,22 @@ import PackageDescription let mParticle_Apple_SDK_URL = "https://static.mparticle.com/sdk/ios/v8.39.0/mParticle_Apple_SDK.xcframework.zip" let mParticle_Apple_SDK_Checksum = "8c6e6fb1891d844486a6be0c671875ec03a0b8457b3cef26bc4f7e3e4b866143" -let mParticle_Apple_SDK_NoLocation_URL = "https://static.mparticle.com/sdk/ios/v8.39.0/mParticle_Apple_SDK_NoLocation.xcframework.zip" +let mParticle_Apple_SDK_NoLocation_URL = + "https://static.mparticle.com/sdk/ios/v8.39.0/mParticle_Apple_SDK_NoLocation.xcframework.zip" let mParticle_Apple_SDK_NoLocation_Checksum = "7016efe3e47b2b2915dd8164f37dad34d1e3a5234e9ee9ecbd1ea4fd7903909e" let package = Package( name: "mParticle-Apple-SDK", - platforms: [ .iOS(.v9), .tvOS(.v9) ], + platforms: [.iOS(.v9), .tvOS(.v9)], products: [ .library( name: "mParticle-Apple-SDK", - targets: ["mParticle_Apple_SDK"]), + targets: ["mParticle_Apple_SDK"] + ), .library( name: "mParticle-Apple-SDK-NoLocation", - targets: ["mParticle_Apple_SDK_NoLocation"]), + targets: ["mParticle_Apple_SDK_NoLocation"] + ), ], dependencies: [ ], diff --git a/README.md b/README.md index 5382c835d..11054847e 100644 --- a/README.md +++ b/README.md @@ -16,9 +16,9 @@ read the [docs](https://docs.mparticle.com/developers/sdk/ios/) or contact us at This document will help you: -* Install the mParticle SDK using [CocoaPods](https://cocoapods.org/?q=mparticle) or [Carthage](https://github.com/Carthage/Carthage) -* Add any desired [kits](#currently-supported-kits) -* Initialize the mParticle SDK +- Install the mParticle SDK using [CocoaPods](https://cocoapods.org/?q=mparticle) or [Carthage](https://github.com/Carthage/Carthage) +- Add any desired [kits](#currently-supported-kits) +- Initialize the mParticle SDK ## Get the SDK @@ -31,7 +31,7 @@ To integrate the SDK using CocoaPods, specify it in your [Podfile](https://guide ```ruby target '' do pod 'mParticle-Apple-SDK', '~> 8' - + # If you'd like to use a version of the SDK that doesn't include any location tracking nor links the CoreLocation framework, use this subspec: # pod 'mParticle-Apple-SDK/mParticleNoLocation', '~> 8' end @@ -90,51 +90,50 @@ Enter the repository URL `https://github.com/mParticle/mparticle-apple-sdk` in t Then choose either the "Package Product" called `mParticle-Apple-SDK`, or if you'd like to use a version of the SDK that doesn't include any location tracking nor links the CoreLocation framework choose `mParticle-Apple-SDK-NoLocation`. -**IMPORTANT:** If you choose the `mParticle-Apple-SDK-NoLocation` package product, you will need to import the SDK using `import mParticle_Apple_SDK_NoLocation` instead of `import mParticle_Apple_SDK` as shown in the rest of the documentation and this README. +**IMPORTANT:** If you choose the `mParticle-Apple-SDK-NoLocation` package product, you will need to import the SDK using `import mParticle_Apple_SDK_NoLocation` instead of `import mParticle_Apple_SDK` as shown in the rest of the documentation and this README. #### Currently Supported Kits Several integrations require additional client-side add-on libraries called "kits." Some kits embed other SDKs, others just contain a bit of additional functionality. Kits are designed to feel just like server-side integrations; you enable, disable, filter, sample, and otherwise tweak kits completely from the mParticle platform UI. The Core SDK will detect kits at runtime, but you need to add them as dependencies to your app. -Kit | CocoaPods | Carthage | Swift Package Manager | -----|:---------:|:-------:|:-------:| -[Adjust](https://github.com/mparticle-integrations/mparticle-apple-integration-adjust) | ✓ | ✓ | ✓ -[Appboy](https://github.com/mparticle-integrations/mparticle-apple-integration-appboy) | ✓ | ✓ | ✓ -[Adobe](https://github.com/mparticle-integrations/mparticle-apple-integration-adobe) | ✓ | ✓ | ✓ -[AppsFlyer](https://github.com/mparticle-integrations/mparticle-apple-integration-appsflyer) | ✓ | ✓ | ✓ -[Appsee](https://github.com/mparticle-integrations/mparticle-apple-integration-appsee) | ✓ | | -[Apptentive](https://github.com/mparticle-integrations/mparticle-apple-integration-apptentive) | ✓ | ✓ | ✓ -[Apptimize](https://github.com/mparticle-integrations/mparticle-apple-integration-apptimize) | ✓ | ✓ | ✓ -[Apteligent](https://github.com/mparticle-integrations/mparticle-apple-integration-apteligent) | ✓ | | -[Blueshift](https://github.com/blueshift-labs/mparticle-apple-integration-blueshift) | ✓ | ✓ | -[Branch Metrics](https://github.com/mparticle-integrations/mparticle-apple-integration-branchmetrics) | ✓ | ✓ | ✓ -[Button](https://github.com/mparticle-integrations/mparticle-apple-integration-button) | ✓ | ✓ | ✓ -[CleverTap](https://github.com/mparticle-integrations/mparticle-apple-integration-clevertap) | ✓ | ✓ | ✓ -[comScore](https://github.com/mparticle-integrations/mparticle-apple-integration-comscore) | ✓ | | ✓ -[Flurry](https://github.com/mparticle-integrations/mparticle-apple-integration-flurry) | ✓ | | -[Foresee](https://github.com/mparticle-integrations/mparticle-apple-integration-foresee) | ✓ | | ✓ -[Google Analytics for Firebase](https://github.com/mparticle-integrations/mparticle-apple-integration-google-analytics-firebase) | ✓ | ✓ | ✓ -[Google Analytics 4 for Firebase](https://github.com/mparticle-integrations/mparticle-apple-integration-google-analytics-firebase-ga4) | ✓ | ✓ | ✓ -[Instabot](https://github.com/mparticle-integrations/mparticle-apple-integration-instabot) | ✓ | | -[Iterable](https://github.com/mparticle-integrations/mparticle-apple-integration-iterable) | ✓ | ✓ | ✓ -[Kochava](https://github.com/mparticle-integrations/mparticle-apple-integration-kochava) | | | ✓ -[Leanplum](https://github.com/mparticle-integrations/mparticle-apple-integration-leanplum) | ✓ | ✓ | ✓ -[Localytics](https://github.com/mparticle-integrations/mparticle-apple-integration-localytics) | ✓ | ✓ | ✓ -[Optimizely](https://github.com/mparticle-integrations/mparticle-apple-integration-optimizely) | ✓ | ✓ | ✓ -[OneTrust](https://github.com/mparticle-integrations/mparticle-apple-integration-onetrust) | ✓ | ✓ | ✓ -[Pilgrim](https://github.com/mparticle-integrations/mparticle-apple-integration-pilgrim) | ✓ | ✓ | -[Primer](https://github.com/mparticle-integrations/mparticle-apple-integration-primer) | ✓ | ✓ | -[Radar](https://github.com/mparticle-integrations/mparticle-apple-integration-radar) | ✓ | ✓ | ✓ -[Responsys](https://github.com/mparticle-integrations/mparticle-apple-integration-responsys) | ✓ | | -[Reveal Mobile](https://github.com/mparticle-integrations/mparticle-apple-integration-revealmobile) | ✓ | | -[Singular](https://github.com/mparticle-integrations/mparticle-apple-integration-singular) | ✓ | | ✓ -[Skyhook](https://github.com/mparticle-integrations/mparticle-apple-integration-skyhook) | ✓ | | -[Taplytics](https://github.com/mparticle-integrations/mparticle-apple-integration-taplytics) | ✓ | | ✓ -[Tune](https://github.com/mparticle-integrations/mparticle-apple-integration-tune) | ✓ | ✓ | -[Urban Airship](https://github.com/mparticle-integrations/mparticle-apple-integration-urbanairship) | ✓ | | ✓ -[UserLeap](https://github.com/UserLeap/userleap-mparticle-ios-kit) | ✓ | ✓ | -[Wootric](https://github.com/mparticle-integrations/mparticle-apple-integration-wootric) | ✓ | | - +| Kit | CocoaPods | Carthage | Swift Package Manager | +| -------------------------------------------------------------------------------------------------------------------------------------- | :-------: | :------: | :-------------------: | +| [Adjust](https://github.com/mparticle-integrations/mparticle-apple-integration-adjust) | ✓ | ✓ | ✓ | +| [Appboy](https://github.com/mparticle-integrations/mparticle-apple-integration-appboy) | ✓ | ✓ | ✓ | +| [Adobe](https://github.com/mparticle-integrations/mparticle-apple-integration-adobe) | ✓ | ✓ | ✓ | +| [AppsFlyer](https://github.com/mparticle-integrations/mparticle-apple-integration-appsflyer) | ✓ | ✓ | ✓ | +| [Appsee](https://github.com/mparticle-integrations/mparticle-apple-integration-appsee) | ✓ | | +| [Apptentive](https://github.com/mparticle-integrations/mparticle-apple-integration-apptentive) | ✓ | ✓ | ✓ | +| [Apptimize](https://github.com/mparticle-integrations/mparticle-apple-integration-apptimize) | ✓ | ✓ | ✓ | +| [Apteligent](https://github.com/mparticle-integrations/mparticle-apple-integration-apteligent) | ✓ | | +| [Blueshift](https://github.com/blueshift-labs/mparticle-apple-integration-blueshift) | ✓ | ✓ | +| [Branch Metrics](https://github.com/mparticle-integrations/mparticle-apple-integration-branchmetrics) | ✓ | ✓ | ✓ | +| [Button](https://github.com/mparticle-integrations/mparticle-apple-integration-button) | ✓ | ✓ | ✓ | +| [CleverTap](https://github.com/mparticle-integrations/mparticle-apple-integration-clevertap) | ✓ | ✓ | ✓ | +| [comScore](https://github.com/mparticle-integrations/mparticle-apple-integration-comscore) | ✓ | | ✓ | +| [Flurry](https://github.com/mparticle-integrations/mparticle-apple-integration-flurry) | ✓ | | +| [Foresee](https://github.com/mparticle-integrations/mparticle-apple-integration-foresee) | ✓ | | ✓ | +| [Google Analytics for Firebase](https://github.com/mparticle-integrations/mparticle-apple-integration-google-analytics-firebase) | ✓ | ✓ | ✓ | +| [Google Analytics 4 for Firebase](https://github.com/mparticle-integrations/mparticle-apple-integration-google-analytics-firebase-ga4) | ✓ | ✓ | ✓ | +| [Instabot](https://github.com/mparticle-integrations/mparticle-apple-integration-instabot) | ✓ | | +| [Iterable](https://github.com/mparticle-integrations/mparticle-apple-integration-iterable) | ✓ | ✓ | ✓ | +| [Kochava](https://github.com/mparticle-integrations/mparticle-apple-integration-kochava) | | | ✓ | +| [Leanplum](https://github.com/mparticle-integrations/mparticle-apple-integration-leanplum) | ✓ | ✓ | ✓ | +| [Localytics](https://github.com/mparticle-integrations/mparticle-apple-integration-localytics) | ✓ | ✓ | ✓ | +| [Optimizely](https://github.com/mparticle-integrations/mparticle-apple-integration-optimizely) | ✓ | ✓ | ✓ | +| [OneTrust](https://github.com/mparticle-integrations/mparticle-apple-integration-onetrust) | ✓ | ✓ | ✓ | +| [Pilgrim](https://github.com/mparticle-integrations/mparticle-apple-integration-pilgrim) | ✓ | ✓ | +| [Primer](https://github.com/mparticle-integrations/mparticle-apple-integration-primer) | ✓ | ✓ | +| [Radar](https://github.com/mparticle-integrations/mparticle-apple-integration-radar) | ✓ | ✓ | ✓ | +| [Responsys](https://github.com/mparticle-integrations/mparticle-apple-integration-responsys) | ✓ | | +| [Reveal Mobile](https://github.com/mparticle-integrations/mparticle-apple-integration-revealmobile) | ✓ | | +| [Singular](https://github.com/mparticle-integrations/mparticle-apple-integration-singular) | ✓ | | ✓ | +| [Skyhook](https://github.com/mparticle-integrations/mparticle-apple-integration-skyhook) | ✓ | | +| [Taplytics](https://github.com/mparticle-integrations/mparticle-apple-integration-taplytics) | ✓ | | ✓ | +| [Tune](https://github.com/mparticle-integrations/mparticle-apple-integration-tune) | ✓ | ✓ | +| [Urban Airship](https://github.com/mparticle-integrations/mparticle-apple-integration-urbanairship) | ✓ | | ✓ | +| [UserLeap](https://github.com/UserLeap/userleap-mparticle-ios-kit) | ✓ | ✓ | +| [Wootric](https://github.com/mparticle-integrations/mparticle-apple-integration-wootric) | ✓ | | ## Initialize the SDK @@ -148,10 +147,10 @@ The mParticle SDK is initialized by calling the `startWithOptions` method within import mParticle_Apple_SDK func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { - + // Override point for customization after application launch. let mParticleOptions = MParticleOptions(key: "<<>>", secret: "<<>>") - + //Please see the Identity page for more information on building this object let request = MPIdentityApiRequest() request.email = "email@example.com" @@ -159,10 +158,10 @@ func application(_ application: UIApplication, didFinishLaunchingWithOptions lau mParticleOptions.onIdentifyComplete = { (apiResult, error) in NSLog("Identify complete. userId = %@ error = %@", apiResult?.user.userId.stringValue ?? "Null User ID", error?.localizedDescription ?? "No Error Available") } - + //Start the SDK MParticle.sharedInstance().start(with: mParticleOptions) - + return true } ``` @@ -194,7 +193,7 @@ Next, you'll need to start the SDK: MParticleOptions *mParticleOptions = [MParticleOptions optionsWithKey:@"REPLACE ME" secret:@"REPLACE ME"]; - + //Please see the Identity page for more information on building this object MPIdentityApiRequest *request = [MPIdentityApiRequest requestWithEmptyUser]; request.email = @"email@example.com"; @@ -202,16 +201,15 @@ Next, you'll need to start the SDK: mParticleOptions.onIdentifyComplete = ^(MPIdentityApiResult * _Nullable apiResult, NSError * _Nullable error) { NSLog(@"Identify complete. userId = %@ error = %@", apiResult.user.userId, error); }; - + [[MParticle sharedInstance] startWithOptions:mParticleOptions]; - + return YES; } ``` Please see [Identity](http://docs.mparticle.com/developers/sdk/ios/identity/) for more information on supplying an `MPIdentityApiRequest` object during SDK initialization. - ## Example Project with Sample Code A sample project is provided with the mParticle Apple SDK. It is a multi-platform video streaming app for both iOS and tvOS. @@ -228,13 +226,11 @@ In order to run either the iOS or tvOS examples, first install the mParticle App 2. Run `pod install` 3. Open **Example.xcworkspace** in Xcode, select either the **iOS_Example** or **tvOS_Example** scheme, build and run. - ## Read More Just by initializing the SDK you'll be set up to track user installs, engagement, and much more. Check out our doc site to learn how to add specific event tracking to your app. -* [SDK Documentation](http://docs.mparticle.com/#mobile-sdk-guide) - +- [SDK Documentation](http://docs.mparticle.com/#mobile-sdk-guide) ## Support diff --git a/RNExample/README.md b/RNExample/README.md index 12470c30e..8bd066df0 100644 --- a/RNExample/README.md +++ b/RNExample/README.md @@ -2,7 +2,7 @@ This is a new [**React Native**](https://reactnative.dev) project, bootstrapped # Getting Started ->**Note**: Make sure you have completed the [React Native - Environment Setup](https://reactnative.dev/docs/environment-setup) instructions till "Creating a new application" step, before proceeding. +> **Note**: Make sure you have completed the [React Native - Environment Setup](https://reactnative.dev/docs/environment-setup) instructions till "Creating a new application" step, before proceeding. ## Step 1: Start the Metro Server diff --git a/RNExample/ios/RNExample/Images.xcassets/AppIcon.appiconset/Contents.json b/RNExample/ios/RNExample/Images.xcassets/AppIcon.appiconset/Contents.json index 81213230d..ddd7fca89 100644 --- a/RNExample/ios/RNExample/Images.xcassets/AppIcon.appiconset/Contents.json +++ b/RNExample/ios/RNExample/Images.xcassets/AppIcon.appiconset/Contents.json @@ -1,53 +1,53 @@ { - "images" : [ + "images": [ { - "idiom" : "iphone", - "scale" : "2x", - "size" : "20x20" + "idiom": "iphone", + "scale": "2x", + "size": "20x20" }, { - "idiom" : "iphone", - "scale" : "3x", - "size" : "20x20" + "idiom": "iphone", + "scale": "3x", + "size": "20x20" }, { - "idiom" : "iphone", - "scale" : "2x", - "size" : "29x29" + "idiom": "iphone", + "scale": "2x", + "size": "29x29" }, { - "idiom" : "iphone", - "scale" : "3x", - "size" : "29x29" + "idiom": "iphone", + "scale": "3x", + "size": "29x29" }, { - "idiom" : "iphone", - "scale" : "2x", - "size" : "40x40" + "idiom": "iphone", + "scale": "2x", + "size": "40x40" }, { - "idiom" : "iphone", - "scale" : "3x", - "size" : "40x40" + "idiom": "iphone", + "scale": "3x", + "size": "40x40" }, { - "idiom" : "iphone", - "scale" : "2x", - "size" : "60x60" + "idiom": "iphone", + "scale": "2x", + "size": "60x60" }, { - "idiom" : "iphone", - "scale" : "3x", - "size" : "60x60" + "idiom": "iphone", + "scale": "3x", + "size": "60x60" }, { - "idiom" : "ios-marketing", - "scale" : "1x", - "size" : "1024x1024" + "idiom": "ios-marketing", + "scale": "1x", + "size": "1024x1024" } ], - "info" : { - "author" : "xcode", - "version" : 1 + "info": { + "author": "xcode", + "version": 1 } } diff --git a/RNExample/ios/RNExample/Images.xcassets/Contents.json b/RNExample/ios/RNExample/Images.xcassets/Contents.json index 2d92bd53f..97a8662eb 100644 --- a/RNExample/ios/RNExample/Images.xcassets/Contents.json +++ b/RNExample/ios/RNExample/Images.xcassets/Contents.json @@ -1,6 +1,6 @@ { - "info" : { - "version" : 1, - "author" : "xcode" + "info": { + "version": 1, + "author": "xcode" } } diff --git a/Scripts/carthage.sh b/Scripts/carthage.sh index 6edeb4209..03ca3e423 100755 --- a/Scripts/carthage.sh +++ b/Scripts/carthage.sh @@ -17,17 +17,17 @@ CURRENT_XCODE_VERSION=$(xcodebuild -version | grep "Build version" | cut -d' ' - EXCLUDED_ARCHS_SIMULATOR="arm64 arm64e armv7 armv7s armv6 armv8" # Xcode 14 -echo "EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1400 = $EXCLUDED_ARCHS_SIMULATOR" >> $xcconfig -echo "EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1400__BUILD_$CURRENT_XCODE_VERSION = $EXCLUDED_ARCHS_SIMULATOR" >> $xcconfig -echo "EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_arm64__XCODE_1400 = $EXCLUDED_ARCHS_SIMULATOR" >> $xcconfig -echo "EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_arm64__XCODE_1400__BUILD_$CURRENT_XCODE_VERSION = $EXCLUDED_ARCHS_SIMULATOR" >> $xcconfig +echo "EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1400 = $EXCLUDED_ARCHS_SIMULATOR" >>$xcconfig +echo "EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1400__BUILD_$CURRENT_XCODE_VERSION = $EXCLUDED_ARCHS_SIMULATOR" >>$xcconfig +echo "EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_arm64__XCODE_1400 = $EXCLUDED_ARCHS_SIMULATOR" >>$xcconfig +echo "EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_arm64__XCODE_1400__BUILD_$CURRENT_XCODE_VERSION = $EXCLUDED_ARCHS_SIMULATOR" >>$xcconfig # Xcode 15 -echo "EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1500 = $EXCLUDED_ARCHS_SIMULATOR" >> $xcconfig -echo "EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1500__BUILD_$CURRENT_XCODE_VERSION = $EXCLUDED_ARCHS_SIMULATOR" >> $xcconfig -echo "EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_arm64__XCODE_1500 = $EXCLUDED_ARCHS_SIMULATOR" >> $xcconfig -echo "EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_arm64__XCODE_1500__BUILD_$CURRENT_XCODE_VERSION = $EXCLUDED_ARCHS_SIMULATOR" >> $xcconfig +echo "EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1500 = $EXCLUDED_ARCHS_SIMULATOR" >>$xcconfig +echo "EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1500__BUILD_$CURRENT_XCODE_VERSION = $EXCLUDED_ARCHS_SIMULATOR" >>$xcconfig +echo "EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_arm64__XCODE_1500 = $EXCLUDED_ARCHS_SIMULATOR" >>$xcconfig +echo "EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_arm64__XCODE_1500__BUILD_$CURRENT_XCODE_VERSION = $EXCLUDED_ARCHS_SIMULATOR" >>$xcconfig -echo 'EXCLUDED_ARCHS = $(inherited) $(EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_$(EFFECTIVE_PLATFORM_SUFFIX)__NATIVE_ARCH_64_BIT_$(NATIVE_ARCH_64_BIT)__XCODE_$(XCODE_VERSION_MAJOR))' >> $xcconfig +echo 'EXCLUDED_ARCHS = $(inherited) $(EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_$(EFFECTIVE_PLATFORM_SUFFIX)__NATIVE_ARCH_64_BIT_$(NATIVE_ARCH_64_BIT)__XCODE_$(XCODE_VERSION_MAJOR))' >>$xcconfig export XCODE_XCCONFIG_FILE="$xcconfig" carthage "$@" diff --git a/Scripts/check_coverage.sh b/Scripts/check_coverage.sh index 94b696b26..694d8168e 100755 --- a/Scripts/check_coverage.sh +++ b/Scripts/check_coverage.sh @@ -8,13 +8,13 @@ RESULT_BUNDLE_PATH="./build/TestResults.xcresult" rm -rf "$RESULT_BUNDLE_PATH" xcodebuild test \ - -project ../mParticle-Apple-SDK.xcodeproj \ - -scheme "$SCHEME" \ - -destination "$DESTINATION" \ - -enableCodeCoverage YES \ - -resultBundlePath "$RESULT_BUNDLE_PATH" \ - -xcrun xccov view --report --json "$RESULT_BUNDLE_PATH" > ./build/coverage.json + -project ../mParticle-Apple-SDK.xcodeproj \ + -scheme "$SCHEME" \ + -destination "$DESTINATION" \ + -enableCodeCoverage YES \ + -resultBundlePath "$RESULT_BUNDLE_PATH" + +xcrun xccov view --report --json "$RESULT_BUNDLE_PATH" >./build/coverage.json python check_coverage.py diff --git a/Scripts/make_artifacts.sh b/Scripts/make_artifacts.sh index e65034dba..f37cab4e9 100755 --- a/Scripts/make_artifacts.sh +++ b/Scripts/make_artifacts.sh @@ -9,55 +9,55 @@ # --- Functions --- function build_framework_artifacts() { - # Build old school "fat" frameworks for iOS and tvOS, both regular and no location builds - ./Scripts/carthage.sh build --no-skip-current + # Build old school "fat" frameworks for iOS and tvOS, both regular and no location builds + ./Scripts/carthage.sh build --no-skip-current - # Zip the Carthage frameworks (includes both platforms in each zip file) - carthage archive mParticle_Apple_SDK - carthage archive mParticle_Apple_SDK_NoLocation + # Zip the Carthage frameworks (includes both platforms in each zip file) + carthage archive mParticle_Apple_SDK + carthage archive mParticle_Apple_SDK_NoLocation - # Clean up temp files - rm -rf Carthage + # Clean up temp files + rm -rf Carthage } function build_xcframework_artifacts() { - # Build modern xcframeworks which work on M1 macs and include both platforms in one package - ./Scripts/xcframework.sh mParticle-Apple-SDK mParticle_Apple_SDK - ./Scripts/xcframework.sh mParticle-Apple-SDK-NoLocation mParticle_Apple_SDK_NoLocation + # Build modern xcframeworks which work on M1 macs and include both platforms in one package + ./Scripts/xcframework.sh mParticle-Apple-SDK mParticle_Apple_SDK + ./Scripts/xcframework.sh mParticle-Apple-SDK-NoLocation mParticle_Apple_SDK_NoLocation - # Sign the xcframeworks - codesign --timestamp -s "Apple Distribution: mParticle, inc (DLD43Y3TRP)" mParticle_Apple_SDK.xcframework - codesign --timestamp -s "Apple Distribution: mParticle, inc (DLD43Y3TRP)" mParticle_Apple_SDK_NoLocation.xcframework + # Sign the xcframeworks + codesign --timestamp -s "Apple Distribution: mParticle, inc (DLD43Y3TRP)" mParticle_Apple_SDK.xcframework + codesign --timestamp -s "Apple Distribution: mParticle, inc (DLD43Y3TRP)" mParticle_Apple_SDK_NoLocation.xcframework - # Zip the xcframeworks - zip -r mParticle_Apple_SDK.xcframework.zip mParticle_Apple_SDK.xcframework - zip -r mParticle_Apple_SDK_NoLocation.xcframework.zip mParticle_Apple_SDK_NoLocation.xcframework + # Zip the xcframeworks + zip -r mParticle_Apple_SDK.xcframework.zip mParticle_Apple_SDK.xcframework + zip -r mParticle_Apple_SDK_NoLocation.xcframework.zip mParticle_Apple_SDK_NoLocation.xcframework - # Clean up temp files - rm -rf archives mParticle_Apple_SDK.xcframework mParticle_Apple_SDK_NoLocation.xcframework + # Clean up temp files + rm -rf archives mParticle_Apple_SDK.xcframework mParticle_Apple_SDK_NoLocation.xcframework } function build_docs_artifact() { - local repo_dir="$(pwd)" - local temp_dir="$HOME/temp" + local repo_dir="$(pwd)" + local temp_dir="$HOME/temp" - # Install appledoc - mkdir -p "$temp_dir" - cd "$temp_dir" - git clone https://github.com/mparticle/appledoc - cd appledoc - sudo sh install-appledoc.sh - cd "$repo_dir" + # Install appledoc + mkdir -p "$temp_dir" + cd "$temp_dir" + git clone https://github.com/mparticle/appledoc + cd appledoc + sudo sh install-appledoc.sh + cd "$repo_dir" - # Try to generate docs, but don't fail the release if it has issues - if appledoc --exit-threshold=0 "./Scripts/AppledocSettings.plist"; then - ditto -c -k --sequesterRsrc --keepParent "./Docs/html" "$repo_dir/generated-docs.zip" - else - echo "Documentation generation failed, creating empty docs archive" - mkdir -p ./Docs/html - echo "Documentation generation failed" > ./Docs/html/index.html - ditto -c -k --sequesterRsrc --keepParent "./Docs/html" "$repo_dir/generated-docs.zip" - fi + # Try to generate docs, but don't fail the release if it has issues + if appledoc --exit-threshold=0 "./Scripts/AppledocSettings.plist"; then + ditto -c -k --sequesterRsrc --keepParent "./Docs/html" "$repo_dir/generated-docs.zip" + else + echo "Documentation generation failed, creating empty docs archive" + mkdir -p ./Docs/html + echo "Documentation generation failed" >./Docs/html/index.html + ditto -c -k --sequesterRsrc --keepParent "./Docs/html" "$repo_dir/generated-docs.zip" + fi } # --- Main --- diff --git a/Scripts/release.sh b/Scripts/release.sh index c6d7b83bd..90bd74cf6 100755 --- a/Scripts/release.sh +++ b/Scripts/release.sh @@ -3,7 +3,7 @@ PREFIXED_VERSION="v$1" NOTES="$2" # Update version number -# +# # Update constant in codebase sed -i '' 's/NSString \*const kMParticleSDKVersion = @".*/NSString *const kMParticleSDKVersion = @"'"$VERSION"'";/' mParticle-Apple-SDK/MPIConstants.m @@ -13,7 +13,7 @@ sed -i '' 's/let kMParticleSDKVersion = ".*/let kMParticleSDKVersion = "'"$VERSI /usr/libexec/PlistBuddy -c "Set CFBundleShortVersionString $VERSION" Framework/Info.plist # Update Carthage release json file -jq --indent 3 '. += {'"\"$VERSION\""': "'"https://github.com/mParticle/mparticle-apple-sdk/releases/download/$PREFIXED_VERSION/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/$PREFIXED_VERSION/mParticle_Apple_SDK.xcframework.zip"'"}' mParticle_Apple_SDK.json > tmp.json +jq --indent 3 '. += {'"\"$VERSION\""': "'"https://github.com/mParticle/mparticle-apple-sdk/releases/download/$PREFIXED_VERSION/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/$PREFIXED_VERSION/mParticle_Apple_SDK.xcframework.zip"'"}' mParticle_Apple_SDK.json >tmp.json mv tmp.json mParticle_Apple_SDK.json # Update CocoaPods podspec file @@ -63,18 +63,18 @@ echo "Checking for generated artifacts..." missing_files=0 for file in mParticle_Apple_SDK.framework.zip mParticle_Apple_SDK_NoLocation.framework.zip mParticle_Apple_SDK.xcframework.zip mParticle_Apple_SDK_NoLocation.xcframework.zip generated-docs.zip; do - if [ -f "$file" ]; then - echo "✓ $file exists" - else - echo "⚠ $file is missing" - missing_files=$((missing_files + 1)) - fi + if [ -f "$file" ]; then + echo "✓ $file exists" + else + echo "⚠ $file is missing" + missing_files=$((missing_files + 1)) + fi done if [ $missing_files -gt 0 ]; then - echo "Warning: $missing_files artifact file(s) are missing, but continuing with release..." + echo "Warning: $missing_files artifact file(s) are missing, but continuing with release..." else - echo "All artifact files generated successfully!" + echo "All artifact files generated successfully!" fi # Always succeed to allow the release to continue diff --git a/Scripts/xcframework.sh b/Scripts/xcframework.sh index 78045b281..d3219f896 100755 --- a/Scripts/xcframework.sh +++ b/Scripts/xcframework.sh @@ -3,7 +3,7 @@ # # xcframework.sh # Paramaters: ./xcframework.sh [scheme] -# Usage examples: +# Usage examples: # ./xcframework.sh mParticle-Apple-SDK # ./xcframework.sh mParticle-Apple-SDK-NoLocation # @@ -18,8 +18,8 @@ xcodebuild archive -project mParticle-Apple-SDK.xcodeproj -scheme $SCHEME -desti xcodebuild archive -project mParticle-Apple-SDK.xcodeproj -scheme $SCHEME -destination "generic/platform=tvOS" -archivePath "archives/$SCHEME-tvOS" xcodebuild archive -project mParticle-Apple-SDK.xcodeproj -scheme $SCHEME -destination "generic/platform=tvOS Simulator" -archivePath "archives/$SCHEME-tvOS_Simulator" xcodebuild -create-xcframework \ - -archive archives/$SCHEME-iOS.xcarchive -framework $MODULE.framework \ - -archive archives/$SCHEME-iOS_Simulator.xcarchive -framework $MODULE.framework \ - -archive archives/$SCHEME-tvOS.xcarchive -framework $MODULE.framework \ - -archive archives/$SCHEME-tvOS_Simulator.xcarchive -framework $MODULE.framework \ - -output $MODULE.xcframework + -archive archives/$SCHEME-iOS.xcarchive -framework $MODULE.framework \ + -archive archives/$SCHEME-iOS_Simulator.xcarchive -framework $MODULE.framework \ + -archive archives/$SCHEME-tvOS.xcarchive -framework $MODULE.framework \ + -archive archives/$SCHEME-tvOS_Simulator.xcarchive -framework $MODULE.framework \ + -output $MODULE.xcframework diff --git a/UnitTests/JSON/sample_dataplan2.json b/UnitTests/JSON/sample_dataplan2.json index bc570bd65..1b5c6e23f 100644 --- a/UnitTests/JSON/sample_dataplan2.json +++ b/UnitTests/JSON/sample_dataplan2.json @@ -1,224 +1,200 @@ { - "version_document":{ - "data_points":[ + "version_document": { + "data_points": [ { - "description":"a search event with a basic name", - "match":{ - "type":"custom_event", - "criteria":{ - "event_name":"Search Event", - "custom_event_type":"search" + "description": "a search event with a basic name", + "match": { + "type": "custom_event", + "criteria": { + "event_name": "Search Event", + "custom_event_type": "search" } }, - "validator":{ - "type":"json_schema", - "definition":{ - "properties":{ - "data":{ - "additionalProperties":true, - "properties":{ - "custom_event_type":{ - "description":"", - "type":"string" + "validator": { + "type": "json_schema", + "definition": { + "properties": { + "data": { + "additionalProperties": true, + "properties": { + "custom_event_type": { + "description": "", + "type": "string" }, - "event_name":{ - "description":"", - "type":"string" + "event_name": { + "description": "", + "type": "string" }, - "custom_attributes":{ - "additionalProperties":true, - "description":"", - "properties":{ - "hello":{ - "description":"", - "type":"string" + "custom_attributes": { + "additionalProperties": true, + "description": "", + "properties": { + "hello": { + "description": "", + "type": "string" } }, - "required":[ - - ], - "type":"object" + "required": [], + "type": "object" } }, - "required":[ - "custom_event_type", - "event_name" - ], - "type":"object" + "required": ["custom_event_type", "event_name"], + "type": "object" } } } } }, { - "description":"no description for this location event", - "match":{ - "type":"custom_event", - "criteria":{ - "event_name":"locationEvent", - "custom_event_type":"location" + "description": "no description for this location event", + "match": { + "type": "custom_event", + "criteria": { + "event_name": "locationEvent", + "custom_event_type": "location" } }, - "validator":{ - "type":"json_schema", - "definition":{ - "properties":{ - "data":{ - "additionalProperties":true, - "properties":{ - "custom_event_type":{ - "description":"", - "type":"string" + "validator": { + "type": "json_schema", + "definition": { + "properties": { + "data": { + "additionalProperties": true, + "properties": { + "custom_event_type": { + "description": "", + "type": "string" }, - "event_name":{ - "description":"", - "type":"string" + "event_name": { + "description": "", + "type": "string" }, - "custom_attributes":{ - "additionalProperties":false, - "description":"", - "properties":{ - "foo":{ - "description":"", - "enum":[ - "bar", - "barr", - "bar bar" - ], - "type":"string" + "custom_attributes": { + "additionalProperties": false, + "description": "", + "properties": { + "foo": { + "description": "", + "enum": ["bar", "barr", "bar bar"], + "type": "string" }, - "foo foo":{ - "description":"", - "maximum":5, - "minimum":0, - "type":"number" + "foo foo": { + "description": "", + "maximum": 5, + "minimum": 0, + "type": "number" }, - "foo number":{ - "description":"", - "enum":[ - "10", - "20", - "30" - ], - "type":"number" + "foo number": { + "description": "", + "enum": ["10", "20", "30"], + "type": "number" } }, - "required":[ - - ], - "type":"object" + "required": [], + "type": "object" } }, - "required":[ - "custom_event_type", - "event_name" - ], - "type":"object" + "required": ["custom_event_type", "event_name"], + "type": "object" } } } } }, { - "description": "", - "match": { - "type": "product_action", - "criteria": { - "action": "remove_from_wish_list" - } - }, - "validator": { - "type": "json_schema", - "definition": { - "properties": { - "data": { - "additionalProperties": true, - "properties": { - "custom_attributes": { - "additionalProperties": false, - "description": "", - "properties": { - "com_attribute_2": { - "description": "", - "type": "string" - }, - "com_attribute_1": { - "description": "", - "type": "string" - } - }, - "required": [], - "type": "object" - }, - "product_action": { + "description": "", + "match": { + "type": "product_action", + "criteria": { + "action": "remove_from_wish_list" + } + }, + "validator": { + "type": "json_schema", + "definition": { + "properties": { + "data": { + "additionalProperties": true, + "properties": { + "custom_attributes": { + "additionalProperties": false, + "description": "", + "properties": { + "com_attribute_2": { + "description": "", + "type": "string" + }, + "com_attribute_1": { + "description": "", + "type": "string" + } + }, + "required": [], + "type": "object" + }, + "product_action": { + "additionalProperties": false, + "description": "", + "properties": { + "products": { + "description": "", + "items": { "additionalProperties": false, "description": "", "properties": { - "products": { + "custom_attributes": { + "additionalProperties": false, "description": "", - "items": { - "additionalProperties": false, - "description": "", - "properties": { - "custom_attributes": { - "additionalProperties": false, - "description": "", - "properties": { - "prodact_prod_attribute2": { - "description": "", - "type": "string" - }, - "prodact_prod_attribute1": { - "description": "", - "type": "string" - } - }, - "required": [], - "type": "object" - } + "properties": { + "prodact_prod_attribute2": { + "description": "", + "type": "string" }, - "required": [], - "type": "object" + "prodact_prod_attribute1": { + "description": "", + "type": "string" + } }, - "type": "array" + "required": [], + "type": "object" } }, "required": [], "type": "object" }, - "product_impressions": { + "type": "array" + } + }, + "required": [], + "type": "object" + }, + "product_impressions": { + "description": "", + "items": { + "additionalProperties": false, + "description": "", + "properties": { + "products": { "description": "", "items": { "additionalProperties": false, "description": "", "properties": { - "products": { + "custom_attributes": { + "additionalProperties": false, "description": "", - "items": { - "additionalProperties": false, - "description": "", - "properties": { - "custom_attributes": { - "additionalProperties": false, - "description": "", - "properties": { - "impr_prod_attribute2": { - "description": "", - "type": "string" - }, - "impr_prod_attribute1": { - "description": "", - "type": "string" - } - }, - "required": [], - "type": "object" - } + "properties": { + "impr_prod_attribute2": { + "description": "", + "type": "string" }, - "required": [], - "type": "object" + "impr_prod_attribute1": { + "description": "", + "type": "string" + } }, - "type": "array" + "required": [], + "type": "object" } }, "required": [], @@ -229,609 +205,544 @@ }, "required": [], "type": "object" - } + }, + "type": "array" } - } + }, + "required": [], + "type": "object" } - }, + } + } + } + }, { - "description":"this commerce event has product attributes and allow additional attributes for event custom attributes and product custom attributes", - "match":{ - "type":"product_action", - "criteria":{ - "action":"add_to_cart" + "description": "this commerce event has product attributes and allow additional attributes for event custom attributes and product custom attributes", + "match": { + "type": "product_action", + "criteria": { + "action": "add_to_cart" } }, - "validator":{ - "type":"json_schema", - "definition":{ - "properties":{ - "data":{ - "additionalProperties":true, - "properties":{ - "currency_code":{ - "description":"", - "enum":[ - "USD", - "CAD", - "AUS" - ], - "type":"string" + "validator": { + "type": "json_schema", + "definition": { + "properties": { + "data": { + "additionalProperties": true, + "properties": { + "currency_code": { + "description": "", + "enum": ["USD", "CAD", "AUS"], + "type": "string" }, - "custom_attributes":{ - "additionalProperties":false, - "description":"", - "properties":{ - "attributeNumMinMax":{ - "description":"", - "maximum":17, - "minimum":9, - "type":"number" + "custom_attributes": { + "additionalProperties": false, + "description": "", + "properties": { + "attributeNumMinMax": { + "description": "", + "maximum": 17, + "minimum": 9, + "type": "number" }, - "attributeEmail":{ - "description":"", - "format":"email", - "type":"string" + "attributeEmail": { + "description": "", + "format": "email", + "type": "string" }, - "attributeNumEnum":{ - "description":"", - "enum":[ - "2", - "7", - "9" - ], - "type":"number" + "attributeNumEnum": { + "description": "", + "enum": ["2", "7", "9"], + "type": "number" }, - "attributeStringAlpha":{ - "description":"", - "pattern":"[AZ]", - "type":"string" + "attributeStringAlpha": { + "description": "", + "pattern": "[AZ]", + "type": "string" }, - "attributeBoolean":{ - "description":"", - "type":"boolean" + "attributeBoolean": { + "description": "", + "type": "boolean" } }, - "required":[ - - ], - "type":"object" + "required": [], + "type": "object" }, - "product_action":{ - "additionalProperties":false, - "description":"", - "properties":{ - "products":{ - "description":"", - "items":{ - "additionalProperties":true, - "description":"", - "properties":{ - "custom_attributes":{ - "additionalProperties":true, - "description":"", - "properties":{ - "plannedAttr2":{ - "description":"", - "type":"string" + "product_action": { + "additionalProperties": false, + "description": "", + "properties": { + "products": { + "description": "", + "items": { + "additionalProperties": true, + "description": "", + "properties": { + "custom_attributes": { + "additionalProperties": true, + "description": "", + "properties": { + "plannedAttr2": { + "description": "", + "type": "string" }, - "plannedAttr1":{ - "description":"", - "type":"string" + "plannedAttr1": { + "description": "", + "type": "string" } }, - "required":[ - - ], - "type":"object" + "required": [], + "type": "object" } }, - "required":[ - - ], - "type":"object" + "required": [], + "type": "object" }, - "type":"array" + "type": "array" } }, - "required":[ - - ], - "type":"object" + "required": [], + "type": "object" } }, - "required":[ - - ], - "type":"object" + "required": [], + "type": "object" } } } } }, { - "description":"view.a product", - "match":{ - "type":"promotion_action", - "criteria":{ - "action":"view" + "description": "view.a product", + "match": { + "type": "promotion_action", + "criteria": { + "action": "view" } }, - "validator":{ - "type":"json_schema", - "definition":{ - "properties":{ - "data":{ - "additionalProperties":true, - "properties":{ - "custom_attributes":{ - "additionalProperties":false, - "description":"", - "properties":{ - "not required":{ - "description":"", - "type":"string" + "validator": { + "type": "json_schema", + "definition": { + "properties": { + "data": { + "additionalProperties": true, + "properties": { + "custom_attributes": { + "additionalProperties": false, + "description": "", + "properties": { + "not required": { + "description": "", + "type": "string" }, - "required":{ - "description":"", - "type":"string" + "required": { + "description": "", + "type": "string" } }, - "required":[ - "required" - ], - "type":"object" + "required": ["required"], + "type": "object" } }, - "required":[ - "custom_attributes" - ], - "type":"object" + "required": ["custom_attributes"], + "type": "object" } } } } }, { - "description":"", - "match":{ - "type":"custom_event", - "criteria":{ - "event_name":"TestEvent", - "custom_event_type":"navigation" + "description": "", + "match": { + "type": "custom_event", + "criteria": { + "event_name": "TestEvent", + "custom_event_type": "navigation" } }, - "validator":{ - "type":"json_schema", - "definition":{ - "properties":{ - "data":{ - "additionalProperties":true, - "properties":{ - "canonical_name":{ - "description":"", - "enum":[ - "This", - "That" - ], - "type":"string" + "validator": { + "type": "json_schema", + "definition": { + "properties": { + "data": { + "additionalProperties": true, + "properties": { + "canonical_name": { + "description": "", + "enum": ["This", "That"], + "type": "string" } }, - "required":[ - - ], - "type":"object" + "required": [], + "type": "object" } } } } }, { - "description":"", - "match":{ - "type":"product_impression", - "criteria":{ - - } + "description": "", + "match": { + "type": "product_impression", + "criteria": {} }, - "validator":{ - "type":"json_schema", - "definition":{ - "properties":{ - "data":{ - "additionalProperties":true, - "properties":{ - "custom_flags":{ - "additionalProperties":false, - "description":"", - "properties":{ - "NotSoCustomFlag":{ - "description":"", - "type":"boolean" + "validator": { + "type": "json_schema", + "definition": { + "properties": { + "data": { + "additionalProperties": true, + "properties": { + "custom_flags": { + "additionalProperties": false, + "description": "", + "properties": { + "NotSoCustomFlag": { + "description": "", + "type": "boolean" } }, - "required":[ - - ], - "type":"object" + "required": [], + "type": "object" }, - "custom_attributes":{ - "additionalProperties":false, - "description":"", - "properties":{ - "thing1":{ - "description":"", - "type":"string" + "custom_attributes": { + "additionalProperties": false, + "description": "", + "properties": { + "thing1": { + "description": "", + "type": "string" } }, - "required":[ - "thing1" - ], - "type":"object" + "required": ["thing1"], + "type": "object" } }, - "required":[ - "custom_attributes" - ], - "type":"object" + "required": ["custom_attributes"], + "type": "object" } } } } }, { - "description":"", - "match":{ - "type":"screen_view", - "criteria":{ - "screen_name":"A New ScreenViewEvent" + "description": "", + "match": { + "type": "screen_view", + "criteria": { + "screen_name": "A New ScreenViewEvent" } }, - "validator":{ - "type":"json_schema", - "definition":{ - "properties":{ - "data":{ - "additionalProperties":true, - "properties":{ - "activity_type":{ - "description":"", - "pattern":"[a-z]", - "type":"string" + "validator": { + "type": "json_schema", + "definition": { + "properties": { + "data": { + "additionalProperties": true, + "properties": { + "activity_type": { + "description": "", + "pattern": "[a-z]", + "type": "string" } }, - "required":[ - - ], - "type":"object" + "required": [], + "type": "object" } } } } }, { - "description":"", - "match":{ - "type":"screen_view", - "criteria":{ - "screen_name":"my screeeen" + "description": "", + "match": { + "type": "screen_view", + "criteria": { + "screen_name": "my screeeen" } }, - "validator":{ - "type":"json_schema", - "definition":{ - "properties":{ - "data":{ - "additionalProperties":true, - "properties":{ - "custom_attributes":{ - "additionalProperties":false, - "description":"", - "properties":{ - "test2key":{ - "description":"", - "type":"string" + "validator": { + "type": "json_schema", + "definition": { + "properties": { + "data": { + "additionalProperties": true, + "properties": { + "custom_attributes": { + "additionalProperties": false, + "description": "", + "properties": { + "test2key": { + "description": "", + "type": "string" }, - "test1key":{ - "description":"", - "type":"string" + "test1key": { + "description": "", + "type": "string" } }, - "required":[ - - ], - "type":"object" + "required": [], + "type": "object" } }, - "required":[ - - ], - "type":"object" + "required": [], + "type": "object" } } } } }, { - "description":"", - "match":{ - "type":"custom_event", - "criteria":{ - "event_name":"something something something", - "custom_event_type":"navigation" + "description": "", + "match": { + "type": "custom_event", + "criteria": { + "event_name": "something something something", + "custom_event_type": "navigation" } }, - "validator":{ - "type":"json_schema", - "definition":{ - "properties":{ - "data":{ - "additionalProperties":true, - "properties":{ - "custom_attributes":{ - "additionalProperties":true, - "description":"", - "type":"object" + "validator": { + "type": "json_schema", + "definition": { + "properties": { + "data": { + "additionalProperties": true, + "properties": { + "custom_attributes": { + "additionalProperties": true, + "description": "", + "type": "object" } }, - "required":[ - - ], - "type":"object" + "required": [], + "type": "object" } } } } }, { - "description":"User Attributes", - "match":{ - "type":"user_attributes", - "criteria":{ - - } + "description": "User Attributes", + "match": { + "type": "user_attributes", + "criteria": {} }, - "validator":{ - "type":"json_schema", - "definition":{ - "additionalProperties":false, - "properties":{ - "my attribute":{ - "description":"", - "type":"string" + "validator": { + "type": "json_schema", + "definition": { + "additionalProperties": false, + "properties": { + "my attribute": { + "description": "", + "type": "string" }, - "my other attribute":{ - "description":"", - "type":"string" + "my other attribute": { + "description": "", + "type": "string" }, - "a third attribute":{ - "description":"", - "type":"string" + "a third attribute": { + "description": "", + "type": "string" } }, - "required":[ - "my other attribute" - ] + "required": ["my other attribute"] } }, - "active_transformation_ids":[ - - ] + "active_transformation_ids": [] }, { - "description":"User Identities", - "match":{ - "type":"user_identities", - "criteria":{ - - } + "description": "User Identities", + "match": { + "type": "user_identities", + "criteria": {} }, - "validator":{ - "type":"json_schema", - "definition":{ - "additionalProperties":true, - "properties":{ - "customerid":{ - "description":"", - "type":"string" + "validator": { + "type": "json_schema", + "definition": { + "additionalProperties": true, + "properties": { + "customerid": { + "description": "", + "type": "string" }, - "amp_id":{ - "description":"", - "type":"string" + "amp_id": { + "description": "", + "type": "string" }, - "email":{ - "description":"", - "type":"string" + "email": { + "description": "", + "type": "string" } }, - "required":[ - "email" - ], - "type":"object" + "required": ["email"], + "type": "object" } } }, { - "description":"", - "match":{ - "type":"custom_event", - "criteria":{ - "event_name":"SocialEvent", - "custom_event_type":"social" + "description": "", + "match": { + "type": "custom_event", + "criteria": { + "event_name": "SocialEvent", + "custom_event_type": "social" } }, - "validator":{ - "type":"json_schema", - "definition":{ - "properties":{ - "data":{ - "additionalProperties":true, - "properties":{ - "custom_attributes":{ - "additionalProperties":false, - "description":"", - "type":"object" + "validator": { + "type": "json_schema", + "definition": { + "properties": { + "data": { + "additionalProperties": true, + "properties": { + "custom_attributes": { + "additionalProperties": false, + "description": "", + "type": "object" } }, - "required":[ - - ], - "type":"object" + "required": [], + "type": "object" } } } } }, { - "description":"this commerce event has product attributes and not allowing additional product attributes for event custom attributes and product custom attributes", - "match":{ - "type":"product_action", - "criteria":{ - "action":"purchase" + "description": "this commerce event has product attributes and not allowing additional product attributes for event custom attributes and product custom attributes", + "match": { + "type": "product_action", + "criteria": { + "action": "purchase" } }, - "validator":{ - "type":"json_schema", - "definition":{ - "properties":{ - "data":{ - "additionalProperties":true, - "properties":{ - "product_action":{ - "additionalProperties":false, - "description":"", - "properties":{ - "products":{ - "description":"", - "items":{ - "additionalProperties":false, - "description":"", - "properties":{ - "custom_attributes":{ - "additionalProperties":false, - "description":"", - "properties":{ - "plannedAttr1":{ - "description":"", - "type":"string" + "validator": { + "type": "json_schema", + "definition": { + "properties": { + "data": { + "additionalProperties": true, + "properties": { + "product_action": { + "additionalProperties": false, + "description": "", + "properties": { + "products": { + "description": "", + "items": { + "additionalProperties": false, + "description": "", + "properties": { + "custom_attributes": { + "additionalProperties": false, + "description": "", + "properties": { + "plannedAttr1": { + "description": "", + "type": "string" }, - "plannedAttr2":{ - "description":"", - "type":"string" + "plannedAttr2": { + "description": "", + "type": "string" } }, - "required":[ - - ], - "type":"object" + "required": [], + "type": "object" }, - "position":{ - "description":"", - "type":"number" + "position": { + "description": "", + "type": "number" }, - "name":{ - "description":"", - "type":"string" + "name": { + "description": "", + "type": "string" } }, - "required":[ - - ], - "type":"object" + "required": [], + "type": "object" }, - "type":"array" + "type": "array" } }, - "required":[ - - ], - "type":"object" + "required": [], + "type": "object" }, - "custom_attributes":{ - "additionalProperties":false, - "description":"", - "properties":{ - "eventAttribute2":{ - "description":"", - "type":"string" + "custom_attributes": { + "additionalProperties": false, + "description": "", + "properties": { + "eventAttribute2": { + "description": "", + "type": "string" }, - "eventAttribute1":{ - "description":"", - "type":"string" + "eventAttribute1": { + "description": "", + "type": "string" } }, - "required":[ - - ], - "type":"object" + "required": [], + "type": "object" } }, - "required":[ - - ], - "type":"object" + "required": [], + "type": "object" } } } } }, { - "description":"", - "match":{ - "type":"promotion_action", - "criteria":{ - "action":"click" + "description": "", + "match": { + "type": "promotion_action", + "criteria": { + "action": "click" } }, - "validator":{ - "type":"json_schema", - "definition":{ - "properties":{ - "data":{ - "additionalProperties":true, - "properties":{ - "product_action":{ - "additionalProperties":true, - "description":"", - "properties":{ - "products":{ - "description":"", - "items":{ - "additionalProperties":false, - "description":"", - "type":"object" + "validator": { + "type": "json_schema", + "definition": { + "properties": { + "data": { + "additionalProperties": true, + "properties": { + "product_action": { + "additionalProperties": true, + "description": "", + "properties": { + "products": { + "description": "", + "items": { + "additionalProperties": false, + "description": "", + "type": "object" }, - "type":"array" + "type": "array" } }, - "required":[ - - ], - "type":"object" + "required": [], + "type": "object" }, - "custom_attributes":{ - "additionalProperties":false, - "description":"", - "properties":{ - "eventAttribute2":{ - "description":"", - "type":"string" + "custom_attributes": { + "additionalProperties": false, + "description": "", + "properties": { + "eventAttribute2": { + "description": "", + "type": "string" }, - "eventAttribute1":{ - "description":"", - "type":"string" + "eventAttribute1": { + "description": "", + "type": "string" } }, - "required":[ - - ], - "type":"object" + "required": [], + "type": "object" } }, - "required":[ - - ], - "type":"object" + "required": [], + "type": "object" } } } diff --git a/UnitTests/MPAttributionResult+MParticlePrivateTests.swift b/UnitTests/MPAttributionResult+MParticlePrivateTests.swift index 43a70d58c..bcb98138e 100644 --- a/UnitTests/MPAttributionResult+MParticlePrivateTests.swift +++ b/UnitTests/MPAttributionResult+MParticlePrivateTests.swift @@ -1,11 +1,10 @@ import XCTest #if MPARTICLE_LOCATION_DISABLE -import mParticle_Apple_SDK_NoLocation + import mParticle_Apple_SDK_NoLocation #else -import mParticle_Apple_SDK + import mParticle_Apple_SDK #endif - class MPAttributionResultMParticlePrivateTests: XCTestCase { func testDescription() { let result = MPAttributionResult( @@ -14,12 +13,12 @@ class MPAttributionResultMParticlePrivateTests: XCTestCase { ) result?.linkInfo = [:] XCTAssertEqual(result?.description(), """ - MPAttributionResult { - kitCode: 1 - kitName: TestKit - linkInfo: { - } - } - """) + MPAttributionResult { + kitCode: 1 + kitName: TestKit + linkInfo: { + } + } + """) } } diff --git a/UnitTests/MPEventTests.swift b/UnitTests/MPEventTests.swift index bbba42dc0..91c7d264b 100644 --- a/UnitTests/MPEventTests.swift +++ b/UnitTests/MPEventTests.swift @@ -55,7 +55,6 @@ class MPEventTests: XCTestCase { XCTAssertNil(sut.endTime) XCTAssertNil(sut.startTime) - // MPBaseEvent properties XCTAssertNotNil(sut.timestamp) XCTAssertEqual(sut.messageType, .event) @@ -194,7 +193,7 @@ class MPEventTests: XCTestCase { XCTAssertEqual(dict["n"] as? String, "Event1") // kMPEventNameKey XCTAssertEqual(dict["et"] as? String, "Other") // kMPEventTypeKey XCTAssertNotNil(dict["en"]) // kMPEventCounterKey - XCTAssertNotNil(dict["est"]) // kMPEventStartTimestamp + XCTAssertNotNil(dict["est"]) // kMPEventStartTimestamp XCTAssertEqual(dict["el"] as? Int, 100) // kMPEventLength } @@ -265,7 +264,6 @@ class MPEventTests: XCTestCase { XCTAssertEqual(receivedMessage, "mParticle -> The event name is too long.") } - // MARK: - Public category methods func testBeginTiming_whenEndTimeIsNotNil() { diff --git a/UnitTests/MPNetworkOptions+MParticlePrivateTests.swift b/UnitTests/MPNetworkOptions+MParticlePrivateTests.swift index bee2df122..f5f341862 100644 --- a/UnitTests/MPNetworkOptions+MParticlePrivateTests.swift +++ b/UnitTests/MPNetworkOptions+MParticlePrivateTests.swift @@ -1,15 +1,14 @@ import XCTest #if MPARTICLE_LOCATION_DISABLE -import mParticle_Apple_SDK_NoLocation + import mParticle_Apple_SDK_NoLocation #else -import mParticle_Apple_SDK + import mParticle_Apple_SDK #endif - class MPNetworkOptionsMParticlePrivateTests: XCTestCase { func testInit() { let sut = MPNetworkOptions() - + XCTAssertFalse(sut.pinningDisabledInDevelopment) XCTAssertFalse(sut.pinningDisabled) XCTAssertFalse(sut.overridesConfigSubdirectory) @@ -17,7 +16,7 @@ class MPNetworkOptionsMParticlePrivateTests: XCTestCase { XCTAssertFalse(sut.overridesIdentitySubdirectory) XCTAssertFalse(sut.overridesAliasSubdirectory) XCTAssertFalse(sut.eventsOnly) - + XCTAssertNil(sut.configHost) XCTAssertNil(sut.eventsHost) XCTAssertNil(sut.eventsTrackingHost) @@ -27,7 +26,7 @@ class MPNetworkOptionsMParticlePrivateTests: XCTestCase { XCTAssertNil(sut.aliasTrackingHost) XCTAssertEqual(sut.certificates, []) } - + func testDescription() { let sut = MPNetworkOptions() sut.configHost = "configHost" diff --git a/UnitTests/MParticleOptions+MParticlePrivateTests.swift b/UnitTests/MParticleOptions+MParticlePrivateTests.swift index 37f7371bf..f5a8dd401 100644 --- a/UnitTests/MParticleOptions+MParticlePrivateTests.swift +++ b/UnitTests/MParticleOptions+MParticlePrivateTests.swift @@ -1,18 +1,18 @@ import XCTest #if MPARTICLE_LOCATION_DISABLE -import mParticle_Apple_SDK_NoLocation + import mParticle_Apple_SDK_NoLocation #else -import mParticle_Apple_SDK + import mParticle_Apple_SDK #endif class MParticleOptionsMParticlePrivateTests: XCTestCase { var sut: MParticleOptions! - + override func setUp() { super.setUp() sut = MParticleOptions() } - + func testInit() { XCTAssertNotNil(sut) XCTAssertTrue(sut.proxyAppDelegate) @@ -22,11 +22,11 @@ class MParticleOptionsMParticlePrivateTests: XCTestCase { XCTAssertTrue(sut.automaticSessionTracking) XCTAssertTrue(sut.shouldBeginSession) XCTAssertFalse(sut.startKitsAsync) - + XCTAssertEqual(sut.logLevel, .none) XCTAssertEqual(sut.uploadInterval, 0.0) XCTAssertEqual(sut.sessionTimeout, 60.0) - + XCTAssertEqual(sut.apiKey, "") XCTAssertEqual(sut.apiSecret, "") XCTAssertEqual(sut.sharedGroupID, "") @@ -35,14 +35,14 @@ class MParticleOptionsMParticlePrivateTests: XCTestCase { XCTAssertEqual(sut.environment, .autoDetect) XCTAssertEqual(sut.customUserAgent, nil) XCTAssertEqual(sut.defaultAgent, "") - + XCTAssertNotNil(sut.customLogger) - + XCTAssertEqual(sut.uploadInterval, 0.0) XCTAssertEqual(sut.sessionTimeout, 60.0) - + XCTAssertNil(sut.networkOptions) - + XCTAssertNil(sut.consentState) XCTAssertNil(sut.dataPlanId) XCTAssertNil(sut.dataPlanVersion) @@ -57,61 +57,60 @@ class MParticleOptionsMParticlePrivateTests: XCTestCase { XCTAssertNotNil(sut.onAttributionComplete) XCTAssertNotNil(sut.onCreateBatch) } - + func testOptionsWithKey() { - let sut = MParticleOptions.init(key: "key", secret: "secret") + let sut = MParticleOptions(key: "key", secret: "secret") XCTAssertEqual(sut.apiKey, "key") XCTAssertEqual(sut.apiSecret, "secret") } - + func testSetProxyAppDelegate() { XCTAssertTrue(sut.proxyAppDelegate) XCTAssertFalse(sut.isProxyAppDelegateSet) - + sut.setProxyAppDelegate(false) - + XCTAssertFalse(sut.proxyAppDelegate) XCTAssertTrue(sut.isProxyAppDelegateSet) } - + func testSetCollectUserAgent() { XCTAssertTrue(sut.collectUserAgent) XCTAssertFalse(sut.isCollectUserAgentSet) - + sut.setCollectUserAgent(false) - + XCTAssertFalse(sut.collectUserAgent) XCTAssertTrue(sut.isCollectUserAgentSet) } - - + func testSetCollectSearchAdsAttribution() { XCTAssertFalse(sut.collectSearchAdsAttribution) XCTAssertFalse(sut.isCollectSearchAdsAttributionSet) - + sut.setCollectSearchAdsAttribution(true) - + XCTAssertTrue(sut.collectSearchAdsAttribution) XCTAssertTrue(sut.isCollectSearchAdsAttributionSet) } - + func testSetTrackNotifications() { XCTAssertTrue(sut.trackNotifications) XCTAssertFalse(sut.isTrackNotificationsSet) - + sut.setTrackNotifications(false) - + XCTAssertFalse(sut.trackNotifications) XCTAssertTrue(sut.isTrackNotificationsSet) } - + func testSetAutomaticSessionTracking() { XCTAssertTrue(sut.automaticSessionTracking) XCTAssertFalse(sut.isAutomaticSessionTrackingSet) - + sut.setAutomaticSessionTracking(false) - + XCTAssertFalse(sut.automaticSessionTracking) XCTAssertTrue(sut.isAutomaticSessionTrackingSet) } @@ -119,57 +118,57 @@ class MParticleOptionsMParticlePrivateTests: XCTestCase { func testSetStartKitsAsync() { XCTAssertFalse(sut.startKitsAsync) XCTAssertFalse(sut.isStartKitsAsyncSet) - + sut.setStartKitsAsync(true) - + XCTAssertTrue(sut.startKitsAsync) XCTAssertTrue(sut.isStartKitsAsyncSet) } - + func testSetUploadInterval() { XCTAssertEqual(sut.uploadInterval, 0.0) XCTAssertFalse(sut.isUploadIntervalSet) - + sut.setUploadInterval(1.0) - + XCTAssertEqual(sut.uploadInterval, 1.0) XCTAssertTrue(sut.isUploadIntervalSet) } - + func testSetSessionTimeout() { XCTAssertEqual(sut.sessionTimeout, 60.0) XCTAssertFalse(sut.isSessionTimeoutSet) - + sut.setSessionTimeout(1.0) - + XCTAssertEqual(sut.sessionTimeout, 1.0) XCTAssertTrue(sut.isSessionTimeoutSet) } - + func testSetConfigMaxAgeSeconds() { sut.setConfigMaxAgeSeconds(10.0) XCTAssertEqual(sut.configMaxAgeSeconds, 10.0) - + sut.setConfigMaxAgeSeconds(-10.0) XCTAssertEqual(sut.configMaxAgeSeconds, 10.0) - + sut.setConfigMaxAgeSeconds(nil) XCTAssertEqual(sut.configMaxAgeSeconds, nil) - + sut.setConfigMaxAgeSeconds(1.0) XCTAssertEqual(sut.configMaxAgeSeconds, 1.0) } - + func testSetPersistenceMaxAgeSeconds() { sut.setPersistenceMaxAgeSeconds(10.0) XCTAssertEqual(sut.persistenceMaxAgeSeconds, 10.0) - + sut.setPersistenceMaxAgeSeconds(-10.0) XCTAssertEqual(sut.persistenceMaxAgeSeconds, 10.0) - + sut.setPersistenceMaxAgeSeconds(nil) XCTAssertEqual(sut.persistenceMaxAgeSeconds, nil) - + sut.setPersistenceMaxAgeSeconds(1.0) XCTAssertEqual(sut.persistenceMaxAgeSeconds, 1.0) } diff --git a/UnitTests/MParticleSession+MParticlePrivateTests.swift b/UnitTests/MParticleSession+MParticlePrivateTests.swift index 88bfaa57e..318700c88 100644 --- a/UnitTests/MParticleSession+MParticlePrivateTests.swift +++ b/UnitTests/MParticleSession+MParticlePrivateTests.swift @@ -1,15 +1,14 @@ import XCTest #if MPARTICLE_LOCATION_DISABLE -import mParticle_Apple_SDK_NoLocation + import mParticle_Apple_SDK_NoLocation #else -import mParticle_Apple_SDK + import mParticle_Apple_SDK #endif - class MParticleSessionMParticlePrivateTests: XCTestCase { func testInit() { let sut = MParticleSession(uuid: "UUID") - XCTAssertEqual(sut?.sessionID, 8993343810776384128 as NSNumber) + XCTAssertEqual(sut?.sessionID, 8_993_343_810_776_384_128 as NSNumber) XCTAssertEqual(sut?.uuid, "UUID") } } diff --git a/UnitTests/MParticleTestsSwift.swift b/UnitTests/MParticleTestsSwift.swift index db83f1fc0..7c3c13792 100644 --- a/UnitTests/MParticleTestsSwift.swift +++ b/UnitTests/MParticleTestsSwift.swift @@ -1,8 +1,8 @@ import XCTest #if MPARTICLE_LOCATION_DISABLE -import mParticle_Apple_SDK_NoLocation + import mParticle_Apple_SDK_NoLocation #else -import mParticle_Apple_SDK + import mParticle_Apple_SDK #endif class MParticleTestsSwift: XCTestCase { @@ -17,10 +17,10 @@ class MParticleTestsSwift: XCTestCase { func customLogger(_ message: String) { receivedMessage = message } - + override func setUp() { super.setUp() - + mparticle = MParticle() mparticle.logLevel = .verbose mparticle.customLogger = customLogger @@ -40,23 +40,23 @@ class MParticleTestsSwift: XCTestCase { state = MPStateMachineMock() mparticle.stateMachine = state } - + override func tearDown() { super.tearDown() receivedMessage = nil mparticle.dataPlanFilter = nil } - + func testSetOptOutCompletionSuccess() { mparticle.setOptOutCompletion(.success, optOut: true) XCTAssertEqual(receivedMessage, "mParticle -> Set Opt Out: 1") } - + func testSetOptOutCompletionFailure() { mparticle.setOptOutCompletion(.fail, optOut: true) XCTAssertEqual(receivedMessage, "mParticle -> Set Opt Out Failed: 1") } - + func testSetOptOutOptOutValueIsDifferentItShouldBeChangedAndDeliveredToBackendController() { XCTAssertFalse(state.optOut) mparticle.optOut = true @@ -66,44 +66,44 @@ class MParticleTestsSwift: XCTestCase { XCTAssertNotNil(backendController.setOptOutCompletionHandler) backendController.setOptOutCompletionHandler?(true, .success) } - + func testIdentifyNoDispatchCallbackNoErrorDefferedKitAvailable() { - mparticle.deferredKitConfiguration_PRIVATE = [[String: String]](); + mparticle.deferredKitConfiguration_PRIVATE = [[String: String]]() let expectedApiResult = MPIdentityApiResult() let options = MParticleOptions() let expectation = XCTestExpectation() options.onIdentifyComplete = { apiResult, error in XCTAssertTrue(expectedApiResult === apiResult) XCTAssertNil(error) - + expectation.fulfill() } mparticle.identifyNoDispatchCallback(expectedApiResult, error: nil, options: options) - + wait(for: [expectation], timeout: 1.0) XCTAssertNil(receivedMessage) XCTAssertNil(mparticle.deferredKitConfiguration_PRIVATE) } - + func testIdentifyNoDispatchCallbackWithErrorDefferedKitAvailable() { - mparticle.deferredKitConfiguration_PRIVATE = [[String: String]](); + mparticle.deferredKitConfiguration_PRIVATE = [[String: String]]() let expectedApiResult = MPIdentityApiResult() let expectedError = NSError(domain: "", code: 0) let options = MParticleOptions() let expectation = XCTestExpectation() - options.onIdentifyComplete = { apiResult, error in + options.onIdentifyComplete = { apiResult, _ in XCTAssertTrue(expectedApiResult === apiResult) XCTAssertTrue(expectedError == expectedError) - + expectation.fulfill() } mparticle.identifyNoDispatchCallback(expectedApiResult, error: expectedError, options: options) - + wait(for: [expectation], timeout: 0.1) XCTAssertEqual(receivedMessage, "mParticle -> Identify request failed with error: Error Domain= Code=0 \"(null)\"") XCTAssertNil(mparticle.deferredKitConfiguration_PRIVATE) } - + func testConfigureDefaultConfigurationExistOptionParametersAreNotSet() { let options = MParticleOptions() mparticle.backendController = MPBackendController_PRIVATE() @@ -114,7 +114,7 @@ class MParticleTestsSwift: XCTestCase { XCTAssertEqual(mparticle.collectUserAgent, true) XCTAssertEqual(mparticle.trackNotifications, true) } - + func testConfigureWhenDefaultConfigurationExists() { let settingsProvider = SettingsProviderMock() let settings: NSMutableDictionary = [ @@ -125,37 +125,37 @@ class MParticleTestsSwift: XCTestCase { "track_notifications": false, "enable_location_tracking": true, "location_tracking_accuracy": 100.0, - "location_tracking_distance_filter": 10.0 + "location_tracking_distance_filter": 10.0, ] settingsProvider.configSettings = settings mparticle.settingsProvider = settingsProvider mparticle.backendController = MPBackendController_PRIVATE() let options = MParticleOptions() mparticle.configure(with: options) - + XCTAssertEqual(mparticle.backendController.sessionTimeout, 2.0) XCTAssertEqual(mparticle.backendController.uploadInterval, 3.0) XCTAssertEqual(mparticle.customUserAgent, "custom_user_agent") XCTAssertEqual(mparticle.collectUserAgent, false) XCTAssertEqual(mparticle.trackNotifications, false) } - + func testStartWithKeyCallbackFirstRun() { let options = MParticleOptions() let userDefaults = MPUserDefaultsMock() XCTAssertFalse(mparticle.initialized) - + mparticle.start(withKeyCallback: true, options: options, userDefaults: userDefaults) - + XCTAssertTrue(mparticle.initialized) XCTAssertNil(mparticle.settingsProvider.configSettings) - + XCTAssertNotNil(userDefaults.setMPObjectValueParam) XCTAssertEqual(userDefaults.setMPObjectKeyParam, "firstrun") XCTAssertEqual(userDefaults.setMPObjectUserIdParam, 0) XCTAssertTrue(userDefaults.synchronizeCalled) } - + func testStartWithKeyCallbackNotFirstRunWithIdentityRequest() { let options = MParticleOptions() let user = mparticle.identity.currentUser @@ -171,129 +171,122 @@ class MParticleTestsSwift: XCTestCase { XCTAssertFalse(userDefaults.setMPObjectCalled) XCTAssertFalse(userDefaults.synchronizeCalled) } - + func testBeginTimedEventCompletionHandlerDataFilterNotSet() { XCTAssertNil(mparticle.dataPlanFilter) - + mparticle.beginTimedEventCompletionHandler(MPEvent(), execStatus: .success) XCTAssertEqual(receivedMessage, """ - mParticle -> Began timed event: Event:{ - Name: <> - Type: Other - Duration: 0 - } - """ - ) + mParticle -> Began timed event: Event:{ + Name: <> + Type: Other + Duration: 0 + } + """) } - + func testBeginTimedEventCompletionHandlerDataFilterSetDataFilterReturnNil() { let dataPlanFilter = MPDataPlanFilterMock() mparticle.dataPlanFilter = dataPlanFilter let expectedEvent = MPEvent() - + mparticle.beginTimedEventCompletionHandler(expectedEvent, execStatus: .success) XCTAssertTrue(dataPlanFilter.transformEventCalled) XCTAssertTrue(dataPlanFilter.transformEventEventParam === expectedEvent) XCTAssertEqual(receivedMessage, """ - mParticle -> Blocked timed event begin from kits: Event:{ - Name: <> - Type: Other\n Duration: 0 - } - """ - ) + mParticle -> Blocked timed event begin from kits: Event:{ + Name: <> + Type: Other\n Duration: 0 + } + """) } - + func testLogEventCallbackDataFilterNotSet() { XCTAssertNil(mparticle.dataPlanFilter) mparticle.logEventCallback(MPEvent(), execStatus: .success) - + XCTAssertNil(receivedMessage) } - + func testLogEventCallbackDataFilterSetDataFilterReturnNil() { let dataPlanFilter = MPDataPlanFilterMock() mparticle.dataPlanFilter = dataPlanFilter let expectedEvent = MPEvent() mparticle.logEventCallback(expectedEvent, execStatus: .success) - + XCTAssertTrue(dataPlanFilter.transformEventCalled) XCTAssertTrue(dataPlanFilter.transformEventEventParam === expectedEvent) XCTAssertEqual(receivedMessage, """ - mParticle -> Blocked timed event end from kits: Event:{ - Name: <> - Type: Other - Duration: 0 - } - """ - ) + mParticle -> Blocked timed event end from kits: Event:{ + Name: <> + Type: Other + Duration: 0 + } + """) } func testLogScreenCallbackDataFilterNotSet() { XCTAssertNil(mparticle.dataPlanFilter) mparticle.logScreenCallback(MPEvent(), execStatus: .success) - + XCTAssertEqual(receivedMessage, """ - mParticle -> Logged screen event: Event:{ - Name: <> - Type: Other - Duration: 0 - } - """ - ) + mParticle -> Logged screen event: Event:{ + Name: <> + Type: Other + Duration: 0 + } + """) } - + func testLogScreenCallbackDataFilterSetDataFilterReturnNil() { let dataPlanFilter = MPDataPlanFilterMock() mparticle.dataPlanFilter = dataPlanFilter let expectedEvent = MPEvent() mparticle.logScreenCallback(expectedEvent, execStatus: .success) - + XCTAssertTrue(dataPlanFilter.transformEventForScreenEventCalled) XCTAssertTrue(dataPlanFilter.transformEventForScreenEventScreenEventParam === expectedEvent) XCTAssertEqual(receivedMessage, """ - mParticle -> Blocked screen event from kits: Event:{ - Name: <> - Type: Other - Duration: 0 - } - """ - ) + mParticle -> Blocked screen event from kits: Event:{ + Name: <> + Type: Other + Duration: 0 + } + """) } func testLogErrorCallbackSuccess() { mparticle.logErrorCallback([:], execStatus: .success, message: "error") - + XCTAssertEqual(receivedMessage, """ - mParticle -> Logged error with message: error - """ - ) + mParticle -> Logged error with message: error + """) } - + func testLogErrorCallbackFail() { mparticle.logErrorCallback([:], execStatus: .fail, message: "error") - + XCTAssertNil(receivedMessage) } func testLogExceptionCallbackSuccess() { let exception = NSException(name: NSExceptionName("Test"), reason: "Test", userInfo: nil) mparticle.logExceptionCallback(exception, execStatus: .success, message: "exception", topmostContext: nil) - + XCTAssertEqual(receivedMessage, """ - mParticle -> Logged exception name: exception, reason: Test, topmost context: (null) - """ - ) + mParticle -> Logged exception name: exception, reason: Test, topmost context: (null) + """) } - + func testLogExceptionCallbackFail() { let exception = NSException(name: NSExceptionName("Test"), reason: "Test", userInfo: nil) mparticle.logExceptionCallback(exception, execStatus: .fail, message: "exception", topmostContext: nil) - + XCTAssertNil(receivedMessage) } - + func testLogCrashCallbackSuccess() { mparticle.logCrashCallback(.success, message: "Message") XCTAssertEqual(receivedMessage, "mParticle -> Logged crash with message: Message") @@ -302,47 +295,46 @@ class MParticleTestsSwift: XCTestCase { func testLogCommerceEventCallbackSuccess() { let commerceEvent = MPCommerceEvent() mparticle.logCommerceEventCallback(commerceEvent, execStatus: .success) - + XCTAssertNil(receivedMessage) } - + func testLogCommerceEventCallbackFail() { let commerceEvent = MPCommerceEvent() mparticle.logCommerceEventCallback(commerceEvent, execStatus: .fail) - + XCTAssertEqual(receivedMessage, """ - mParticle -> Failed to log commerce event: MPCommerceEvent { - } - - """ - ) + mParticle -> Failed to log commerce event: MPCommerceEvent { + } + + """) } func testLogNetworkPerformanceCallbackSuccess() { mparticle.logNetworkPerformanceCallback(.success) - + XCTAssertEqual(receivedMessage, "mParticle -> Logged network performance measurement") } - + func testLogNetworkPerformanceCallbackFail() { mparticle.logNetworkPerformanceCallback(.fail) - + XCTAssertNil(receivedMessage) } - + func testSetSharedInstance() { MParticle.setSharedInstance(mparticle) XCTAssertEqual(listenerController.onAPICalledApiName?.description, "setSharedInstance:") XCTAssertTrue(listenerController.onAPICalledParameter1 === mparticle) } - + func testStartWithOptionsListenerControllerCalled() { let options = MParticleOptions(key: "key", secret: "secret") mparticle.start(with: options) XCTAssertEqual(listenerController.onAPICalledApiName?.description, "startWithOptions:") XCTAssertTrue(listenerController.onAPICalledParameter1 === options) } - + func testBeginTimedEventDependenciesReceiveCorrectParametersAndHandlerExecutedWithoutErrors() { let expectedEvent = MPEvent() mparticle.beginTimedEvent(expectedEvent) @@ -354,7 +346,7 @@ class MParticleTestsSwift: XCTestCase { backendController.beginTimedEventCompletionHandler?(expectedEvent, .success) XCTAssertNotNil(receivedMessage) } - + func testEndTimedEventListenerControllerCalled() { let expectedEvent = MPEvent() mparticle.endTimedEvent(expectedEvent) @@ -362,7 +354,7 @@ class MParticleTestsSwift: XCTestCase { XCTAssertEqual(listenerController.onAPICalledApiName?.description, "endTimedEvent:") XCTAssertTrue(listenerController.onAPICalledParameter1 === expectedEvent) } - + func testLogEventWithBaseEventListenerControllerCalled() { let expectedEvent = MPBaseEvent() mparticle.logEvent(expectedEvent) @@ -370,7 +362,7 @@ class MParticleTestsSwift: XCTestCase { XCTAssertEqual(listenerController.onAPICalledApiName?.description, "logEvent:") XCTAssertTrue(listenerController.onAPICalledParameter1 === expectedEvent) } - + func testLogCustomEventListenerControllerCalled() { let expectedEvent = MPEvent() mparticle.logEvent(expectedEvent) @@ -378,7 +370,7 @@ class MParticleTestsSwift: XCTestCase { XCTAssertEqual(listenerController.onAPICalledApiName?.description, "logCustomEvent:") XCTAssertTrue(listenerController.onAPICalledParameter1 === expectedEvent) } - + func testLogScreenEventListenerControllerCalled() { let expectedEvent = MPEvent() mparticle.logScreenEvent(expectedEvent) @@ -401,14 +393,14 @@ class MParticleTestsSwift: XCTestCase { XCTAssertEqual(listenerController.onAPICalledApiName?.description, "logException:topmostContext:") XCTAssertTrue(listenerController.onAPICalledParameter1 === expectedException) } - + func testLogCrashListenerControllerCalled() { mparticle.logCrash("message", stackTrace: "stackTrace", plCrashReport: "report") wait(for: [listenerController.onAPICalledExpectation!], timeout: 0.1) XCTAssertEqual(listenerController.onAPICalledApiName?.description, "logCrash:stackTrace:plCrashReport:") XCTAssertEqual(listenerController.onAPICalledParameter1 as? String, "message") } - + func testLogCommerceEventListenerControllerCalled() { let expectedEvent = MPCommerceEvent() mparticle.logCommerceEvent(expectedEvent) @@ -416,7 +408,7 @@ class MParticleTestsSwift: XCTestCase { XCTAssertEqual(listenerController.onAPICalledApiName?.description, "logCommerceEvent:") XCTAssertTrue(listenerController.onAPICalledParameter1 === expectedEvent) } - + func testSetIntegrationAttributesListenerControllerCalled() { mparticle.setIntegrationAttributes(["test": "test"], forKit: NSNumber(value: 1)) wait(for: [listenerController.onAPICalledExpectation!], timeout: 0.1) @@ -437,7 +429,7 @@ class MParticleTestsSwift: XCTestCase { XCTAssertEqual(listenerController.onAPICalledApiName?.description, "onKitsInitialized:") XCTAssertNotNil(listenerController.onAPICalledParameter1) } - + func testExecuteKitsInitializedBlocks() { mparticle.executeKitsInitializedBlocks() XCTAssertEqual(listenerController.onAPICalledApiName?.description, "executeKitsInitializedBlocks") @@ -461,75 +453,79 @@ class MParticleTestsSwift: XCTestCase { XCTAssertEqual(listenerController.onAPICalledApiName?.description, "kitInstance:completionHandler:") XCTAssertEqual(listenerController.onAPICalledParameter1 as? Int, 1) } -#if os(iOS) - func testBackgroundLocationTrackingListenerControllerCalled() { - mparticle.backgroundLocationTracking = true - XCTAssertEqual(listenerController.onAPICalledApiName?.description, "setBackgroundLocationTracking:") - XCTAssertEqual(listenerController.onAPICalledParameter1 as? Bool, true) - - _ = mparticle.backgroundLocationTracking - XCTAssertEqual(listenerController.onAPICalledApiNames[1].description, "backgroundLocationTracking") - } - - func testWebviewBridgeValueWithCustomerBridgeNameListenerControllerCalled() { - let expectedWebView = WKWebView() - mparticle.initializeWKWebView(expectedWebView, bridgeName: "name") - XCTAssertEqual(listenerController.onAPICalledApiName?.description, "initializeWKWebView:bridgeName:") - XCTAssertNotNil(listenerController.onAPICalledParameter1) - XCTAssertEqual(listenerController.onAPICalledParameter2 as? String, "name") - } - - func testLogNotificationOpenedWithUserInfoAndActionIdentifierListenerControllerCalled() { - mparticle.logNotificationOpened(userInfo: [:], andActionIdentifier: "identifier") - XCTAssertEqual(listenerController.onAPICalledApiName?.description, "logNotificationOpenedWithUserInfo:andActionIdentifier:") - XCTAssertEqual(listenerController.onAPICalledParameter1 as? [String:String], [:]) - } - - func testUserContentControllerDidReceiveScriptMessageListenerControllerCalled() { - mparticle.userContentController(WKUserContentController(), didReceive: WKScriptMessage()) - XCTAssertEqual(listenerController.onAPICalledApiName?.description, "userContentController:didReceiveScriptMessage:") - XCTAssertNotNil(listenerController.onAPICalledParameter1) - XCTAssertNotNil(listenerController.onAPICalledParameter2) - } - - func testHandleWebviewCommandListenerControllerCalled() { - mparticle.handleWebviewCommand("command", dictionary: [:]) - XCTAssertEqual(listenerController.onAPICalledApiName?.description, "handleWebviewCommand:dictionary:") - XCTAssertEqual(listenerController.onAPICalledParameter1 as? String, "command") - XCTAssertEqual(listenerController.onAPICalledParameter2 as? [String:String], [:]) - } - -#if !MPARTICLE_LOCATION_DISABLE - func testLocationListenerControllerCalled() { - _ = mparticle.location - XCTAssertEqual(listenerController.onAPICalledApiName?.description, "location") - } - - func testSetLocationListenerControllerCalled() { - let expectedLocation = CLLocation(latitude: 1, longitude: 2) - mparticle.location = expectedLocation - wait(for: [listenerController.onAPICalledExpectation!], timeout: 0.1) - XCTAssertEqual(listenerController.onAPICalledApiName?.description, "setLocation:") - XCTAssertEqual(listenerController.onAPICalledParameter1 as? CLLocation, expectedLocation) - } - func testBeginLocationTrackingListenerControllerCalled() { - mparticle.beginLocationTracking(CLLocationAccuracy.nan, minDistance: CLLocationDistance.nan) - XCTAssertEqual(listenerController.onAPICalledApiName?.description, "beginLocationTracking:minDistance:authorizationRequest:") - XCTAssertNotNil(listenerController.onAPICalledParameter1) - XCTAssertNotNil(listenerController.onAPICalledParameter2) - } + #if os(iOS) + func testBackgroundLocationTrackingListenerControllerCalled() { + mparticle.backgroundLocationTracking = true + XCTAssertEqual(listenerController.onAPICalledApiName?.description, "setBackgroundLocationTracking:") + XCTAssertEqual(listenerController.onAPICalledParameter1 as? Bool, true) - func testEndLocationTrackingListenerControllerCalled() { - mparticle.endLocationTracking() - XCTAssertEqual(listenerController.onAPICalledApiName?.description, "endLocationTracking") - } -#endif -#endif + _ = mparticle.backgroundLocationTracking + XCTAssertEqual(listenerController.onAPICalledApiNames[1].description, "backgroundLocationTracking") + } + + func testWebviewBridgeValueWithCustomerBridgeNameListenerControllerCalled() { + let expectedWebView = WKWebView() + mparticle.initializeWKWebView(expectedWebView, bridgeName: "name") + XCTAssertEqual(listenerController.onAPICalledApiName?.description, "initializeWKWebView:bridgeName:") + XCTAssertNotNil(listenerController.onAPICalledParameter1) + XCTAssertEqual(listenerController.onAPICalledParameter2 as? String, "name") + } + + func testLogNotificationOpenedWithUserInfoAndActionIdentifierListenerControllerCalled() { + mparticle.logNotificationOpened(userInfo: [:], andActionIdentifier: "identifier") + XCTAssertEqual(listenerController.onAPICalledApiName?.description, + "logNotificationOpenedWithUserInfo:andActionIdentifier:") + XCTAssertEqual(listenerController.onAPICalledParameter1 as? [String: String], [:]) + } + + func testUserContentControllerDidReceiveScriptMessageListenerControllerCalled() { + mparticle.userContentController(WKUserContentController(), didReceive: WKScriptMessage()) + XCTAssertEqual(listenerController.onAPICalledApiName?.description, "userContentController:didReceiveScriptMessage:") + XCTAssertNotNil(listenerController.onAPICalledParameter1) + XCTAssertNotNil(listenerController.onAPICalledParameter2) + } + + func testHandleWebviewCommandListenerControllerCalled() { + mparticle.handleWebviewCommand("command", dictionary: [:]) + XCTAssertEqual(listenerController.onAPICalledApiName?.description, "handleWebviewCommand:dictionary:") + XCTAssertEqual(listenerController.onAPICalledParameter1 as? String, "command") + XCTAssertEqual(listenerController.onAPICalledParameter2 as? [String: String], [:]) + } + + #if !MPARTICLE_LOCATION_DISABLE + func testLocationListenerControllerCalled() { + _ = mparticle.location + XCTAssertEqual(listenerController.onAPICalledApiName?.description, "location") + } + + func testSetLocationListenerControllerCalled() { + let expectedLocation = CLLocation(latitude: 1, longitude: 2) + mparticle.location = expectedLocation + wait(for: [listenerController.onAPICalledExpectation!], timeout: 0.1) + XCTAssertEqual(listenerController.onAPICalledApiName?.description, "setLocation:") + XCTAssertEqual(listenerController.onAPICalledParameter1 as? CLLocation, expectedLocation) + } + + func testBeginLocationTrackingListenerControllerCalled() { + mparticle.beginLocationTracking(CLLocationAccuracy.nan, minDistance: CLLocationDistance.nan) + XCTAssertEqual(listenerController.onAPICalledApiName?.description, + "beginLocationTracking:minDistance:authorizationRequest:") + XCTAssertNotNil(listenerController.onAPICalledParameter1) + XCTAssertNotNil(listenerController.onAPICalledParameter2) + } + + func testEndLocationTrackingListenerControllerCalled() { + mparticle.endLocationTracking() + XCTAssertEqual(listenerController.onAPICalledApiName?.description, "endLocationTracking") + } + #endif + #endif func testNetworkPermissionListenerControllerCalled() { mparticle.logNetworkPerformance("", httpMethod: "", startTime: 0.0, duration: 1.0, bytesSent: 100, bytesReceived: 200) wait(for: [listenerController.onAPICalledExpectation!], timeout: 0.1) - XCTAssertEqual(listenerController.onAPICalledApiName?.description, "logNetworkPerformance:httpMethod:startTime:duration:bytesSent:bytesReceived:") + XCTAssertEqual(listenerController.onAPICalledApiName?.description, + "logNetworkPerformance:httpMethod:startTime:duration:bytesSent:bytesReceived:") XCTAssertNotNil(listenerController.onAPICalledParameter1) } @@ -566,13 +562,13 @@ class MParticleTestsSwift: XCTestCase { XCTAssertEqual(listenerController.onAPICalledApiName?.description, "webviewBridgeValueWithCustomerBridgeName:") XCTAssertEqual(listenerController.onAPICalledParameter1 as? String, "value") } - + func testSessionDidBegin() { kitContainer.forwardSDKCallExpectation = XCTestExpectation() mparticle.sessionDidBegin(MPSession()) - + wait(for: [kitContainer.forwardSDKCallExpectation!], timeout: 1.0) - + XCTAssertTrue(kitContainer.forwardSDKCallCalled) XCTAssertEqual(kitContainer.forwardSDKCallSelectorParam?.description, "beginSession") XCTAssertEqual(kitContainer.forwardSDKCallMessageTypeParam, .sessionStart) @@ -580,13 +576,13 @@ class MParticleTestsSwift: XCTestCase { XCTAssertNil(kitContainer.forwardSDKCallParametersParam) XCTAssertNil(kitContainer.forwardSDKCallUserInfoParam) } - + func testSessionDidEnd() { kitContainer.forwardSDKCallExpectation = XCTestExpectation() mparticle.sessionDidEnd(MPSession()) - + wait(for: [kitContainer.forwardSDKCallExpectation!], timeout: 1.0) - + XCTAssertTrue(kitContainer.forwardSDKCallCalled) XCTAssertEqual(kitContainer.forwardSDKCallSelectorParam?.description, "endSession") XCTAssertEqual(kitContainer.forwardSDKCallMessageTypeParam, .sessionEnd) @@ -594,7 +590,7 @@ class MParticleTestsSwift: XCTestCase { XCTAssertNil(kitContainer.forwardSDKCallParametersParam) XCTAssertNil(kitContainer.forwardSDKCallUserInfoParam) } - + func testResetForSwitchingWorkspaces() { let expectation = XCTestExpectation() @@ -606,27 +602,27 @@ class MParticleTestsSwift: XCTestCase { } wait(for: [expectation], timeout: 1.0) - + XCTAssertTrue(kitContainer.flushSerializedKitsCalled) XCTAssertTrue(kitContainer.removeAllSideloadedKitsCalled) XCTAssertEqual(persistenceController.resetDatabaseCalled, true) XCTAssertTrue(backendController.unproxyOriginalAppDelegateCalled) } - + func testBeginSessionTempSessionAvailableSessionTempSessionShouldNotBeCreated() { backendController.session = nil backendController.tempSessionReturnValue = MParticleSession() mparticle.beginSession() XCTAssertFalse(backendController.createTempSessionCalled) } - + func testBeginSessionSessionAvailableSessionTempSessionShouldNotBeCreated() { backendController.session = MPSession() backendController.tempSessionReturnValue = nil mparticle.beginSession() XCTAssertFalse(backendController.createTempSessionCalled) } - + func testBeginSessionSessionUnavailable() { backendController.session = nil backendController.tempSessionReturnValue = nil @@ -637,14 +633,14 @@ class MParticleTestsSwift: XCTestCase { XCTAssertEqual(backendController.beginSessionIsManualParam, true) XCTAssertNotNil(backendController.beginSessionDateParam) } - + func testEndSessionNoSession() { backendController.session = nil mparticle.endSession() XCTAssertEqual(executor.executeOnMessageQueueAsync, true) XCTAssertFalse(backendController.endSessionWithIsManualCalled) } - + func testEndSessionWithSession() { backendController.session = MPSession() mparticle.endSession() @@ -652,7 +648,7 @@ class MParticleTestsSwift: XCTestCase { XCTAssertTrue(backendController.endSessionWithIsManualCalled) XCTAssertEqual(backendController.endSessionIsManualParam, true) } - + func testForwardLogInstall() { mparticle.forwardLogInstall() XCTAssertEqual(executor.executeOnMainAsync, true) @@ -663,7 +659,7 @@ class MParticleTestsSwift: XCTestCase { XCTAssertNil(kitContainer.forwardSDKCallParametersParam) XCTAssertNil(kitContainer.forwardSDKCallUserInfoParam) } - + func testForwardLogUpdate() { mparticle.forwardLogUpdate() XCTAssertEqual(executor.executeOnMainAsync, true) @@ -674,44 +670,44 @@ class MParticleTestsSwift: XCTestCase { XCTAssertNil(kitContainer.forwardSDKCallParametersParam) XCTAssertNil(kitContainer.forwardSDKCallUserInfoParam) } - + func testIndentityReturnsTheSameObject() { let identity = mparticle.identity XCTAssertTrue(identity === mparticle.identity) } - + func testRoktReturnsTheSameObject() { let rokt = mparticle.rokt XCTAssertTrue(rokt === mparticle.rokt) } - + func testSessionTimeoutReturnsValueFromBackendController() { mparticle.backendController.sessionTimeout = 100 XCTAssertEqual(mparticle.sessionTimeout, 100) } - + func testUniqueIdentifierRwturnedFromStateMachine() { let stateMachine = MPStateMachineMock() stateMachine.consumerInfo.uniqueIdentifier = "test" mparticle.stateMachine = stateMachine XCTAssertEqual(mparticle.uniqueIdentifier, "test") } - + func testSetUploadIntervalChangeValueInBackendControllerWhenIntervalGreaterThenOne() { mparticle.setUploadInterval(3) XCTAssertEqual(backendController.uploadInterval, 3) } - + func testSetUploadIntervalNotChangeValueInBackendControllerWhenIntervalLessThenOne() { mparticle.setUploadInterval(0.1) XCTAssertEqual(backendController.uploadInterval, 0.0) } - + func testUploadIntervalGetFromBackendController() { backendController.uploadInterval = 100 XCTAssertEqual(mparticle.uploadInterval, 100) } - + func testUserAttributesForUserIdRequestDataFromBackendController() { backendController.userAttributesReturnValue = ["key": "value"] let dictionary = mparticle.userAttributes(forUserId: 1) @@ -719,7 +715,7 @@ class MParticleTestsSwift: XCTestCase { XCTAssertTrue(backendController.userAttributesCalled) XCTAssertEqual(backendController.userAttributesUserIdParam, 1) } - + func testConfigureWithOptionsNoSettings() { let settingsProvider = SettingsProviderMock() mparticle.settingsProvider = settingsProvider @@ -729,13 +725,13 @@ class MParticleTestsSwift: XCTestCase { XCTAssertNil(mparticle.customUserAgent) XCTAssertTrue(mparticle.collectUserAgent) XCTAssertTrue(mparticle.trackNotifications) -#if os(iOS) -#if !MPARTICLE_LOCATION_DISABLE - XCTAssertNil(listenerController.onAPICalledApiName) -#endif -#endif + #if os(iOS) + #if !MPARTICLE_LOCATION_DISABLE + XCTAssertNil(listenerController.onAPICalledApiName) + #endif + #endif } - + func testConfigureWithOptionsWithSettingsAndOptionNotSet() { let settingsProvider = SettingsProviderMock() mparticle.settingsProvider = settingsProvider @@ -745,7 +741,7 @@ class MParticleTestsSwift: XCTestCase { "custom_user_agent": "agent", "collect_user_agent": false, "track_notifications": false, - "enable_location_tracking": true + "enable_location_tracking": true, ] let options = MParticleOptions() options.isSessionTimeoutSet = false @@ -759,60 +755,62 @@ class MParticleTestsSwift: XCTestCase { XCTAssertEqual(mparticle.customUserAgent, "agent") XCTAssertFalse(mparticle.collectUserAgent) XCTAssertFalse(mparticle.trackNotifications) - -#if os(iOS) -#if !MPARTICLE_LOCATION_DISABLE - XCTAssertEqual(listenerController.onAPICalledApiName?.description, "beginLocationTracking:minDistance:authorizationRequest:") -#endif -#endif + + #if os(iOS) + #if !MPARTICLE_LOCATION_DISABLE + XCTAssertEqual(listenerController.onAPICalledApiName?.description, + "beginLocationTracking:minDistance:authorizationRequest:") + #endif + #endif } - + // MARK: - logEvent + func testLogEventCalledLogCustomEvent() { let event = MPEvent(name: "test", type: .other)! mparticle.logEvent(event) wait(for: [listenerController.onAPICalledExpectation!], timeout: 0.1) XCTAssertEqual(listenerController.onAPICalledApiName?.description, "logCustomEvent:") } - + func testLogEventCalledLogCommerceEvent() { let commerceEvent = MPCommerceEvent(action: .purchase)! mparticle.logEvent(commerceEvent) wait(for: [listenerController.onAPICalledExpectation!], timeout: 0.1) XCTAssertEqual(listenerController.onAPICalledApiName?.description, "logCommerceEvent:") } - + func testLogEventWithFilterReturningNil_blocksEvent() { let event = MPBaseEvent(eventType: .other)! let dataPlanFilter = MPDataPlanFilterMock() dataPlanFilter.transformEventForBaseEventReturnValue = nil mparticle.dataPlanFilter = dataPlanFilter - + mparticle.logEvent(event) - + // Verify listener was called XCTAssertEqual(listenerController.onAPICalledApiName?.description, "logEvent:") XCTAssertTrue(listenerController.onAPICalledParameter1 === event) - + // Verify backend was called XCTAssertTrue(backendController.logBaseEventCalled) XCTAssertTrue(backendController.logBaseEventEventParam === event) let completion = backendController.logBaseEventCompletionHandler! XCTAssertNotNil(completion) completion(event, .success) - + // Verify executor usage XCTAssertTrue(executor.executeOnMessageQueueAsync) - + // Verify filter transform event XCTAssertTrue(dataPlanFilter.transformEventForBaseEventCalled) XCTAssertTrue(dataPlanFilter.transformEventForBaseEventParam === event) - + // Logger should record the blocked event message XCTAssertEqual(receivedMessage, "mParticle -> Blocked base event from kits: \(event)") } - + func testLogBaseEventWithFilterReturningEvent_forwardsTransformedEvent() { let event = MPBaseEvent(eventType: .other)! let transformedEvent = MPBaseEvent(eventType: .addToCart)! @@ -822,69 +820,68 @@ class MParticleTestsSwift: XCTestCase { mparticle.dataPlanFilter = dataPlanFilter mparticle.logEvent(event) - + // Verify listener was called XCTAssertEqual(listenerController.onAPICalledApiName?.description, "logEvent:") XCTAssertTrue(listenerController.onAPICalledParameter1 === event) - + // Verify backend was called XCTAssertTrue(backendController.logBaseEventCalled) XCTAssertTrue(backendController.logBaseEventEventParam === event) let completion = backendController.logBaseEventCompletionHandler! XCTAssertNotNil(completion) completion(event, .success) - + // Verify executor usage XCTAssertTrue(executor.executeOnMessageQueueAsync) XCTAssertTrue(executor.executeOnMainAsync) - + // Verify filter transformed event XCTAssertTrue(dataPlanFilter.transformEventForBaseEventCalled) XCTAssertTrue(dataPlanFilter.transformEventForBaseEventParam === event) - + // Verify kit container forwarded transformed event XCTAssertTrue(kitContainer.forwardSDKCallCalled) XCTAssertEqual(kitContainer.forwardSDKCallSelectorParam?.description, "logBaseEvent:") XCTAssertEqual(kitContainer.forwardSDKCallMessageTypeParam, .unknown) XCTAssertTrue(kitContainer.forwardSDKCallEventParam === transformedEvent) } - - + // MARK: - logCustomEvent - + func testLogCustomEventWithNilEvent_logsError() { mparticle.logCustomEvent(nil) XCTAssertEqual(receivedMessage, "mParticle -> Cannot log nil event!") } - + func testLogCustomEventWithFilterReturningNil_blocksEvent() { let event = MPEvent(name: "blocked", type: .other)! let dataPlanFilter = MPDataPlanFilterMock() dataPlanFilter.transformEventReturnValue = nil mparticle.dataPlanFilter = dataPlanFilter - + mparticle.logCustomEvent(event) - + // Verify event timing ended XCTAssertNil(event.endTime) - + // Verify listener was called XCTAssertEqual(listenerController.onAPICalledApiName?.description, "logCustomEvent:") XCTAssertTrue(listenerController.onAPICalledParameter1 === event) - + // Verify backend was called XCTAssertTrue(backendController.logEventCalled) XCTAssertTrue(backendController.logEventEventParam === event) XCTAssertNotNil(backendController.logEventCompletionHandler) - + // Verify executor usage XCTAssertTrue(executor.executeOnMessageQueueAsync) - + // Verify filter transform event XCTAssertTrue(dataPlanFilter.transformEventCalled) XCTAssertTrue(dataPlanFilter.transformEventEventParam === event) - + // Logger should record the blocked event message XCTAssertEqual(receivedMessage, "mParticle -> Blocked custom event from kits: \(event)") } @@ -898,27 +895,27 @@ class MParticleTestsSwift: XCTestCase { mparticle.dataPlanFilter = dataPlanFilter mparticle.logCustomEvent(event) - + // Verify event timing ended XCTAssertNil(event.endTime) - + // Verify listener was called XCTAssertEqual(listenerController.onAPICalledApiName?.description, "logCustomEvent:") XCTAssertTrue(listenerController.onAPICalledParameter1 === event) - + // Verify backend was called XCTAssertTrue(backendController.logEventCalled) XCTAssertTrue(backendController.logEventEventParam === event) XCTAssertNotNil(backendController.logEventCompletionHandler) - + // Verify executor usage XCTAssertTrue(executor.executeOnMessageQueueAsync) XCTAssertTrue(executor.executeOnMainAsync) - + // Verify filter transformed event XCTAssertTrue(dataPlanFilter.transformEventCalled) XCTAssertTrue(dataPlanFilter.transformEventEventParam === event) - + // Verify kit container forwarded transformed event XCTAssertTrue(kitContainer.forwardSDKCallCalled) XCTAssertEqual(kitContainer.forwardSDKCallSelectorParam?.description, "logEvent:") @@ -940,7 +937,6 @@ class MParticleTestsSwift: XCTestCase { XCTAssertTrue(executor.executeOnMessageQueueAsync) } - func testLogCommerceEventWithFilterReturningNil_blocksEvent() { let commerceEvent = MPCommerceEvent(eventType: .other)! @@ -975,7 +971,6 @@ class MParticleTestsSwift: XCTestCase { XCTAssertEqual(receivedMessage, "mParticle -> Blocked commerce event from kits: \(commerceEvent)") } - func testLogCommerceEventWithFilterReturningEvent_forwardsTransformedEvent() { let commerceEvent = MPCommerceEvent(eventType: .other)! let transformedCommerceEvent = MPCommerceEvent(eventType: .viewDetail)! @@ -1046,7 +1041,7 @@ class MParticleTestsSwift: XCTestCase { XCTAssertNotNil(completion) completion(loggedEvent, .success) } - + func testLogLTVIncrease_withoutEventInfo_defaultsToNilInfo() { let amount = 12.5 let name = "name" @@ -1077,39 +1072,39 @@ class MParticleTestsSwift: XCTestCase { XCTAssertNotNil(completion) completion(loggedEvent, .success) } - + func testLogLTVIncreaseCallback_withSuccessExecStatus_noDataPlanFilter_forwardsEvent() { let event = MPEvent(name: "ltv", type: .transaction)! - + let dataPlanFilter = MPDataPlanFilterMock() dataPlanFilter.transformEventReturnValue = nil mparticle.dataPlanFilter = dataPlanFilter mparticle.logLTVIncreaseCallback(event, execStatus: .success) - + XCTAssertTrue(dataPlanFilter.transformEventCalled) XCTAssertTrue(dataPlanFilter.transformEventEventParam === event) XCTAssertEqual(receivedMessage, "mParticle -> Blocked LTV increase event from kits: \(event)") } - + func testLogLTVIncreaseCallback_withSuccessExecStatus_filterReturnsTransformedEvent_forwardsTransformedEvent() { let event = MPEvent(name: "ltv", type: .transaction)! let transformedEvent = MPEvent(name: "transformed-ltv", type: .other)! - + let dataPlanFilter = MPDataPlanFilterMock() dataPlanFilter.transformEventReturnValue = transformedEvent mparticle.dataPlanFilter = dataPlanFilter mparticle.logLTVIncreaseCallback(event, execStatus: .success) - + // Verify filter transformed event XCTAssertTrue(dataPlanFilter.transformEventCalled) XCTAssertTrue(dataPlanFilter.transformEventEventParam === event) - + // Verify executor usage XCTAssertTrue(executor.executeOnMainAsync) - + // Verify kit container forwarded transformed event XCTAssertTrue(kitContainer.forwardSDKCallCalled) XCTAssertEqual(kitContainer.forwardSDKCallSelectorParam?.description, "logLTVIncrease:event:") @@ -1139,8 +1134,7 @@ class MParticleTestsSwift: XCTestCase { Type: Other Duration: 0 } - """ - ) + """) } func testLeaveBreadcrumbCallback_withDataFilterSet_andDataFilterReturnNil() { @@ -1158,8 +1152,7 @@ class MParticleTestsSwift: XCTestCase { Type: Other Duration: 0 } - """ - ) + """) } func testLeaveBreadcrumbCallback_execStatusFail_noLoggedMessages() { @@ -1178,33 +1171,33 @@ class MParticleTestsSwift: XCTestCase { } func testLeaveBreadcrumb_eventNamePassed_backendControllerReceiveCorrectName() { - mparticle.leaveBreadcrumb("expectedEvent", eventInfo: ["key" : "value"]) + mparticle.leaveBreadcrumb("expectedEvent", eventInfo: ["key": "value"]) XCTAssertEqual(backendController.eventWithNameEventNameParam, "expectedEvent") } func testLeaveBreadcrumb_eventNamePassed_backendControllerReturnsNilEvent_newEventCreated() { - mparticle.leaveBreadcrumb("expectedEvent", eventInfo: ["key" : "value"]) + mparticle.leaveBreadcrumb("expectedEvent", eventInfo: ["key": "value"]) XCTAssertEqual(backendController.leaveBreadcrumbEventParam?.name, "expectedEvent") XCTAssertEqual(backendController.leaveBreadcrumbEventParam?.type, .other) XCTAssertNotNil(backendController.leaveBreadcrumbEventParam?.timestamp) - XCTAssertEqual(backendController.leaveBreadcrumbEventParam?.customAttributes as! [String : String], ["key" : "value"]) + XCTAssertEqual(backendController.leaveBreadcrumbEventParam?.customAttributes as! [String: String], ["key": "value"]) XCTAssertNotNil(backendController.leaveBreadcrumbCompletionHandler) } func testLeaveBreadcrumb_eventNamePassed_backendControllerReturnsEvent_eventModified() { let event = MPEvent(name: "expectedEvent", type: .navigation) backendController.eventSet?.add(event as Any) - mparticle.leaveBreadcrumb("expectedEvent", eventInfo: ["key" : "value"]) + mparticle.leaveBreadcrumb("expectedEvent", eventInfo: ["key": "value"]) XCTAssertEqual(backendController.leaveBreadcrumbEventParam?.name, "expectedEvent") XCTAssertEqual(backendController.leaveBreadcrumbEventParam?.type, .navigation) XCTAssertNotNil(backendController.leaveBreadcrumbEventParam?.timestamp) - XCTAssertEqual(backendController.leaveBreadcrumbEventParam?.customAttributes as! [String : String], ["key" : "value"]) + XCTAssertEqual(backendController.leaveBreadcrumbEventParam?.customAttributes as! [String: String], ["key": "value"]) XCTAssertNotNil(backendController.leaveBreadcrumbCompletionHandler) } func testLeaveBreadcrumb_eventNamePassed_CallbackCallsCallbackFunction() { let event = MPEvent(name: "expectedEvent", type: .navigation) - mparticle.leaveBreadcrumb("expectedEvent", eventInfo: ["key" : "value"]) + mparticle.leaveBreadcrumb("expectedEvent", eventInfo: ["key": "value"]) backendController.leaveBreadcrumbCompletionHandler?(event!, .success) XCTAssertEqual(receivedMessage, """ mParticle -> Left breadcrumb: Event:{ @@ -1212,7 +1205,6 @@ class MParticleTestsSwift: XCTestCase { Type: Navigation Duration: 0 } - """ - ) + """) } } diff --git a/UnitTests/Mocks/ExecutorMock.swift b/UnitTests/Mocks/ExecutorMock.swift index f6b43839a..618e4b577 100644 --- a/UnitTests/Mocks/ExecutorMock.swift +++ b/UnitTests/Mocks/ExecutorMock.swift @@ -5,39 +5,38 @@ // Created by Denis Chilik on 9/9/25. // - class ExecutorMock: ExecutorProtocol { func messageQueue() -> dispatch_queue_t { return DispatchQueue.main } - + func isMessageQueue() -> Bool { return false } - + var executeOnMessageQueueAsync: Bool = false - + func execute(onMessage block: (() -> Void)!) { executeOnMessageQueueAsync = true block() } - + var executeOnMessageQueueSync = false - + func execute(onMessageSync block: (() -> Void)!) { executeOnMessageQueueSync = true block() } - + var executeOnMainAsync = false - + func execute(onMain block: (() -> Void)!) { executeOnMainAsync = true block() } - + var executeOnMainSync = false - + func execute(onMainSync block: (() -> Void)!) { executeOnMainSync = true block() diff --git a/UnitTests/Mocks/MPBackendControllerMock.swift b/UnitTests/Mocks/MPBackendControllerMock.swift index 504cfa579..a7711922e 100644 --- a/UnitTests/Mocks/MPBackendControllerMock.swift +++ b/UnitTests/Mocks/MPBackendControllerMock.swift @@ -1,8 +1,8 @@ import XCTest #if MPARTICLE_LOCATION_DISABLE -import mParticle_Apple_SDK_NoLocation + import mParticle_Apple_SDK_NoLocation #else -import mParticle_Apple_SDK + import mParticle_Apple_SDK #endif class MPBackendControllerMock: NSObject, MPBackendControllerProtocol { @@ -12,6 +12,7 @@ class MPBackendControllerMock: NSObject, MPBackendControllerProtocol { var session: MPSession? // MARK: - Opt-out + var setOptOutCalled = false var setOptOutOptOutStatusParam: Bool? var setOptOutCompletionHandler: ((Bool, MPExecStatus) -> Void)? @@ -23,6 +24,7 @@ class MPBackendControllerMock: NSObject, MPBackendControllerProtocol { } // MARK: - User attributes + var userAttributesCalled = false var userAttributesUserIdParam: NSNumber? var userAttributesReturnValue: NSMutableDictionary = [:] @@ -34,6 +36,7 @@ class MPBackendControllerMock: NSObject, MPBackendControllerProtocol { } // MARK: - Start + var startCalled = false var startApiKeyParam: String? var startSecretParam: String? @@ -45,7 +48,17 @@ class MPBackendControllerMock: NSObject, MPBackendControllerProtocol { var startConsentStateParam: MPConsentState? var startCompletionHandler: (() -> Void)? - func start(withKey apiKey: String, secret: String, networkOptions: MPNetworkOptions?, firstRun: Bool, installationType: MPInstallationType, proxyAppDelegate: Bool, startKitsAsync: Bool, consentState: MPConsentState?, completionHandler: @escaping () -> Void) { + func start( + withKey apiKey: String, + secret: String, + networkOptions: MPNetworkOptions?, + firstRun: Bool, + installationType: MPInstallationType, + proxyAppDelegate: Bool, + startKitsAsync: Bool, + consentState: MPConsentState?, + completionHandler: @escaping () -> Void + ) { startCalled = true startApiKeyParam = apiKey startSecretParam = secret @@ -59,6 +72,7 @@ class MPBackendControllerMock: NSObject, MPBackendControllerProtocol { } // MARK: - Prepare batches + var prepareBatchesCalled = false var prepareBatchesUploadSettingsParam: MPUploadSettings? @@ -68,6 +82,7 @@ class MPBackendControllerMock: NSObject, MPBackendControllerProtocol { } // MARK: - Temp session + var tempSessionCalled = false var tempSessionReturnValue: MParticleSession? @@ -77,6 +92,7 @@ class MPBackendControllerMock: NSObject, MPBackendControllerProtocol { } // MARK: - App delegate proxying + var unproxyOriginalAppDelegateCalled = false func unproxyOriginalAppDelegate() { @@ -84,6 +100,7 @@ class MPBackendControllerMock: NSObject, MPBackendControllerProtocol { } // MARK: - Session lifecycle + var endSessionCalled = false func endSession() { @@ -101,6 +118,7 @@ class MPBackendControllerMock: NSObject, MPBackendControllerProtocol { } // MARK: - Events + var logEventCalled = false var logEventEventParam: MPEvent? var logEventCompletionHandler: ((MPEvent, MPExecStatus) -> Void)? @@ -123,6 +141,7 @@ class MPBackendControllerMock: NSObject, MPBackendControllerProtocol { } // MARK: - Base events + var logBaseEventCalled = false var logBaseEventEventParam: MPBaseEvent? var logBaseEventCompletionHandler: ((MPBaseEvent, MPExecStatus) -> Void)? @@ -134,28 +153,35 @@ class MPBackendControllerMock: NSObject, MPBackendControllerProtocol { } // MARK: - Commerce events + var logCommerceEventCalled = false var logCommerceEventParam: MPCommerceEvent? var logCommerceEventCompletionHandler: ((MPCommerceEvent, MPExecStatus) -> Void)? - func logCommerceEvent(_ commerceEvent: MPCommerceEvent, completionHandler: @escaping (MPCommerceEvent, MPExecStatus) -> Void) { + func logCommerceEvent(_ commerceEvent: MPCommerceEvent, + completionHandler: @escaping (MPCommerceEvent, MPExecStatus) -> Void) { logCommerceEventCalled = true logCommerceEventParam = commerceEvent logCommerceEventCompletionHandler = completionHandler } // MARK: - Network perf + var logNetworkPerformanceCalled = false var logNetworkPerformanceParam: MPNetworkPerformance? var logNetworkPerformanceCompletionHandler: ((MPNetworkPerformance, MPExecStatus) -> Void)? - func logNetworkPerformanceMeasurement(_ networkPerformance: MPNetworkPerformance, completionHandler: ((MPNetworkPerformance, MPExecStatus) -> Void)? = nil) { + func logNetworkPerformanceMeasurement( + _ networkPerformance: MPNetworkPerformance, + completionHandler: ((MPNetworkPerformance, MPExecStatus) -> Void)? = nil + ) { logNetworkPerformanceCalled = true logNetworkPerformanceParam = networkPerformance logNetworkPerformanceCompletionHandler = completionHandler } // MARK: - Screen + var logScreenCalled = false var logScreenEventParam: MPEvent? var logScreenCompletionHandler: ((MPEvent, MPExecStatus) -> Void)? @@ -167,6 +193,7 @@ class MPBackendControllerMock: NSObject, MPBackendControllerProtocol { } // MARK: - Breadcrumbs + var leaveBreadcrumbCalled = false var leaveBreadcrumbEventParam: MPEvent? var leaveBreadcrumbCompletionHandler: ((MPEvent, MPExecStatus) -> Void)? @@ -178,14 +205,21 @@ class MPBackendControllerMock: NSObject, MPBackendControllerProtocol { } // MARK: - Errors & Crashes + var logErrorCalled = false var logErrorMessageParam: String? var logErrorExceptionParam: NSException? var logErrorTopmostContextParam: Any? - var logErrorEventInfoParam: [AnyHashable : Any]? + var logErrorEventInfoParam: [AnyHashable: Any]? var logErrorCompletionHandler: ((String?, MPExecStatus) -> Void)? - func logError(_ message: String?, exception: NSException?, topmostContext: Any?, eventInfo: [AnyHashable : Any]?, completionHandler: @escaping (String?, MPExecStatus) -> Void) { + func logError( + _ message: String?, + exception: NSException?, + topmostContext: Any?, + eventInfo: [AnyHashable: Any]?, + completionHandler: @escaping (String?, MPExecStatus) -> Void + ) { logErrorCalled = true logErrorMessageParam = message logErrorExceptionParam = exception @@ -200,7 +234,12 @@ class MPBackendControllerMock: NSObject, MPBackendControllerProtocol { var logCrashPlReportParam: String? var logCrashCompletionHandler: ((String?, MPExecStatus) -> Void)? - func logCrash(_ message: String?, stackTrace: String?, plCrashReport: String, completionHandler: @escaping (String?, MPExecStatus) -> Void) { + func logCrash( + _ message: String?, + stackTrace: String?, + plCrashReport: String, + completionHandler: @escaping (String?, MPExecStatus) -> Void + ) { logCrashCalled = true logCrashMessageParam = message logCrashStackTraceParam = stackTrace @@ -209,13 +248,14 @@ class MPBackendControllerMock: NSObject, MPBackendControllerProtocol { } // MARK: - Session attributes + var sessionAttributesStore: [String: Any] = [:] var setSessionAttributeCalled = false var setSessionAttributeKeyParam: String? var setSessionAttributeValueParam: Any? var setSessionAttributeReturnValue = MPExecStatus.success - func setSessionAttribute(_ session: MPSession, key: String, value: Any) -> MPExecStatus { + func setSessionAttribute(_: MPSession, key: String, value: Any) -> MPExecStatus { setSessionAttributeCalled = true setSessionAttributeKeyParam = key setSessionAttributeValueParam = value @@ -228,7 +268,7 @@ class MPBackendControllerMock: NSObject, MPBackendControllerProtocol { var incrementSessionAttributeByValueParam: NSNumber? var incrementSessionAttributeReturnValue: NSNumber? - func incrementSessionAttribute(_ session: MPSession, key: String, byValue value: NSNumber) -> NSNumber? { + func incrementSessionAttribute(_: MPSession, key: String, byValue value: NSNumber) -> NSNumber? { incrementSessionAttributeCalled = true incrementSessionAttributeKeyParam = key incrementSessionAttributeByValueParam = value @@ -237,6 +277,7 @@ class MPBackendControllerMock: NSObject, MPBackendControllerProtocol { } // MARK: - Session mgmt + var createTempSessionCalled = false func createTempSession() { @@ -263,6 +304,7 @@ class MPBackendControllerMock: NSObject, MPBackendControllerProtocol { } // MARK: - Upload & Kits + var waitForKitsAndUploadCalled = false var waitForKitsAndUploadCompletionHandler: (() -> Void)? var waitForKitsAndUploadReturnValue: MPExecStatus = .success @@ -272,38 +314,47 @@ class MPBackendControllerMock: NSObject, MPBackendControllerProtocol { waitForKitsAndUploadCompletionHandler = completionHandler return waitForKitsAndUploadReturnValue } -#if os(iOS) -#if !MPARTICLE_LOCATION_DISABLE - // MARK: - Location - var beginLocationTrackingCalled = false - var beginLocationTrackingAccuracyParam: CLLocationAccuracy? - var beginLocationTrackingDistanceParam: CLLocationDistance? - var beginLocationTrackingAuthParam: MPLocationAuthorizationRequest? - var beginLocationTrackingReturnValue: MPExecStatus = .success - - func beginLocationTracking(withAccuracy accuracy: CLLocationAccuracy, distanceFilter distance: CLLocationDistance, authorizationRequest: MPLocationAuthorizationRequest) -> MPExecStatus { - beginLocationTrackingCalled = true - beginLocationTrackingAccuracyParam = accuracy - beginLocationTrackingDistanceParam = distance - beginLocationTrackingAuthParam = authorizationRequest - return beginLocationTrackingReturnValue - } - - var endLocationTrackingCalled = false - var endLocationTrackingReturnValue: MPExecStatus = .success - - func endLocationTracking() -> MPExecStatus { - endLocationTrackingCalled = true - return endLocationTrackingReturnValue - } -#endif - // MARK: - Notifications - var logUserNotificationCalled = false - var logUserNotificationParam: MParticleUserNotification? - func logUserNotification(_ userNotification: MParticleUserNotification) { - logUserNotificationCalled = true - logUserNotificationParam = userNotification - } -#endif + #if os(iOS) + #if !MPARTICLE_LOCATION_DISABLE + + // MARK: - Location + + var beginLocationTrackingCalled = false + var beginLocationTrackingAccuracyParam: CLLocationAccuracy? + var beginLocationTrackingDistanceParam: CLLocationDistance? + var beginLocationTrackingAuthParam: MPLocationAuthorizationRequest? + var beginLocationTrackingReturnValue: MPExecStatus = .success + + func beginLocationTracking( + withAccuracy accuracy: CLLocationAccuracy, + distanceFilter distance: CLLocationDistance, + authorizationRequest: MPLocationAuthorizationRequest + ) -> MPExecStatus { + beginLocationTrackingCalled = true + beginLocationTrackingAccuracyParam = accuracy + beginLocationTrackingDistanceParam = distance + beginLocationTrackingAuthParam = authorizationRequest + return beginLocationTrackingReturnValue + } + + var endLocationTrackingCalled = false + var endLocationTrackingReturnValue: MPExecStatus = .success + + func endLocationTracking() -> MPExecStatus { + endLocationTrackingCalled = true + return endLocationTrackingReturnValue + } + #endif + + // MARK: - Notifications + + var logUserNotificationCalled = false + var logUserNotificationParam: MParticleUserNotification? + + func logUserNotification(_ userNotification: MParticleUserNotification) { + logUserNotificationCalled = true + logUserNotificationParam = userNotification + } + #endif } diff --git a/UnitTests/Mocks/MPDataPlanFilterMock.swift b/UnitTests/Mocks/MPDataPlanFilterMock.swift index 155b9435c..591fc2533 100644 --- a/UnitTests/Mocks/MPDataPlanFilterMock.swift +++ b/UnitTests/Mocks/MPDataPlanFilterMock.swift @@ -1,8 +1,8 @@ import XCTest #if MPARTICLE_LOCATION_DISABLE -import mParticle_Apple_SDK_NoLocation + import mParticle_Apple_SDK_NoLocation #else -import mParticle_Apple_SDK + import mParticle_Apple_SDK #endif @objcMembers @@ -10,57 +10,57 @@ class MPDataPlanFilterMock: NSObject, MPDataPlanFilterProtocol { var isBlockedUserIdentityTypeCalled = false var isBlockedUserIdentityTypeUserIdentityTypeParam: MPIdentity? var isBlockedUserIdentityTypeReturnValue: Bool = false - + func isBlockedUserIdentityType(_ userIdentityType: MPIdentity) -> Bool { isBlockedUserIdentityTypeCalled = true isBlockedUserIdentityTypeUserIdentityTypeParam = userIdentityType return isBlockedUserIdentityTypeReturnValue } - + var isBlockedUserAttributeKeyCalled = false var isBlockedUserAttributeKeyUserAttributeKeyParam: String? var isBlockedUserAttributeKeyReturnValue: Bool = false - + func isBlockedUserAttributeKey(_ userAttributeKey: String) -> Bool { isBlockedUserAttributeKeyCalled = true isBlockedUserAttributeKeyUserAttributeKeyParam = userAttributeKey return isBlockedUserAttributeKeyReturnValue } - + var transformEventCalled = false var transformEventEventParam: MPEvent? var transformEventReturnValue: MPEvent? - + func transformEvent(for event: MPEvent) -> MPEvent? { transformEventCalled = true transformEventEventParam = event return transformEventReturnValue } - + var transformEventForScreenEventCalled = false var transformEventForScreenEventScreenEventParam: MPEvent? var transformEventForScreenEventReturnValue: MPEvent? - + func transformEvent(forScreenEvent screenEvent: MPEvent) -> MPEvent? { transformEventForScreenEventCalled = true transformEventForScreenEventScreenEventParam = screenEvent return transformEventForScreenEventReturnValue } - + var transformEventForCommerceEventCalled = false var transformEventForCommerceEventParam: MPCommerceEvent? var transformEventForCommerceEventReturnValue: MPCommerceEvent? - + func transformEvent(forCommerceEvent commerceEvent: MPCommerceEvent) -> MPCommerceEvent? { transformEventForCommerceEventCalled = true transformEventForCommerceEventParam = commerceEvent return transformEventForCommerceEventReturnValue } - + var transformEventForBaseEventCalled = false var transformEventForBaseEventParam: MPBaseEvent? var transformEventForBaseEventReturnValue: MPBaseEvent? - + func transformEvent(forBaseEvent baseEvent: MPBaseEvent) -> MPBaseEvent? { transformEventForBaseEventCalled = true transformEventForBaseEventParam = baseEvent diff --git a/UnitTests/Mocks/MPKitContainerMock.swift b/UnitTests/Mocks/MPKitContainerMock.swift index 5d2972295..a63d4f713 100644 --- a/UnitTests/Mocks/MPKitContainerMock.swift +++ b/UnitTests/Mocks/MPKitContainerMock.swift @@ -1,38 +1,39 @@ import XCTest #if MPARTICLE_LOCATION_DISABLE -import mParticle_Apple_SDK_NoLocation + import mParticle_Apple_SDK_NoLocation #else -import mParticle_Apple_SDK + import mParticle_Apple_SDK #endif class MPKitContainerMock: MPKitContainerProtocol { - var attributionInfo: NSMutableDictionary = NSMutableDictionary() - + var attributionInfo: NSMutableDictionary = .init() + var kitsInitialized: Bool = false - + var forwardCommerceEventCallCalled = false var forwardCommerceEventCallCommerceEventParam: MPCommerceEvent? - + func forwardCommerceEventCall(_ commerceEvent: MPCommerceEvent) { forwardCommerceEventCallCalled = true forwardCommerceEventCallCommerceEventParam = commerceEvent } - + var forwardSDKCallCalled = false var forwardSDKCallSelectorParam: Selector? - var forwardSDKCallKitHandlerParam: ((any MPKitProtocol, [AnyHashable : Any], MPKitConfiguration) -> Void)? + var forwardSDKCallKitHandlerParam: ((any MPKitProtocol, [AnyHashable: Any], MPKitConfiguration) -> Void)? var forwardSDKCallExpectation: XCTestExpectation? - + var forwardSDKCallEventParam: MPBaseEvent? var forwardSDKCallParametersParam: MPForwardQueueParameters? var forwardSDKCallMessageTypeParam: MPMessageType? - var forwardSDKCallUserInfoParam: [AnyHashable : Any]? - + var forwardSDKCallUserInfoParam: [AnyHashable: Any]? + func forwardSDKCall(_ selector: Selector, event: MPBaseEvent?, parameters: MPForwardQueueParameters?, messageType: MPMessageType, - userInfo: [AnyHashable : Any]? = nil) { + userInfo: [AnyHashable: Any]? = nil) + { forwardSDKCallCalled = true forwardSDKCallSelectorParam = selector forwardSDKCallEventParam = event @@ -41,60 +42,62 @@ class MPKitContainerMock: MPKitContainerProtocol { forwardSDKCallUserInfoParam = userInfo forwardSDKCallExpectation?.fulfill() } - - var forwardSDKCallBatchParam: [AnyHashable : Any]? - + + var forwardSDKCallBatchParam: [AnyHashable: Any]? + func forwardSDKCall(_ selector: Selector, - batch: [AnyHashable : Any], - kitHandler: @escaping (any MPKitProtocol, [AnyHashable : Any], MPKitConfiguration) -> Void) { + batch: [AnyHashable: Any], + kitHandler: @escaping (any MPKitProtocol, [AnyHashable: Any], MPKitConfiguration) -> Void) + { forwardSDKCallCalled = true forwardSDKCallSelectorParam = selector forwardSDKCallBatchParam = batch forwardSDKCallKitHandlerParam = kitHandler forwardSDKCallExpectation?.fulfill() } - - var forwardSDKCallUserAttributes: [AnyHashable : Any]? - + + var forwardSDKCallUserAttributes: [AnyHashable: Any]? + func forwardSDKCall(_ selector: Selector, - userAttributes: [AnyHashable : Any] = [:], - kitHandler: @escaping (any MPKitProtocol, [AnyHashable : Any]?, MPKitConfiguration) -> Void) { + userAttributes: [AnyHashable: Any] = [:], + kitHandler: @escaping (any MPKitProtocol, [AnyHashable: Any]?, MPKitConfiguration) -> Void) + { forwardSDKCallCalled = true forwardSDKCallSelectorParam = selector forwardSDKCallUserAttributes = userAttributes forwardSDKCallKitHandlerParam = kitHandler forwardSDKCallExpectation?.fulfill() } - + var configureKitsCalled = false - var configureKitsKitsConfigurationParam: [[AnyHashable : Any]]? - - func configureKits(_ kitsConfiguration: [[AnyHashable : Any]]?) { + var configureKitsKitsConfigurationParam: [[AnyHashable: Any]]? + + func configureKits(_ kitsConfiguration: [[AnyHashable: Any]]?) { configureKitsCalled = true configureKitsKitsConfigurationParam = kitsConfiguration } - + var removeKitsFromRegistryInvalidForWorkspaceSwitchCalled = false - + func removeKitsFromRegistryInvalidForWorkspaceSwitch() { removeKitsFromRegistryInvalidForWorkspaceSwitchCalled = true } - + var flushSerializedKitsCalled = false - + func flushSerializedKits() { flushSerializedKitsCalled = true } - + var removeAllSideloadedKitsCalled = false - + func removeAllSideloadedKits() { removeAllSideloadedKitsCalled = true } - + var hasKitBatchingKitsCalled = false var hasKitBatchingKitsReturnValue: Bool = false - + func hasKitBatchingKits() -> Bool { hasKitBatchingKitsCalled = true return hasKitBatchingKitsReturnValue diff --git a/UnitTests/Mocks/MPListenerControllerMock.swift b/UnitTests/Mocks/MPListenerControllerMock.swift index f7d9da68a..4ea38f484 100644 --- a/UnitTests/Mocks/MPListenerControllerMock.swift +++ b/UnitTests/Mocks/MPListenerControllerMock.swift @@ -2,31 +2,31 @@ import XCTest class MPListenerControllerMock: NSObject, MPListenerControllerProtocol { var onAPICalledCalled = false - + var onAPICalledApiNames = [Selector]() - + var onAPICalledApiName: Selector? { return onAPICalledApiNames.first } - + var onAPICalledParameter1: NSObject? var onAPICalledExpectation: XCTestExpectation? - + func onAPICalled(_ apiName: Selector) { onAPICalledCalled = true onAPICalledApiNames.append(apiName) onAPICalledExpectation?.fulfill() } - + func onAPICalled(_ apiName: Selector, parameter1: NSObject?) { onAPICalledCalled = true onAPICalledApiNames.append(apiName) onAPICalledParameter1 = parameter1 onAPICalledExpectation?.fulfill() } - + var onAPICalledParameter2: NSObject? - + func onAPICalled(_ apiName: Selector, parameter1: NSObject?, parameter2: NSObject?) { onAPICalledCalled = true onAPICalledApiNames.append(apiName) @@ -34,9 +34,9 @@ class MPListenerControllerMock: NSObject, MPListenerControllerProtocol { onAPICalledParameter2 = parameter2 onAPICalledExpectation?.fulfill() } - + var onAPICalledParameter3: NSObject? - + func onAPICalled(_ apiName: Selector, parameter1: NSObject?, parameter2: NSObject?, parameter3: NSObject?) { onAPICalledCalled = true onAPICalledApiNames.append(apiName) diff --git a/UnitTests/Mocks/MPPersistenceControllerMock.swift b/UnitTests/Mocks/MPPersistenceControllerMock.swift index 8e2f0c585..ba8570748 100644 --- a/UnitTests/Mocks/MPPersistenceControllerMock.swift +++ b/UnitTests/Mocks/MPPersistenceControllerMock.swift @@ -1,52 +1,51 @@ import XCTest #if MPARTICLE_LOCATION_DISABLE -import mParticle_Apple_SDK_NoLocation + import mParticle_Apple_SDK_NoLocation #else -import mParticle_Apple_SDK + import mParticle_Apple_SDK #endif class MPPersistenceControllerMock: MPPersistenceControllerProtocol { var resetDatabaseForWorkspaceSwitchingCalled = false - + func resetDatabaseForWorkspaceSwitching() { resetDatabaseForWorkspaceSwitchingCalled = true } - + var resetDatabaseCalled = false - + func resetDatabase() { resetDatabaseCalled = true } - + var saveCelled = false var saveForwardRecordParam: MPForwardRecord? - + func save(_ forwardRecord: MPForwardRecord) { saveCelled = true saveForwardRecordParam = forwardRecord } - - + var saveIntegrationAttributesParam: MPIntegrationAttributes? - + func save(_ integrationAttributes: MPIntegrationAttributes) { saveCelled = true saveIntegrationAttributesParam = integrationAttributes } - + var deleteIntegrationAttributesCalled = false var deleteIntegrationAttributesIntegrationIdParam: NSNumber? - + func deleteIntegrationAttributes(forIntegrationId integrationId: NSNumber) { deleteIntegrationAttributesCalled = true deleteIntegrationAttributesIntegrationIdParam = integrationId } - + var fetchIntegrationAttributesCalled = false var fetchIntegrationAttributesIntegrationIdParam: NSNumber? - var fetchIntegrationAttributesReturnValue: [AnyHashable : Any]? - - func fetchIntegrationAttributes(forId integrationId: NSNumber) -> [AnyHashable : Any]? { + var fetchIntegrationAttributesReturnValue: [AnyHashable: Any]? + + func fetchIntegrationAttributes(forId integrationId: NSNumber) -> [AnyHashable: Any]? { fetchIntegrationAttributesCalled = true fetchIntegrationAttributesIntegrationIdParam = integrationId return fetchIntegrationAttributesReturnValue diff --git a/UnitTests/Mocks/MPStateMachineMock.swift b/UnitTests/Mocks/MPStateMachineMock.swift index e425b0761..bc10601f4 100644 --- a/UnitTests/Mocks/MPStateMachineMock.swift +++ b/UnitTests/Mocks/MPStateMachineMock.swift @@ -1,32 +1,32 @@ import XCTest #if MPARTICLE_LOCATION_DISABLE -import mParticle_Apple_SDK_NoLocation + import mParticle_Apple_SDK_NoLocation #else -import mParticle_Apple_SDK -import CoreLocation + import CoreLocation + import mParticle_Apple_SDK #endif class MPStateMachineMock: MPStateMachineProtocol { -#if !MPARTICLE_LOCATION_DISABLE - var location: CLLocation? = nil - - var locationManager: mParticle_Apple_SDK.MPLocationManager_PRIVATE? -#endif + #if !MPARTICLE_LOCATION_DISABLE + var location: CLLocation? + + var locationManager: mParticle_Apple_SDK.MPLocationManager_PRIVATE? + #endif var optOut: Bool = false - + var logLevel: MPILogLevel = .none - - var consumerInfo: MPConsumerInfo = MPConsumerInfo() - + + var consumerInfo: MPConsumerInfo = .init() + var automaticSessionTracking: Bool = false - + var currentSession: MPSession? = nil - + var attAuthorizationStatus: NSNumber? = nil - + var attAuthorizationTimestamp: NSNumber? = nil - + var apiKey: String = "apiKey" - + var secret: String = "secret" } diff --git a/UnitTests/Mocks/MPUserDefaultsMock.swift b/UnitTests/Mocks/MPUserDefaultsMock.swift index 821d61b49..4bf334b1b 100644 --- a/UnitTests/Mocks/MPUserDefaultsMock.swift +++ b/UnitTests/Mocks/MPUserDefaultsMock.swift @@ -1,29 +1,26 @@ import XCTest #if MPARTICLE_LOCATION_DISABLE -import mParticle_Apple_SDK_NoLocation + import mParticle_Apple_SDK_NoLocation #else -import mParticle_Apple_SDK + import mParticle_Apple_SDK #endif - class MPUserDefaultsMock: MPUserDefaultsProtocol { var setMPObjectCalled = false var setMPObjectValueParam: Any? var setMPObjectKeyParam: String? var setMPObjectUserIdParam: NSNumber? - + func setMPObject(_ value: Any?, forKey key: String, userId: NSNumber) { setMPObjectCalled = true setMPObjectValueParam = value setMPObjectKeyParam = key setMPObjectUserIdParam = userId } - + var synchronizeCalled = false - + func synchronize() { synchronizeCalled = true } } - - diff --git a/UnitTests/Mocks/SettingsProviderMock.swift b/UnitTests/Mocks/SettingsProviderMock.swift index 4cbcedcea..85709e9b0 100644 --- a/UnitTests/Mocks/SettingsProviderMock.swift +++ b/UnitTests/Mocks/SettingsProviderMock.swift @@ -1,8 +1,8 @@ import XCTest #if MPARTICLE_LOCATION_DISABLE -import mParticle_Apple_SDK_NoLocation + import mParticle_Apple_SDK_NoLocation #else -import mParticle_Apple_SDK + import mParticle_Apple_SDK #endif class SettingsProviderMock: NSObject, SettingsProviderProtocol { diff --git a/UnitTests/NSArray+MPCaseInsensitiveTests.swift b/UnitTests/NSArray+MPCaseInsensitiveTests.swift index cfdfa9941..dafd2dea1 100644 --- a/UnitTests/NSArray+MPCaseInsensitiveTests.swift +++ b/UnitTests/NSArray+MPCaseInsensitiveTests.swift @@ -1,17 +1,14 @@ import XCTest #if MPARTICLE_LOCATION_DISABLE -import mParticle_Apple_SDK_NoLocation + import mParticle_Apple_SDK_NoLocation #else -import mParticle_Apple_SDK + import mParticle_Apple_SDK #endif class NSArray_MPCaseInsensitiveTests: XCTestCase { + override func setUp() {} - override func setUp() { - } - - override func tearDown() { - } + override func tearDown() {} func testArrayTrue() { let array = ["someWord", "someOtherWord", "ABC", "AbCdEF"] @@ -20,7 +17,7 @@ class NSArray_MPCaseInsensitiveTests: XCTestCase { XCTAssertTrue(array.caseInsensitiveContainsObject("someotherword")) XCTAssertTrue(array.caseInsensitiveContainsObject("abcdef")) } - + func testArrayFalse() { let array = ["someWord", "someOtherWord", "ABC", "AbCdEF"] XCTAssertFalse(array.caseInsensitiveContainsObject("somWord")) @@ -28,7 +25,7 @@ class NSArray_MPCaseInsensitiveTests: XCTestCase { XCTAssertFalse(array.caseInsensitiveContainsObject("someotherwords")) XCTAssertFalse(array.caseInsensitiveContainsObject("abcdefg")) } - + func testNSArrayTrue() { let nsArray = ["someWord", "someOtherWord", "ABC", "AbCdEF"] as NSArray XCTAssertTrue(nsArray.caseInsensitiveContainsObject("someWord")) @@ -36,7 +33,7 @@ class NSArray_MPCaseInsensitiveTests: XCTestCase { XCTAssertTrue(nsArray.caseInsensitiveContainsObject("someotherword")) XCTAssertTrue(nsArray.caseInsensitiveContainsObject("abcdef")) } - + func testNSArrayFalse() { let nsArray = ["someWord", "someOtherWord", "ABC", "AbCdEF"] as NSArray XCTAssertFalse(nsArray.caseInsensitiveContainsObject("somWord")) diff --git a/UnitTests/NSString+MPPercentEscapeTests.swift b/UnitTests/NSString+MPPercentEscapeTests.swift index 17b564e82..e3a844bf8 100644 --- a/UnitTests/NSString+MPPercentEscapeTests.swift +++ b/UnitTests/NSString+MPPercentEscapeTests.swift @@ -1,21 +1,28 @@ import XCTest #if MPARTICLE_LOCATION_DISABLE -import mParticle_Apple_SDK_NoLocation + import mParticle_Apple_SDK_NoLocation #else -import mParticle_Apple_SDK + import mParticle_Apple_SDK #endif class NSString_MPPercentEscapeTests: XCTestCase { + override func setUp() {} - override func setUp() { - } - - override func tearDown() { - } + override func tearDown() {} func testPercentEscape() { - let array = ["288160084=2832403&-515079401=2832403&1546594223=2832403&264784951=2832403&4151713=2832403&-1663781220=2832403", "Test;Testing", "Test Testing", "AbCdEF"] - let escapedArray = ["288160084=2832403&-515079401=2832403&1546594223=2832403&264784951=2832403&4151713=2832403&-1663781220=2832403", "Test%3BTesting", "Test%20Testing", "AbCdEF"] + let array = [ + "288160084=2832403&-515079401=2832403&1546594223=2832403&264784951=2832403&4151713=2832403&-1663781220=2832403", + "Test;Testing", + "Test Testing", + "AbCdEF" + ] + let escapedArray = [ + "288160084=2832403&-515079401=2832403&1546594223=2832403&264784951=2832403&4151713=2832403&-1663781220=2832403", + "Test%3BTesting", + "Test%20Testing", + "AbCdEF" + ] XCTAssertEqual(array[0].percentEscape(), escapedArray[0]) XCTAssertEqual(array[1].percentEscape(), escapedArray[1]) diff --git a/UnitTests/SettingsProviderTests.swift b/UnitTests/SettingsProviderTests.swift index d011c7f6e..9c5400eba 100644 --- a/UnitTests/SettingsProviderTests.swift +++ b/UnitTests/SettingsProviderTests.swift @@ -1,15 +1,14 @@ import XCTest #if MPARTICLE_LOCATION_DISABLE -import mParticle_Apple_SDK_NoLocation + import mParticle_Apple_SDK_NoLocation #else -import mParticle_Apple_SDK + import mParticle_Apple_SDK #endif class SettingsProviderTests: XCTestCase { - func testDefaultConfiguration() { let settingsProvider = SettingsProvider() - + let config = settingsProvider.configSettings XCTAssertEqual(config, nil) } diff --git a/mParticle-Apple-SDK/Consent/MPCCPAConsent.swift b/mParticle-Apple-SDK/Consent/MPCCPAConsent.swift index 6ce8d6a40..5a2568405 100644 --- a/mParticle-Apple-SDK/Consent/MPCCPAConsent.swift +++ b/mParticle-Apple-SDK/Consent/MPCCPAConsent.swift @@ -11,34 +11,33 @@ import Foundation * Record of consent under the CCPA. */ @objc public final class MPCCPAConsent: NSObject, NSCopying { - /** - * Whether the user consented to data collection - This should be set to false if the user has opted out of data sharing under the CCPA. - */ + * Whether the user consented to data collection + This should be set to false if the user has opted out of data sharing under the CCPA. + */ @objc public var consented = false - + /** - * The data collection document to which the user consented or did not consent - */ + * The data collection document to which the user consented or did not consent + */ @objc public var document: String? - + /** - * Timestamp when the user was prompted for consent - */ + * Timestamp when the user was prompted for consent + */ @objc public var timestamp = Date() - + /** - * Where the consent prompt took place. This can be a physical or digital location (e.g. URL) - */ + * Where the consent prompt took place. This can be a physical or digital location (e.g. URL) + */ @objc public var location: String? - + /** - * The device ID associated with this consent record - */ + * The device ID associated with this consent record + */ @objc public var hardwareId: String? - - @objc public func copy(with zone: NSZone? = nil) -> Any { + + @objc public func copy(with _: NSZone? = nil) -> Any { let copy = MPCCPAConsent() copy.consented = consented copy.document = document diff --git a/mParticle-Apple-SDK/Consent/MPGDPRConsent.swift b/mParticle-Apple-SDK/Consent/MPGDPRConsent.swift index a54fdfb4a..709bfb287 100644 --- a/mParticle-Apple-SDK/Consent/MPGDPRConsent.swift +++ b/mParticle-Apple-SDK/Consent/MPGDPRConsent.swift @@ -10,35 +10,33 @@ import Foundation /** * Record of consent under the GDPR. */ -@objc public class MPGDPRConsent : NSObject, NSCopying { - - +@objc public class MPGDPRConsent: NSObject, NSCopying { /** - * Whether the user consented to data collection - */ + * Whether the user consented to data collection + */ @objc public var consented = false /** - * The data collection document to which the user consented or did not consent - */ + * The data collection document to which the user consented or did not consent + */ @objc public var document: String? /** - * Timestamp when the user was prompted for consent - */ + * Timestamp when the user was prompted for consent + */ @objc public var timestamp = Date() /** - * Where the consent prompt took place. This can be a physical or digital location (e.g. URL) - */ + * Where the consent prompt took place. This can be a physical or digital location (e.g. URL) + */ @objc public var location: String? /** - * The device ID associated with this consent record - */ + * The device ID associated with this consent record + */ @objc public var hardwareId: String? - - @objc public func copy(with zone: NSZone? = nil) -> Any { + + @objc public func copy(with _: NSZone? = nil) -> Any { let copy = MPGDPRConsent() copy.consented = consented copy.document = document @@ -48,4 +46,3 @@ import Foundation return copy } } - diff --git a/mParticle-Apple-SDK/Identity/MPUserIdentityChange.swift b/mParticle-Apple-SDK/Identity/MPUserIdentityChange.swift index 23348f437..e4aa54765 100644 --- a/mParticle-Apple-SDK/Identity/MPUserIdentityChange.swift +++ b/mParticle-Apple-SDK/Identity/MPUserIdentityChange.swift @@ -5,12 +5,11 @@ // Created by Ben Baron on 12/3/24. // -@objc public final class MPUserIdentityChange_PRIVATE : NSObject { - +@objc public final class MPUserIdentityChange_PRIVATE: NSObject { @objc public var newUserIdentity: MPUserIdentityInstance_PRIVATE? @objc public var oldUserIdentity: MPUserIdentityInstance_PRIVATE? @objc public private(set) var changed = false - + private var _timestamp: Date? @objc public var timestamp: Date? { get { @@ -24,25 +23,29 @@ } } - @objc public init(newUserIdentity: MPUserIdentityInstance_PRIVATE?, userIdentities: [[String : Any]]?) { + @objc public init(newUserIdentity: MPUserIdentityInstance_PRIVATE?, userIdentities: [[String: Any]]?) { self.newUserIdentity = newUserIdentity - self.changed = true - + changed = true + if let userIdentities = userIdentities { for ui in userIdentities { if let idTypeInt = ui[MessageKeys.kMPUserIdentityTypeKey] as? UInt, - let idType = MPUserIdentity(rawValue: idTypeInt), - let idValue = ui[MessageKeys.kMPUserIdentityIdKey] as? String, - idType == newUserIdentity?.type && idValue == newUserIdentity?.value { - - self.changed = false + let idType = MPUserIdentity(rawValue: idTypeInt), + let idValue = ui[MessageKeys.kMPUserIdentityIdKey] as? String, + idType == newUserIdentity?.type && idValue == newUserIdentity?.value { + changed = false break } } } } - @objc public convenience init(newUserIdentity: MPUserIdentityInstance_PRIVATE?, oldUserIdentity: MPUserIdentityInstance_PRIVATE?, timestamp: Date?, userIdentities: [[String : Any]]?) { + @objc public convenience init( + newUserIdentity: MPUserIdentityInstance_PRIVATE?, + oldUserIdentity: MPUserIdentityInstance_PRIVATE?, + timestamp: Date?, + userIdentities: [[String: Any]]? + ) { self.init(newUserIdentity: newUserIdentity, userIdentities: userIdentities) self.oldUserIdentity = oldUserIdentity self.timestamp = timestamp diff --git a/mParticle-Apple-SDK/Identity/MPUserIdentityInstance.swift b/mParticle-Apple-SDK/Identity/MPUserIdentityInstance.swift index 20f959cc5..58bda483c 100644 --- a/mParticle-Apple-SDK/Identity/MPUserIdentityInstance.swift +++ b/mParticle-Apple-SDK/Identity/MPUserIdentityInstance.swift @@ -5,8 +5,7 @@ // Created by Ben Baron on 12/3/24. // -@objc public final class MPUserIdentityInstance_PRIVATE : NSObject { - +@objc public final class MPUserIdentityInstance_PRIVATE: NSObject { @objc public var value: String? @objc public var dateFirstSet: Date? @objc public var type: MPUserIdentity @@ -24,12 +23,12 @@ self.isFirstTimeSet = isFirstTimeSet } - @objc public convenience init(userIdentityDictionary: [String : Any]) { + @objc public convenience init(userIdentityDictionary: [String: Any]) { let typeInt = userIdentityDictionary[MessageKeys.kMPUserIdentityTypeKey] as? UInt ?? 0 let type = MPUserIdentity(rawValue: typeInt) ?? .other let value = userIdentityDictionary[MessageKeys.kMPUserIdentityIdKey] as? String let firstSetMillis = userIdentityDictionary[MessageKeys.kMPDateUserIdentityWasFirstSet] as? Double ?? 0.0 - let dateFirstSet = Date(timeIntervalSince1970: firstSetMillis / 1000.0) + let dateFirstSet = Date(timeIntervalSince1970: firstSetMillis/1000.0) let isFirstSet = userIdentityDictionary[MessageKeys.kMPIsFirstTimeUserIdentityHasBeenSet] as? Bool ?? false self.init(type: type, value: value, dateFirstSet: dateFirstSet, isFirstTimeSet: isFirstSet) } @@ -39,15 +38,16 @@ var identityDictionary = [AnyHashable: Any]() identityDictionary[MessageKeys.kMPUserIdentityTypeKey] = type.rawValue identityDictionary[MessageKeys.kMPIsFirstTimeUserIdentityHasBeenSet] = isFirstTimeSet - + if let dateFirstSet = dateFirstSet { - identityDictionary[MessageKeys.kMPDateUserIdentityWasFirstSet] = MPMilliseconds(timestamp: dateFirstSet.timeIntervalSince1970) + identityDictionary[MessageKeys.kMPDateUserIdentityWasFirstSet] = MPMilliseconds(timestamp: dateFirstSet + .timeIntervalSince1970) } - + if let value = value { identityDictionary[MessageKeys.kMPUserIdentityIdKey] = value } - + return NSMutableDictionary(dictionary: identityDictionary) } } diff --git a/mParticle-Apple-SDK/Kits/MPSideloadedKit.swift b/mParticle-Apple-SDK/Kits/MPSideloadedKit.swift index f4f2fa8eb..868d88e53 100644 --- a/mParticle-Apple-SDK/Kits/MPSideloadedKit.swift +++ b/mParticle-Apple-SDK/Kits/MPSideloadedKit.swift @@ -9,110 +9,120 @@ import Foundation @objc public class MPSideloadedKit: NSObject { @objc public var kitInstance: MPKitProtocol - - private var eventTypeFilters: [String:Any] = [:] - private var eventNameFilters: [String:Any] = [:] - private var eventAttributeFilters: [String:Any] = [:] - private var messageTypeFilters: [String:Any] = [:] - private var screenNameFilters: [String:Any] = [:] - private var screenAttributeFilters: [String:Any] = [:] - private var userIdentityFilters: [String:Any] = [:] - private var userAttributeFilters: [String:Any] = [:] - private var commerceEventAttributeFilters: [String:Any] = [:] - private var commerceEventEntityTypeFilters: [String:Any] = [:] - private var commerceEventAppFamilyAttributeFilters: [String:Any] = [:] - private var attributeValueFiltering: [String:Any] = [:] - + + private var eventTypeFilters: [String: Any] = [:] + private var eventNameFilters: [String: Any] = [:] + private var eventAttributeFilters: [String: Any] = [:] + private var messageTypeFilters: [String: Any] = [:] + private var screenNameFilters: [String: Any] = [:] + private var screenAttributeFilters: [String: Any] = [:] + private var userIdentityFilters: [String: Any] = [:] + private var userAttributeFilters: [String: Any] = [:] + private var commerceEventAttributeFilters: [String: Any] = [:] + private var commerceEventEntityTypeFilters: [String: Any] = [:] + private var commerceEventAppFamilyAttributeFilters: [String: Any] = [:] + private var attributeValueFiltering: [String: Any] = [:] + // MUST also include the following keys with empty dictionaries as the values, or the SDK will crash - private var addEventAttributeList: [String:Any] = [:] - private var removeEventAttributeList: [String:Any] = [:] - private var singleItemEventAttributeList: [String:Any] = [:] - + private var addEventAttributeList: [String: Any] = [:] + private var removeEventAttributeList: [String: Any] = [:] + private var singleItemEventAttributeList: [String: Any] = [:] + // Consent Filtering being handled seperately - private var consentRegulationFilters: [String:Any] = [:] - private var consentPurposeFilters: [String:Any] = [:] - + private var consentRegulationFilters: [String: Any] = [:] + private var consentPurposeFilters: [String: Any] = [:] + @objc public init(kitInstance: MPKitProtocol) { self.kitInstance = kitInstance } - + @objc public func addEventTypeFilter(eventType: MPEventType) { eventTypeFilters[MPIHasher.hashEventType(eventType)] = 0 } - + @objc public func addEventNameFilter(eventType: MPEventType, eventName: String) { eventNameFilters[MPIHasher.hashEventType(eventType, eventName: eventName, isLogScreen: false)] = 0 } - + @objc public func addScreenNameFilter(screenName: String) { eventNameFilters[MPIHasher.hashEventType(MPEventType.click, eventName: screenName, isLogScreen: true)] = 0 } - + @objc public func addEventAttributeFilter(eventType: MPEventType, eventName: String, customAttributeKey: String) { - eventAttributeFilters[MPIHasher.hashEventAttributeKey(eventType, eventName: eventName, customAttributeName: customAttributeKey, isLogScreen: false)] = 0 + eventAttributeFilters[MPIHasher.hashEventAttributeKey( + eventType, + eventName: eventName, + customAttributeName: customAttributeKey, + isLogScreen: false + )] = 0 } - + @objc public func addScreenAttributeFilter(screenName: String, customAttributeKey: String) { - eventAttributeFilters[MPIHasher.hashEventAttributeKey(MPEventType.click, eventName: screenName, customAttributeName: customAttributeKey, isLogScreen: true)] = 0 + eventAttributeFilters[MPIHasher.hashEventAttributeKey( + MPEventType.click, + eventName: screenName, + customAttributeName: customAttributeKey, + isLogScreen: true + )] = 0 } - + @objc public func addUserIdentityFilter(userIdentity: MPUserIdentity) { userIdentityFilters[MPIHasher.hashUserIdentity(userIdentity)] = 0 } - + @objc public func addUserAttributeFilter(userAttributeKey: String) { userAttributeFilters[MPIHasher.hashUserAttributeKey(userAttributeKey)] = 0 } - + @objc public func addCommerceEventAttributeFilter(eventType: MPEventType, eventAttributeKey: String) { commerceEventAttributeFilters[MPIHasher.hashCommerceEventAttribute(eventType, key: eventAttributeKey)] = 0 } - + @objc public func addCommerceEventEntityTypeFilter(commerceEventKind: MPCommerceEventKind) { commerceEventEntityTypeFilters[String(commerceEventKind.rawValue)] = 0 } - + @objc public func addCommerceEventAppFamilyAttributeFilter(attributeKey: String) { commerceEventAppFamilyAttributeFilters[MPIHasher.hashString(attributeKey.lowercased())] = 1 } - + // Special filter case that can only have 1 at a time unlike the others // If `forward` is true, ONLY matching events are forwarded, if false, any matching events are blocked // NOTE: This is iOS/Android only, web has a different signature // Attribute value filtering @objc public func setEventAttributeConditionalForwarding(attributeName: String, attributeValue: String, onlyForward: Bool) { - self.attributeValueFiltering["a"] = MPIHasher.hashUserAttributeKey(attributeName) - self.attributeValueFiltering["v"] = MPIHasher.hashUserAttributeValue(attributeValue) - self.attributeValueFiltering["i"] = onlyForward; + attributeValueFiltering["a"] = MPIHasher.hashUserAttributeKey(attributeName) + attributeValueFiltering["v"] = MPIHasher.hashUserAttributeValue(attributeValue) + attributeValueFiltering["i"] = onlyForward } - + // Please use the constants starting on line 393 of MPIConstants.h @objc public func addMessageTypeFilter(messageTypeConstant: String) { - self.messageTypeFilters[messageTypeConstant] = 0 + messageTypeFilters[messageTypeConstant] = 0 } - - @objc public func getKitFilters() -> [String:Any] { - var kitFilters: [String:Any] = [:] - kitFilters["et"] = self.eventTypeFilters - kitFilters["ec"] = self.eventNameFilters - kitFilters["ea"] = self.eventAttributeFilters - kitFilters["mt"] = self.messageTypeFilters - kitFilters["svec"] = self.screenNameFilters - kitFilters["svea"] = self.screenAttributeFilters - kitFilters["uid"] = self.userIdentityFilters - kitFilters["ua"] = self.userAttributeFilters - kitFilters["cea"] = self.commerceEventAttributeFilters - kitFilters["ent"] = self.commerceEventEntityTypeFilters - kitFilters["afa"] = self.commerceEventAppFamilyAttributeFilters - kitFilters["avf"] = self.attributeValueFiltering - - kitFilters["eaa"] = self.addEventAttributeList - kitFilters["ear"] = self.removeEventAttributeList - kitFilters["eas"] = self.singleItemEventAttributeList - - kitFilters["reg"] = self.consentRegulationFilters - kitFilters["pur"] = self.consentPurposeFilters - + + @objc public func getKitFilters() -> [String: Any] { + var kitFilters: [String: Any] = [:] + kitFilters["et"] = eventTypeFilters + kitFilters["ec"] = eventNameFilters + kitFilters["ea"] = eventAttributeFilters + kitFilters["mt"] = messageTypeFilters + kitFilters["svec"] = screenNameFilters + kitFilters["svea"] = screenAttributeFilters + kitFilters["uid"] = userIdentityFilters + kitFilters["ua"] = userAttributeFilters + kitFilters["cea"] = commerceEventAttributeFilters + kitFilters["ent"] = commerceEventEntityTypeFilters + kitFilters["afa"] = commerceEventAppFamilyAttributeFilters + kitFilters["avf"] = attributeValueFiltering + + kitFilters["eaa"] = addEventAttributeList + kitFilters["ear"] = removeEventAttributeList + kitFilters["eas"] = singleItemEventAttributeList + + kitFilters["reg"] = consentRegulationFilters + kitFilters["pur"] = consentPurposeFilters + return kitFilters } } diff --git a/mParticle-Apple-SDK/Location/MPLocationManager.swift b/mParticle-Apple-SDK/Location/MPLocationManager.swift index 8ca2095ea..e719b8d5e 100644 --- a/mParticle-Apple-SDK/Location/MPLocationManager.swift +++ b/mParticle-Apple-SDK/Location/MPLocationManager.swift @@ -9,33 +9,31 @@ import Foundation import UIKit #if os(iOS) && !MPARTICLE_LOCATION_DISABLE -import CoreLocation + import CoreLocation #endif -@objc final public class MPLocationManager_PRIVATE: NSObject { - +@objc public final class MPLocationManager_PRIVATE: NSObject { private static var _trackingLocation = false @objc public class var trackingLocation: Bool { return _trackingLocation } - + #if os(iOS) && !MPARTICLE_LOCATION_DISABLE - private static var _locationManager: CLLocationManager? - - @objc public var location: CLLocation? - @objc public private(set) var authorizationRequest: MPLocationAuthorizationRequest - @objc public private(set) var requestedAccuracy: CLLocationAccuracy - @objc public private(set) var requestedDistanceFilter: CLLocationDistance - @objc public var backgroundLocationTracking: Bool - - @objc public var locationManager: CLLocationManager? { - get { + private static var _locationManager: CLLocationManager? + + @objc public var location: CLLocation? + @objc public private(set) var authorizationRequest: MPLocationAuthorizationRequest + @objc public private(set) var requestedAccuracy: CLLocationAccuracy + @objc public private(set) var requestedDistanceFilter: CLLocationDistance + @objc public var backgroundLocationTracking: Bool + + @objc public var locationManager: CLLocationManager? { guard Self._locationManager == nil else { return Self._locationManager } - + let authorizationStatus = CLLocationManager.authorizationStatus() - guard authorizationStatus != .restricted && authorizationStatus != .denied else { + guard authorizationStatus != .restricted, authorizationStatus != .denied else { if let _ = Self._locationManager { Self._locationManager = nil location = nil @@ -43,68 +41,72 @@ import CoreLocation } return nil } - + let _locationManager = CLLocationManager() _locationManager.delegate = self Self._locationManager = _locationManager return Self._locationManager } - } - - @objc public init?(accuracy: CLLocationAccuracy, distanceFilter: CLLocationDistance, authorizationRequest: MPLocationAuthorizationRequest) { - let authorizationStatus = CLLocationManager.authorizationStatus() - guard authorizationStatus != .restricted && authorizationStatus != .denied else { - return nil - } - - self.authorizationRequest = authorizationRequest - requestedAccuracy = accuracy - requestedDistanceFilter = distanceFilter - backgroundLocationTracking = true - Self._trackingLocation = false - super.init() - - // Must be run on the main thread or no delegate methods will be called - DispatchQueue.main.async { - if let locationManager = self.locationManager { - locationManager.desiredAccuracy = accuracy - locationManager.distanceFilter = distanceFilter - - let keys = Bundle.main.infoDictionary?.keys - if let keys = keys, authorizationRequest == .always && keys.contains("NSLocationAlwaysUsageDescription") { - locationManager.requestAlwaysAuthorization() - } else if let keys = keys, authorizationRequest == .whenInUse && keys.contains("NSLocationWhenInUseUsageDescription") { - locationManager.requestWhenInUseAuthorization() - } else { - locationManager.startUpdatingLocation() + + @objc public init?( + accuracy: CLLocationAccuracy, + distanceFilter: CLLocationDistance, + authorizationRequest: MPLocationAuthorizationRequest + ) { + let authorizationStatus = CLLocationManager.authorizationStatus() + guard authorizationStatus != .restricted, authorizationStatus != .denied else { + return nil + } + + self.authorizationRequest = authorizationRequest + requestedAccuracy = accuracy + requestedDistanceFilter = distanceFilter + backgroundLocationTracking = true + Self._trackingLocation = false + super.init() + + // Must be run on the main thread or no delegate methods will be called + DispatchQueue.main.async { + if let locationManager = self.locationManager { + locationManager.desiredAccuracy = accuracy + locationManager.distanceFilter = distanceFilter + + let keys = Bundle.main.infoDictionary?.keys + if let keys = keys, authorizationRequest == .always, keys.contains("NSLocationAlwaysUsageDescription") { + locationManager.requestAlwaysAuthorization() + } else if let keys = keys, authorizationRequest == .whenInUse, + keys.contains("NSLocationWhenInUseUsageDescription") { + locationManager.requestWhenInUseAuthorization() + } else { + locationManager.startUpdatingLocation() + } } } } - } - @objc public func endLocationTracking() { - Self._locationManager?.stopUpdatingLocation() - Self._locationManager = nil - - location = nil - Self._trackingLocation = false - } - + @objc public func endLocationTracking() { + Self._locationManager?.stopUpdatingLocation() + Self._locationManager = nil + + location = nil + Self._trackingLocation = false + } + #endif } #if os(iOS) && !MPARTICLE_LOCATION_DISABLE -extension MPLocationManager_PRIVATE: CLLocationManagerDelegate { - public func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { - Self._trackingLocation = (status == .authorizedAlways || status == .authorizedWhenInUse) - - if Self._trackingLocation { - locationManager?.startUpdatingLocation() + extension MPLocationManager_PRIVATE: CLLocationManagerDelegate { + public func locationManager(_: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { + Self._trackingLocation = (status == .authorizedAlways || status == .authorizedWhenInUse) + + if Self._trackingLocation { + locationManager?.startUpdatingLocation() + } + } + + public func locationManager(_: CLLocationManager, didUpdateLocations locations: [CLLocation]) { + location = locations.last } } - - public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { - location = locations.last - } -} #endif diff --git a/mParticle-Apple-SDK/Logger/MPLogger.swift b/mParticle-Apple-SDK/Logger/MPLogger.swift index 6d2462516..c1265f7e0 100644 --- a/mParticle-Apple-SDK/Logger/MPLogger.swift +++ b/mParticle-Apple-SDK/Logger/MPLogger.swift @@ -9,9 +9,8 @@ import Foundation @objcMembers public class MPLog: NSObject { - private static func MPLogger(loggerLevel: MPILogLevel, format: String, arguments: any CVarArg...) { - if (MParticle.sharedInstance().logLevel.rawValue >= loggerLevel.rawValue && loggerLevel != .none) { + if MParticle.sharedInstance().logLevel.rawValue >= loggerLevel.rawValue && loggerLevel != .none { let msg = String.localizedStringWithFormat("mParticle -> \(format)", arguments) if let customLogger = MParticle.sharedInstance().customLogger { customLogger(msg) @@ -20,32 +19,32 @@ public class MPLog: NSObject { } } } - + public static func error(_ format: String, _ arguments: any CVarArg...) { MPLogger(loggerLevel: .error, format: format, arguments: arguments) } - + public static func warning(_ format: String, _ arguments: any CVarArg...) { MPLogger(loggerLevel: .warning, format: format, arguments: arguments) } - + public static func debug(_ format: String, _ arguments: any CVarArg...) { MPLogger(loggerLevel: .debug, format: format, arguments: arguments) } - + public static func verbose(_ format: String, _ arguments: any CVarArg...) { MPLogger(loggerLevel: .verbose, format: format, arguments: arguments) } - + public var logLevel: MPILogLevel public var customLogger: ((String) -> Void)? - + public init(logLevel: MPILogLevel) { self.logLevel = logLevel } - + private func log(loggerLevel: MPILogLevel, format: String, arguments: any CVarArg...) { - if (logLevel.rawValue >= loggerLevel.rawValue && loggerLevel != .none) { + if logLevel.rawValue >= loggerLevel.rawValue && loggerLevel != .none { let msg = String.localizedStringWithFormat("mParticle -> \(format)", arguments) if let customLogger = customLogger { customLogger(msg) @@ -54,23 +53,19 @@ public class MPLog: NSObject { } } } - - @objc + public func error(_ message: String) { log(loggerLevel: .error, format: message) } - - @objc + public func warning(_ message: String) { log(loggerLevel: .warning, format: message) } - - @objc + public func debug(_ message: String) { log(loggerLevel: .debug, format: message) } - - @objc + public func verbose(_ message: String) { log(loggerLevel: .verbose, format: message) } diff --git a/mParticle-Apple-SDK/MPConstants.swift b/mParticle-Apple-SDK/MPConstants.swift index 7c9b63df6..4d7c0d085 100644 --- a/mParticle-Apple-SDK/MPConstants.swift +++ b/mParticle-Apple-SDK/MPConstants.swift @@ -17,7 +17,7 @@ func MPMilliseconds(timestamp: Double) -> Double { let kMParticleSDKVersion = "8.39.0" -struct MessageKeys { +enum MessageKeys { static let kMPMessagesKey = "msgs" static let kMPMessageIdKey = "id" static let kMPMessageUserIdKey = "mpid" @@ -54,7 +54,7 @@ struct MessageKeys { static let kMPDataPlanVersionKey = "v" } -struct PushNotifications { +enum PushNotifications { static let kMPDeviceTokenKey = "to" static let kMPPushStatusKey = "r" static let kMPPushMessageTypeKey = "t" @@ -74,7 +74,7 @@ struct PushNotifications { static let kMPPushNotificationCategoryIdentifierKey = "acid" } -struct RemoteConfig { +enum RemoteConfig { static let kMPRemoteConfigExceptionHandlingModeKey = "cue" static let kMPRemoteConfigExceptionHandlingModeAppDefined = "appdefined" static let kMPRemoteConfigExceptionHandlingModeForce = "forcecatch" @@ -159,13 +159,13 @@ struct RemoteConfig { static let kMPRemoteConfigDataPlanningDataPlanVersionValuePromotionAction = "promotion_action" static let kMPRemoteConfigDataPlanningDataPlanVersionValueProductImpressions = "product_impressions" static let kMPRemoteConfigDataPlanningDataPlanVersionValueCriteria = "criteria" - static let kMPRemoteConfigDataPlanningDataPlanVersionValueAction = "action" + static let kMPRemoteConfigDataPlanningDataPlanVersionValueAction = "action" static let kMPRemoteConfigDataPlanningDataPlanVersionValueImpressionUnknown = "unknown" static let kMPRemoteConfigDataPlanningDataPlanVersionValueImpressionView = "view" static let kMPRemoteConfigDataPlanningDataPlanVersionValueImpressionClick = "click" } -struct ConsentFiltering { +enum ConsentFiltering { static let kMPConsentKitFilter = "crvf" static let kMPConsentKitFilterIncludeOnMatch = "i" static let kMPConsentKitFilterItems = "v" @@ -178,7 +178,7 @@ struct ConsentFiltering { static let kMPConsentCCPAPurposeName = "data_sale_opt_out" } -struct Notifications { +enum Notifications { static let kMPCrashReportOccurredNotification = Notification.Name("MPCrashReportOccurredNotification") static let kMPConfigureExceptionHandlingNotification = Notification.Name("MPConfigureExceptionHandlingNotification") static let kMPUserNotificationDictionaryKey = Notification.Name("MPUserNotificationDictionaryKey") @@ -188,7 +188,7 @@ struct Notifications { static let kMPRemoteNotificationOldDeviceTokenKey = Notification.Name("MPRemoteNotificationOldDeviceTokenKey") } -struct Device { +enum Device { static let kMPDeviceInformationKey = "di" static let kMPDeviceBrandKey = "b" static let kMPDeviceProductKey = "p" @@ -222,7 +222,7 @@ struct Device { static let kMPDeviceInvalidVendorId = "00000000-0000-0000-0000-000000000000" } -struct Miscellaneous { +enum Miscellaneous { static let kMPFirstSeenUser = "fsu" static let kMPLastSeenUser = "lsu" static let kMPAppInitialLaunchTimeKey = "ict" @@ -233,13 +233,12 @@ struct Miscellaneous { static let kMPLastIdentifiedDate = "last_date_used" static let MPSideloadedKitsCountUserDefaultsKey = "MPSideloadedKitsCountUserDefaultsKey" static let kMPLastUploadSettingsUserDefaultsKey = "lastUploadSettings" - static let CONFIG_REQUESTS_DEFAULT_EXPIRATION_AGE = 5.0*60 - static let CONFIG_REQUESTS_MAX_EXPIRATION_AGE = 60*60*24.0 + static let CONFIG_REQUESTS_DEFAULT_EXPIRATION_AGE = 5.0 * 60 + static let CONFIG_REQUESTS_MAX_EXPIRATION_AGE = 60 * 60 * 24.0 static let kMPDeviceTokenTypeKey = "tot" static let kMPATT = "atts" static let kMPATTTimestamp = "attt" static let kMPDeviceCydiaJailbrokenKey = "cydia" - } /// User Identities diff --git a/mParticle-Apple-SDK/MPRoktEvent.swift b/mParticle-Apple-SDK/MPRoktEvent.swift index d755341ab..f33d99d10 100644 --- a/mParticle-Apple-SDK/MPRoktEvent.swift +++ b/mParticle-Apple-SDK/MPRoktEvent.swift @@ -20,13 +20,13 @@ import Foundation } @objc public class MPRoktShowLoadingIndicator: MPRoktEvent { - @objc public override init() { + @objc override public init() { super.init() } } @objc public class MPRoktHideLoadingIndicator: MPRoktEvent { - @objc public override init() { + @objc override public init() { super.init() } } @@ -121,9 +121,10 @@ import Foundation @objc public let catalogItemId: String @objc public let currency: String private let _description: String - @objc public override var description: String { + @objc override public var description: String { _description } + @objc public let linkedProductId: String? @objc public let providerData: String @objc public let quantity: NSDecimalNumber? @@ -131,22 +132,22 @@ import Foundation @objc public let unitPrice: NSDecimalNumber? @objc public init(placementId: String, - name: String?, - cartItemId: String, - catalogItemId: String, - currency: String, - description: String, - linkedProductId: String?, - providerData: String, - quantity: NSDecimalNumber?, - totalPrice: NSDecimalNumber?, - unitPrice: NSDecimalNumber?) { + name: String?, + cartItemId: String, + catalogItemId: String, + currency: String, + description: String, + linkedProductId: String?, + providerData: String, + quantity: NSDecimalNumber?, + totalPrice: NSDecimalNumber?, + unitPrice: NSDecimalNumber?) { self.placementId = placementId self.name = name self.cartItemId = cartItemId self.catalogItemId = catalogItemId self.currency = currency - self._description = description + _description = description self.linkedProductId = linkedProductId self.providerData = providerData self.quantity = quantity @@ -156,4 +157,3 @@ import Foundation } } } - diff --git a/mParticle-Apple-SDK/Utils/MPConvertJS.swift b/mParticle-Apple-SDK/Utils/MPConvertJS.swift index 5a8d5e156..b74f1db36 100644 --- a/mParticle-Apple-SDK/Utils/MPConvertJS.swift +++ b/mParticle-Apple-SDK/Utils/MPConvertJS.swift @@ -21,8 +21,7 @@ import Foundation case removeFromWishlist = 10 } -@objc final public class MPConvertJS_PRIVATE: NSObject { - +@objc public final class MPConvertJS_PRIVATE: NSObject { @objc public static func commerceEventAction(_ json: NSNumber) -> MPCommerceEventAction { switch json.uintValue { case MPJSCommerceEventAction.addToCart.rawValue: @@ -50,24 +49,24 @@ import Foundation return .addToCart } } - - @objc public static func commerceEvent(_ json: [AnyHashable : Any]) -> MPCommerceEvent? { + + @objc public static func commerceEvent(_ json: [AnyHashable: Any]) -> MPCommerceEvent? { guard json["ProductAction"] == nil || json["ProductAction"] is [String: Any] else { MPLog.error("Unexpected commerce event data received from webview") return nil } - + let productAction = json["ProductAction"] as? [String: Any] let isProductAction = productAction?["ProductActionType"] != nil let isPromotion = json["PromotionAction"] != nil let isImpression = json["ProductImpressions"] != nil let isValid = isProductAction || isPromotion || isImpression - + if !isValid { MPLog.error("Invalid commerce event dictionary received from webview: %@", json) return nil } - + let commerceEvent: MPCommerceEvent if isProductAction { guard let productActionType = productAction?["ProductActionType"] as? NSNumber else { @@ -82,8 +81,8 @@ import Foundation } else { commerceEvent = MPCommerceEvent(impressionName: nil, product: nil) } - - if let eventAttributes = json["EventAttributes"] as? [String : Any] { + + if let eventAttributes = json["EventAttributes"] as? [String: Any] { commerceEvent.customAttributes = eventAttributes } if let checkoutOptions = json["CheckoutOptions"] as? String { @@ -104,7 +103,7 @@ import Foundation if let checkoutStep = json["CheckoutStep"] as? NSNumber { commerceEvent.checkoutStep = checkoutStep.intValue } - if let customFlags = json["CustomFlags"] as? [String : Any] { + if let customFlags = json["CustomFlags"] as? [String: Any] { for key in customFlags.keys { if let valueArray = customFlags[key] as? [String] { commerceEvent.addCustomFlags(valueArray, withKey: key) @@ -114,15 +113,15 @@ import Foundation } } - if let jsonProducts = productAction?["ProductList"] as? [[AnyHashable : Any]] { + if let jsonProducts = productAction?["ProductList"] as? [[AnyHashable: Any]] { let products = jsonProducts.map { Self.product($0) } commerceEvent.addProducts(products) } - if let jsonImpressions = json["ProductImpressions"] as? [[AnyHashable : Any]] { + if let jsonImpressions = json["ProductImpressions"] as? [[AnyHashable: Any]] { for jsonImpression in jsonImpressions { if let listName = jsonImpression["ProductImpressionList"] as? String, - let jsonProducts = jsonImpression["ProductList"] as? [[AnyHashable : Any]] { + let jsonProducts = jsonImpression["ProductList"] as? [[AnyHashable: Any]] { for jsonObject in jsonProducts { let product = MPConvertJS_PRIVATE.product(jsonObject) commerceEvent.addImpression(product, listName: listName) @@ -130,24 +129,24 @@ import Foundation } } } - + return commerceEvent } - - @objc public static func promotionContainer(_ json: [AnyHashable : Any]) -> MPPromotionContainer? { + + @objc public static func promotionContainer(_ json: [AnyHashable: Any]) -> MPPromotionContainer? { guard let promotionDictionary = (json["PromotionAction"] as? [String: Any]) else { MPLog.error("Unexpected promotion container action data received from webview") return nil } - + guard let promotionActionTypeNumber = (promotionDictionary["PromotionActionType"] as? NSNumber) else { MPLog.error("Unexpected promotion container action type data received from webview") return nil } - + let promotionAction = promotionActionTypeNumber.intValue == 1 ? MPPromotionAction.view : MPPromotionAction.click let promotionContainer = MPPromotionContainer(action: promotionAction, promotion: nil) - if let jsonPromotions = promotionDictionary["PromotionList"] as? [[AnyHashable : Any]] { + if let jsonPromotions = promotionDictionary["PromotionList"] as? [[AnyHashable: Any]] { for jsonObject in jsonPromotions { promotionContainer.addPromotion(MPConvertJS_PRIVATE.promotion(jsonObject)) } @@ -156,10 +155,10 @@ import Foundation return nil } - return promotionContainer; + return promotionContainer } - - @objc public static func promotion(_ json: [AnyHashable : Any]) -> MPPromotion { + + @objc public static func promotion(_ json: [AnyHashable: Any]) -> MPPromotion { let promotion = MPPromotion() if let creative = json["Creative"] as? String { @@ -174,13 +173,13 @@ import Foundation if let id = json["Id"] as? String { promotion.promotionId = id } - - return promotion; + + return promotion } - - @objc public static func transactionAttributes(_ json: [AnyHashable : Any] = [:]) -> MPTransactionAttributes! { + + @objc public static func transactionAttributes(_ json: [AnyHashable: Any] = [:]) -> MPTransactionAttributes! { let transactionAttributes = MPTransactionAttributes() - + if let affiliation = json["Affiliation"] as? String { transactionAttributes.affiliation = affiliation } @@ -199,13 +198,13 @@ import Foundation if let transactionId = json["TransactionId"] as? String { transactionAttributes.transactionId = transactionId } - - return transactionAttributes; + + return transactionAttributes } - - @objc public static func product(_ json: [AnyHashable : Any]) -> MPProduct { + + @objc public static func product(_ json: [AnyHashable: Any]) -> MPProduct { let product = MPProduct() - + if let brand = json["Brand"] as? String { product.brand = brand } @@ -235,27 +234,27 @@ import Foundation if let quantity = json["Quantity"] as? NSNumber { product.quantity = quantity } - if let jsonAttributes = json["Attributes"] as? [String : String] { + if let jsonAttributes = json["Attributes"] as? [String: String] { for (key, value) in jsonAttributes { product.setValue(value, forKey: key) } } - return product; + return product } - + @objc private static func identityFromNumber(_ identityTypeNumber: NSNumber) -> MPIdentity { return MPIdentity(rawValue: identityTypeNumber.uintValue) ?? .other } - - @objc public static func identityApiRequest(_ json: [AnyHashable : Any]?) -> MPIdentityApiRequest? { + + @objc public static func identityApiRequest(_ json: [AnyHashable: Any]?) -> MPIdentityApiRequest? { let request = MPIdentityApiRequest.withEmptyUser() - - guard let userIdentities = json?["UserIdentities"] as? [[AnyHashable : Any]] else { + + guard let userIdentities = json?["UserIdentities"] as? [[AnyHashable: Any]] else { MPLog.error("Unexpected user identity data received from webview") return nil } - + for identityDictionary in userIdentities { if let identity = identityDictionary["Identity"] as? String, let identityTypeNumber = identityDictionary["Type"] as? NSNumber, @@ -271,7 +270,7 @@ import Foundation let identityType = MPIdentity(rawValue: identityTypeNumber.uintValue) { request.setIdentity(identity, identityType: identityType) } - + return request } } diff --git a/mParticle-Apple-SDK/Utils/MPDateFormatter.swift b/mParticle-Apple-SDK/Utils/MPDateFormatter.swift index 00ca0f017..be8f5f0b1 100644 --- a/mParticle-Apple-SDK/Utils/MPDateFormatter.swift +++ b/mParticle-Apple-SDK/Utils/MPDateFormatter.swift @@ -7,7 +7,7 @@ import Foundation -@objc public class MPDateFormatter : NSObject { +@objc public class MPDateFormatter: NSObject { private static var dateFormatterRFC3339: DateFormatter = { let formatter = DateFormatter() formatter.locale = Locale(identifier: "en_US_POSIX") @@ -15,7 +15,7 @@ import Foundation formatter.timeZone = TimeZone(secondsFromGMT: 0) return formatter }() - + private static var dateFormatterRFC1123: DateFormatter = { let formatter = DateFormatter() formatter.locale = Locale(identifier: "en_US") @@ -23,7 +23,7 @@ import Foundation formatter.dateFormat = "EEE',' dd MMM yyyy HH':'mm':'ss z" return formatter }() - + private static var dateFormatterRFC850: DateFormatter = { let formatter = DateFormatter() formatter.locale = dateFormatterRFC1123.locale @@ -31,20 +31,20 @@ import Foundation formatter.dateFormat = "EEEE',' dd'-'MMM'-'yy HH':'mm':'ss z" return formatter }() - + @objc(dateFromString:) public static func date(from dateString: String) -> Date? { guard !dateString.isEmpty else { return nil } - + if let date = dateFormatterRFC3339.date(from: dateString) { return date } - + if let date = dateFormatterRFC1123.date(from: dateString) { return date } - + return dateFormatterRFC850.date(from: dateString) } @@ -52,7 +52,7 @@ import Foundation guard !dateString.isEmpty else { return nil } - + return dateFormatterRFC1123.date(from: dateString) } @@ -60,7 +60,7 @@ import Foundation guard !dateString.isEmpty else { return nil } - + return dateFormatterRFC3339.date(from: dateString) } @@ -72,4 +72,3 @@ import Foundation return dateFormatterRFC3339.string(from: date) } } - diff --git a/mParticle-Apple-SDK/Utils/MPDevice.swift b/mParticle-Apple-SDK/Utils/MPDevice.swift index ba61595af..13adf7586 100644 --- a/mParticle-Apple-SDK/Utils/MPDevice.swift +++ b/mParticle-Apple-SDK/Utils/MPDevice.swift @@ -6,35 +6,35 @@ // import Foundation -import QuartzCore import MachO +import QuartzCore #if os(iOS) && !MPARTICLE_LOCATION_DISABLE -import CoreTelephony + import CoreTelephony #endif @objc(MPDevice) -public class MPDevice : NSObject, NSCopying { +public class MPDevice: NSObject, NSCopying { private var stateMachine: MPStateMachine_PRIVATE private var userDefaults: MPUserDefaults private var identity: MPIdentityApi - - @objc required public init(stateMachine: MPStateMachine_PRIVATE, userDefaults: MPUserDefaults, identity: MPIdentityApi) { + + @objc public required init(stateMachine: MPStateMachine_PRIVATE, userDefaults: MPUserDefaults, identity: MPIdentityApi) { self.stateMachine = stateMachine self.userDefaults = userDefaults self.identity = identity super.init() } - - @objc public func copy(with zone: NSZone? = nil) -> Any { - let copyObject = MPDevice(stateMachine: self.stateMachine, userDefaults: self.userDefaults, identity: self.identity) - - copyObject.advertiserId = self.advertiserId - copyObject.architecture = self.architecture - copyObject.model = self.model - copyObject.vendorId = self.vendorId - copyObject.screenSize = self.screenSize - + + @objc public func copy(with _: NSZone? = nil) -> Any { + let copyObject = MPDevice(stateMachine: stateMachine, userDefaults: userDefaults, identity: identity) + + copyObject.advertiserId = advertiserId + copyObject.architecture = architecture + copyObject.model = model + copyObject.vendorId = vendorId + copyObject.screenSize = screenSize + return copyObject } @@ -66,29 +66,24 @@ public class MPDevice : NSObject, NSCopying { return arch } else { guard let archRaw = NXGetLocalArchInfo().pointee.name else { - return "unknown" - } + return "unknown" + } return String(cString: archRaw) } } } @objc public var brand: String { - get { - return UIDevice.current.model - } + return UIDevice.current.model } - -#if os(iOS) && !MPARTICLE_LOCATION_DISABLE - @objc public var carrier: String? { - get { + + #if os(iOS) && !MPARTICLE_LOCATION_DISABLE + @objc public var carrier: String? { // Deprecated and no longer provided by Apple https://developer.apple.com/documentation/coretelephony/cttelephonynetworkinfo/subscribercellularprovider return nil } - } - - @objc public var radioAccessTechnology: String { - get { + + @objc public var radioAccessTechnology: String { if let radioAccessTechnology = CTTelephonyNetworkInfo().currentRadioAccessTechnology { if let range = radioAccessTechnology.range(of: "CTRadioAccessTechnology") { if !range.isEmpty { @@ -98,45 +93,36 @@ public class MPDevice : NSObject, NSCopying { } return "None" } - } -#endif + #endif @objc public var country: String? { - get { - return Locale.current.regionCode - } + return Locale.current.regionCode } private var _deviceIdentifier: String? @objc public var deviceIdentifier: String { - get { - if _deviceIdentifier == nil { - if let deviceID = userDefaults[Device.kMPDeviceIdentifierKey] as? String { - _deviceIdentifier = deviceID - } else { - _deviceIdentifier = UUID().uuidString - userDefaults[Device.kMPDeviceIdentifierKey] = _deviceIdentifier - } + if _deviceIdentifier == nil { + if let deviceID = userDefaults[Device.kMPDeviceIdentifierKey] as? String { + _deviceIdentifier = deviceID + } else { + _deviceIdentifier = UUID().uuidString + userDefaults[Device.kMPDeviceIdentifierKey] = _deviceIdentifier } - return _deviceIdentifier ?? "" } + return _deviceIdentifier ?? "" } @objc public var language: String? { - get { - // Extra logic added to strip out the country code to stay consistent with earlier iOS releases - guard let subString = Locale.preferredLanguages[0].split(separator: "-").first else { - return nil - } - - return String(subString) + // Extra logic added to strip out the country code to stay consistent with earlier iOS releases + guard let subString = Locale.preferredLanguages[0].split(separator: "-").first else { + return nil } + + return String(subString) } @objc public var manufacturer: String { - get { - return "Apple" - } + return "Apple" } private var _model: String? @@ -148,11 +134,11 @@ public class MPDevice : NSObject, NSCopying { if _model == nil { var size = 0 sysctlbyname("hw.machine", nil, &size, nil, 0) - var model = [CChar](repeating: 0, count: size) + var model = [CChar](repeating: 0, count: size) sysctlbyname("hw.machine", &model, &size, nil, 0) _model = String(cString: model) } - + if let model = _model { return model } else { @@ -162,50 +148,37 @@ public class MPDevice : NSObject, NSCopying { } @objc open var name: String { - get { - return UIDevice.current.name - } + return UIDevice.current.name } @objc open var platform: String { - get { - switch UIDevice.current.userInterfaceIdiom { - case .phone, .pad: - return "iOS" - case .tv: - return "tvOS" - default: - return "unknown" - - } + switch UIDevice.current.userInterfaceIdiom { + case .phone, .pad: + return "iOS" + case .tv: + return "tvOS" + default: + return "unknown" } } @objc public var product: String? { - get { - return UIDevice.current.model - } + return UIDevice.current.model } @objc public var operatingSystem: String { - get { - return UIDevice.current.systemVersion - } + return UIDevice.current.systemVersion } @objc public var timezoneOffset: String { - get { - let seconds = TimeZone.current.secondsFromGMT() - let hours = seconds/3600 - - return String(format: "%+i", hours) - } + let seconds = TimeZone.current.secondsFromGMT() + let hours = seconds/3600 + + return String(format: "%+i", hours) } @objc public var timezoneDescription: String { - get { - return Calendar.current.timeZone.identifier - } + return Calendar.current.timeZone.identifier } private var _vendorId: String? @@ -215,7 +188,8 @@ public class MPDevice : NSObject, NSCopying { } get { if _vendorId == nil { - if let vendor = userDefaults[Device.kMPDeviceAppVendorIdKey] as? String, vendor != Device.kMPDeviceInvalidVendorId { + if let vendor = userDefaults[Device.kMPDeviceAppVendorIdKey] as? String, + vendor != Device.kMPDeviceInvalidVendorId { _vendorId = vendor } else { _vendorId = UIDevice.current.identifierForVendor?.uuidString @@ -227,13 +201,11 @@ public class MPDevice : NSObject, NSCopying { } @objc public var buildId: String? { - get { - var size = 0 - sysctlbyname("kern.osversion", nil, &size, nil, 0) - var build = [CChar](repeating: 0, count: size) - sysctlbyname("kern.osversion", &build, &size, nil, 0) - return String(cString: build) - } + var size = 0 + sysctlbyname("kern.osversion", nil, &size, nil, 0) + var build = [CChar](repeating: 0, count: size) + sysctlbyname("kern.osversion", &build, &size, nil, 0) + return String(cString: build) } private var _screenSize: CGSize? @@ -255,150 +227,152 @@ public class MPDevice : NSObject, NSCopying { } @objc public var isDaylightSavingTime: Bool { - get { - let isDaylightSavingTime = TimeZone.current.isDaylightSavingTime() - return isDaylightSavingTime - } + let isDaylightSavingTime = TimeZone.current.isDaylightSavingTime() + return isDaylightSavingTime } @objc public var isTablet: Bool { - get { - let isTablet = UI_USER_INTERFACE_IDIOM() == .pad - return isTablet - } + let isTablet = UI_USER_INTERFACE_IDIOM() == .pad + return isTablet } - @objc public class func jailbrokenInfo() -> [AnyHashable : Any] { + @objc public class func jailbrokenInfo() -> [AnyHashable: Any] { var jailbroken = false - -#if targetEnvironment(simulator) + + #if targetEnvironment(simulator) // Simulator -#else - let fileManager = FileManager.default - var signerIdentityKey: String? - let bundleInfoDictionary = Bundle.main.infoDictionary - var key: String? - - if var infoEnumerator = bundleInfoDictionary?.keys.makeIterator() { - while (key != nil) { - key = infoEnumerator.next() - if let signerId = key?.copy() as? String, (signerId.lowercased() == Device.kMPDeviceSignerIdentityString) { - signerIdentityKey = signerId - break - } - } - } - - jailbroken = signerIdentityKey != nil - - if (!jailbroken) { - let filePaths = ["/usr/sbin/sshd", - "/Library/MobileSubstrate/MobileSubstrate.dylib", - "/bin/bash", - "/usr/libexec/sftp-server", - "/Applications/Cydia.app", - "/Applications/blackra1n.app", - "/Applications/FakeCarrier.app", - "/Applications/Icy.app", - "/Applications/IntelliScreen.app", - "/Applications/MxTube.app", - "/Applications/RockApp.app", - "/Applications/SBSettings.app", - "/Applications/WinterBoard.app", - "/Library/MobileSubstrate/DynamicLibraries/LiveClock.plist", - "/Library/MobileSubstrate/DynamicLibraries/Veency.plist", - "/private/var/lib/apt", - "/private/var/lib/cydia", - "/private/var/mobile/Library/SBSettings/Themes", - "/private/var/stash", - "/private/var/tmp/cydia.log", - "/System/Library/LaunchDaemons/com.ikey.bbot.plist", - "/System/Library/LaunchDaemons/com.saurik.Cydia.Startup.plist"] - - for filePath in filePaths { - jailbroken = fileManager.fileExists(atPath: filePath) - - if jailbroken { - break + #else + let fileManager = FileManager.default + var signerIdentityKey: String? + let bundleInfoDictionary = Bundle.main.infoDictionary + var key: String? + + if var infoEnumerator = bundleInfoDictionary?.keys.makeIterator() { + while key != nil { + key = infoEnumerator.next() + if let signerId = key?.copy() as? String, signerId.lowercased() == Device.kMPDeviceSignerIdentityString { + signerIdentityKey = signerId + break + } } } - + + jailbroken = signerIdentityKey != nil + if !jailbroken { - // Valid test only if running as root on a jailbroken device - let jailbrokenTestData = "Jailbroken filesystem test.".data(using: .utf8) - let filePath = "/private/mpjailbrokentest.txt" - do { - try jailbrokenTestData?.write(to: URL(fileURLWithPath: filePath), options: []) - } catch { - MPLog.warning("Device is not jailbroken, failed to write test file: \(error)") + let filePaths = ["/usr/sbin/sshd", + "/Library/MobileSubstrate/MobileSubstrate.dylib", + "/bin/bash", + "/usr/libexec/sftp-server", + "/Applications/Cydia.app", + "/Applications/blackra1n.app", + "/Applications/FakeCarrier.app", + "/Applications/Icy.app", + "/Applications/IntelliScreen.app", + "/Applications/MxTube.app", + "/Applications/RockApp.app", + "/Applications/SBSettings.app", + "/Applications/WinterBoard.app", + "/Library/MobileSubstrate/DynamicLibraries/LiveClock.plist", + "/Library/MobileSubstrate/DynamicLibraries/Veency.plist", + "/private/var/lib/apt", + "/private/var/lib/cydia", + "/private/var/mobile/Library/SBSettings/Themes", + "/private/var/stash", + "/private/var/tmp/cydia.log", + "/System/Library/LaunchDaemons/com.ikey.bbot.plist", + "/System/Library/LaunchDaemons/com.saurik.Cydia.Startup.plist"] + + for filePath in filePaths { + jailbroken = fileManager.fileExists(atPath: filePath) + + if jailbroken { + break + } } - jailbroken = fileManager.fileExists(atPath: filePath) - if jailbroken { + if !jailbroken { + // Valid test only if running as root on a jailbroken device + let jailbrokenTestData = Data("Jailbroken filesystem test.".utf8) + let filePath = "/private/mpjailbrokentest.txt" do { - try FileManager.default.removeItem(atPath: filePath) + try jailbrokenTestData.write(to: URL(fileURLWithPath: filePath), options: []) } catch { - MPLog.error("Device is jailbroken and test file still exists, failed to remove test file: \(error)") + MPLog.warning("Device is not jailbroken, failed to write test file: \(error)") + } + jailbroken = fileManager.fileExists(atPath: filePath) + + if jailbroken { + do { + try FileManager.default.removeItem(atPath: filePath) + } catch { + MPLog.error("Device is jailbroken and test file still exists, failed to remove test file: \(error)") + } } } } - } -#endif - return [Miscellaneous.kMPDeviceCydiaJailbrokenKey:NSNumber(value: jailbroken)] + #endif + return [Miscellaneous.kMPDeviceCydiaJailbrokenKey: NSNumber(value: jailbroken)] } - - @objc public func dictionaryRepresentation() -> [AnyHashable : Any] { - var deviceDictionary: [AnyHashable : Any] = [Device.kMPDeviceBrandKey:self.model, - Device.kMPDeviceNameKey:self.name, - Device.kMPDeviceProductKey:self.model, - Device.kMPDeviceOSKey:self.operatingSystem, - Device.kMPDeviceModelKey:self.model, - Device.kMPDeviceArchitectureKey:self.architecture, - Device.kMPScreenWidthKey:String(format: Device.kMPDeviceFloatingPointFormat, self.screenSize.width), - Device.kMPScreenHeightKey:String(format: Device.kMPDeviceFloatingPointFormat, self.screenSize.height), - Device.kMPDevicePlatformKey:self.platform, - Device.kMPDeviceManufacturerKey:self.manufacturer, - Device.kMPTimezoneOffsetKey:self.timezoneOffset, - Device.kMPTimezoneDescriptionKey:self.timezoneDescription, - Device.kMPDeviceJailbrokenKey:MPDevice.jailbrokenInfo(), - Device.kMPDeviceIsTabletKey:NSNumber(value: self.isTablet), - Device.kMPDeviceIsDaylightSavingTime:NSNumber(value: self.isDaylightSavingTime), - Device.kMPDeviceLimitAdTrackingKey:NSNumber(value: false)] - - if let language = self.language { + + @objc public func dictionaryRepresentation() -> [AnyHashable: Any] { + var deviceDictionary: [AnyHashable: Any] = [Device.kMPDeviceBrandKey: model, + Device.kMPDeviceNameKey: name, + Device.kMPDeviceProductKey: model, + Device.kMPDeviceOSKey: operatingSystem, + Device.kMPDeviceModelKey: model, + Device.kMPDeviceArchitectureKey: architecture, + Device.kMPScreenWidthKey: String( + format: Device.kMPDeviceFloatingPointFormat, + screenSize.width + ), + Device.kMPScreenHeightKey: String( + format: Device.kMPDeviceFloatingPointFormat, + screenSize.height + ), + Device.kMPDevicePlatformKey: platform, + Device.kMPDeviceManufacturerKey: manufacturer, + Device.kMPTimezoneOffsetKey: timezoneOffset, + Device.kMPTimezoneDescriptionKey: timezoneDescription, + Device.kMPDeviceJailbrokenKey: MPDevice.jailbrokenInfo(), + Device.kMPDeviceIsTabletKey: NSNumber(value: isTablet), + Device.kMPDeviceIsDaylightSavingTime: NSNumber(value: isDaylightSavingTime), + Device.kMPDeviceLimitAdTrackingKey: NSNumber(value: false)] + + if let language = language { deviceDictionary[Device.kMPDeviceLocaleLanguageKey] = language } - - if let country = self.country { + + if let country = country { deviceDictionary[Device.kMPDeviceLocaleCountryKey] = country } - - if let advertiserId = self.advertiserId { + + if let advertiserId = advertiserId { deviceDictionary[Device.kMPDeviceAdvertiserIdKey] = advertiserId } - - if let vendorId = self.vendorId { + + if let vendorId = vendorId { deviceDictionary[Device.kMPDeviceAppVendorIdKey] = vendorId } - - if let buildId = self.buildId { + + if let buildId = buildId { deviceDictionary[Device.kMPDeviceBuildIdKey] = buildId } - -#if os(iOS) && !MPARTICLE_LOCATION_DISABLE - deviceDictionary[Device.kMPDeviceRadioKey] = self.radioAccessTechnology - - if let pushNotificationToken = MPNotificationController_PRIVATE.deviceToken() { - if let tokenString = MPUserDefaults.stringFromDeviceToken(pushNotificationToken) { - deviceDictionary[PushNotifications.kMPDeviceTokenKey] = tokenString + + #if os(iOS) && !MPARTICLE_LOCATION_DISABLE + deviceDictionary[Device.kMPDeviceRadioKey] = radioAccessTechnology + + if let pushNotificationToken = MPNotificationController_PRIVATE.deviceToken() { + if let tokenString = MPUserDefaults.stringFromDeviceToken(pushNotificationToken) { + deviceDictionary[PushNotifications.kMPDeviceTokenKey] = tokenString + } } - } -#endif - + #endif + if let noDeviceToken = stateMachine.deviceTokenType?.isEmpty, !noDeviceToken { deviceDictionary[Miscellaneous.kMPDeviceTokenTypeKey] = stateMachine.deviceTokenType } - + if let authStatus = stateMachine.attAuthorizationStatus { switch authStatus.intValue { case MPATTAuthorizationStatusSwift.notDetermined.rawValue: @@ -413,31 +387,31 @@ public class MPDevice : NSObject, NSCopying { break } } - + if let authTimestamp = stateMachine.attAuthorizationTimestamp { deviceDictionary[Miscellaneous.kMPATTTimestamp] = authTimestamp } - + return deviceDictionary } - @objc public func dictionaryRepresentation(withMpid mpid: NSNumber?) -> [AnyHashable : Any] { - var deviceDictionary: [AnyHashable : Any] = self.dictionaryRepresentation() - + @objc public func dictionaryRepresentation(withMpid mpid: NSNumber?) -> [AnyHashable: Any] { + var deviceDictionary: [AnyHashable: Any] = dictionaryRepresentation() + if let mpid = mpid { - if let userIdentities = self.identity.getUser(mpid)?.identities { + if let userIdentities = identity.getUser(mpid)?.identities { if let advertiserId = userIdentities[MPIdentity.iosAdvertiserId.rawValue as NSNumber], let currentStatus = stateMachine.attAuthorizationStatus, currentStatus.intValue == MPATTAuthorizationStatusSwift.authorized.rawValue { deviceDictionary[Device.kMPDeviceAdvertiserIdKey] = advertiserId } - + if let vendorId = userIdentities[MPIdentity.iosVendorId.rawValue as NSNumber] { deviceDictionary[Device.kMPDeviceAppVendorIdKey] = vendorId } } } - + return deviceDictionary } } diff --git a/mParticle-Apple-SDK/Utils/MPIHasher.swift b/mParticle-Apple-SDK/Utils/MPIHasher.swift index 6e887931c..0a152fea7 100644 --- a/mParticle-Apple-SDK/Utils/MPIHasher.swift +++ b/mParticle-Apple-SDK/Utils/MPIHasher.swift @@ -7,33 +7,32 @@ import Foundation -@objc public class MPIHasher : NSObject { - +@objc public class MPIHasher: NSObject { @objc public class func hashFNV1a(_ data: Data) -> Int64 { - var rampHash: UInt64 = 0xcbf29ce484222325 - + var rampHash: UInt64 = 0xCBF2_9CE4_8422_2325 + for byte in data { - rampHash = (rampHash ^ UInt64(byte)) &* 0x100000001B3 + rampHash = (rampHash ^ UInt64(byte)) &* 0x100_0000_01B3 } return Int64(bitPattern: rampHash) } @objc public class func hashString(_ stringToHash: String) -> String { if stringToHash.isEmpty { - return ""; + return "" } - + let lowercaseStringToHash = stringToHash.lowercased() guard let dataToHash = lowercaseStringToHash.data(using: .utf8) else { MPLog.warning("Hash String Failed. Could not encode string as data") return "" } - + var hash: Int32 = 0 for byte in dataToHash { - hash = ((hash << 5) &- hash) &+ Int32(byte); + hash = ((hash << 5) &- hash) &+ Int32(byte) } - + return String(hash) } @@ -69,7 +68,12 @@ import Foundation return hashString(stringToBeHashed) } - @objc public class func hashEventAttributeKey(_ eventType: MPEventType, eventName: String, customAttributeName: String, isLogScreen: Bool) -> String { + @objc public class func hashEventAttributeKey( + _ eventType: MPEventType, + eventName: String, + customAttributeName: String, + isLogScreen: Bool + ) -> String { let stringToBeHashed: String if isLogScreen { stringToBeHashed = "0\(eventName)\(customAttributeName)" diff --git a/mParticle-Apple-SDK/Utils/MPLaunchInfo.swift b/mParticle-Apple-SDK/Utils/MPLaunchInfo.swift index 58489136a..81f5679c8 100644 --- a/mParticle-Apple-SDK/Utils/MPLaunchInfo.swift +++ b/mParticle-Apple-SDK/Utils/MPLaunchInfo.swift @@ -6,18 +6,19 @@ // import Foundation -@objc public class MPLaunchInfo : NSObject { + +@objc public class MPLaunchInfo: NSObject { private let annotationKey = UIApplication.OpenURLOptionsKey.annotation private let sourceAppKey = UIApplication.OpenURLOptionsKey.sourceApplication private var sourceApp: String? - + @objc public private(set) var sourceApplication: String? @objc public private(set) var annotation: String? @objc public private(set) var url: URL - - @objc required public init(URL: URL, sourceApplication: String?, annotation: Any?) { + + @objc public required init(URL: URL, sourceApplication: String?, annotation: Any?) { sourceApp = sourceApplication - self.url = URL + url = URL if let sourceApp = sourceApp { let urlString = url.absoluteString let appLinksRange = urlString.range(of: "al_applink_data") @@ -26,29 +27,29 @@ import Foundation self.sourceApplication = nil } self.annotation = MPLaunchInfo.stringifyAnnotation(annotation) - + super.init() } - - @objc public init(URL: URL, options: [String : Any]?) { - self.url = URL + + @objc public init(URL: URL, options: [String: Any]?) { + url = URL if let options = options { - if let sourceApp = options[self.sourceAppKey.rawValue] as? String { + if let sourceApp = options[sourceAppKey.rawValue] as? String { self.sourceApp = sourceApp } - if let sourceApp = self.sourceApp { + if let sourceApp = sourceApp { let urlString = url.absoluteString let appLinksRange = urlString.range(of: "al_applink_data") - self.sourceApplication = appLinksRange?.lowerBound == nil ? sourceApp : String(format: "AppLink(%@)", sourceApp) + sourceApplication = appLinksRange?.lowerBound == nil ? sourceApp : String(format: "AppLink(%@)", sourceApp) } else { - self.sourceApplication = nil + sourceApplication = nil } - - if let annotation = options[self.annotationKey.rawValue] as? String { + + if let annotation = options[annotationKey.rawValue] as? String { self.annotation = annotation } } - + super.init() } @@ -103,20 +104,18 @@ import Foundation return nil } } - - @objc public var options: [String : Any] { - get { - var options: [String : Any] = [:] - - if let sourceApplication = self.sourceApplication { - options[self.sourceAppKey.rawValue] = sourceApplication - } - - if let annotation = self.annotation { - options[self.annotationKey.rawValue] = annotation - } - - return options + + @objc public var options: [String: Any] { + var options: [String: Any] = [:] + + if let sourceApplication = sourceApplication { + options[sourceAppKey.rawValue] = sourceApplication } + + if let annotation = annotation { + options[annotationKey.rawValue] = annotation + } + + return options } } diff --git a/mParticle-Apple-SDK/Utils/MPResponseConfig.swift b/mParticle-Apple-SDK/Utils/MPResponseConfig.swift index ee3b4aa88..ffd7d20dd 100644 --- a/mParticle-Apple-SDK/Utils/MPResponseConfig.swift +++ b/mParticle-Apple-SDK/Utils/MPResponseConfig.swift @@ -7,143 +7,169 @@ import Foundation -@objc public class MPResponseConfig : NSObject { - @objc public private(set) var configuration: [AnyHashable : Any]? +@objc public class MPResponseConfig: NSObject { + @objc public private(set) var configuration: [AnyHashable: Any]? private var stateMachine: MPStateMachine_PRIVATE private var backendController: MPBackendController_PRIVATE - - @objc public convenience init?(configuration: [AnyHashable : Any], stateMachine: MPStateMachine_PRIVATE, backendController: MPBackendController_PRIVATE) { - self.init(configuration: configuration, dataReceivedFromServer: true, stateMachine: stateMachine, backendController: backendController) + + @objc public convenience init?( + configuration: [AnyHashable: Any], + stateMachine: MPStateMachine_PRIVATE, + backendController: MPBackendController_PRIVATE + ) { + self.init( + configuration: configuration, + dataReceivedFromServer: true, + stateMachine: stateMachine, + backendController: backendController + ) } - - @objc public init?(configuration: [AnyHashable : Any], dataReceivedFromServer: Bool, stateMachine: MPStateMachine_PRIVATE, backendController: MPBackendController_PRIVATE) { + + @objc public init?( + configuration: [AnyHashable: Any], + dataReceivedFromServer: Bool, + stateMachine: MPStateMachine_PRIVATE, + backendController: MPBackendController_PRIVATE + ) { self.configuration = configuration self.stateMachine = stateMachine self.backendController = backendController super.init() - - if self.configuration == nil || self.configuration?.count == 0 { + + if self.configuration == nil || self.configuration?.isEmpty == true { return nil } - self.setUp(dataReceivedFromServer: dataReceivedFromServer) + setUp(dataReceivedFromServer: dataReceivedFromServer) } - + @objc private func setUp(dataReceivedFromServer: Bool) { - if let config = self.configuration { + if let config = configuration { if dataReceivedFromServer { var hasConsentFilters = false - - if let configKitDictionary = config[RemoteConfig.kMPRemoteConfigKitsKey] as? [[String : Any]] { + + if let configKitDictionary = config[RemoteConfig.kMPRemoteConfigKitsKey] as? [[String: Any]] { for kitDictionary in configKitDictionary { - let consentKitFilter = kitDictionary[ConsentFiltering.kMPConsentKitFilter] as? [String : Any] - hasConsentFilters = consentKitFilter != nil && consentKitFilter!.count > 0 + let consentKitFilter = kitDictionary[ConsentFiltering.kMPConsentKitFilter] as? [String: Any] + hasConsentFilters = consentKitFilter != nil && !consentKitFilter!.isEmpty var hasRegulationOrPurposeFilters = false - - if let hashes = kitDictionary[RemoteConfig.kMPRemoteConfigKitHashesKey] as? [String : Any], hashes.count > 0 { - if let regulationFilters = hashes[ConsentFiltering.kMPConsentRegulationFilters] as? [String : Any], regulationFilters.count > 0 { + + if let hashes = kitDictionary[RemoteConfig.kMPRemoteConfigKitHashesKey] as? [String: Any], + !hashes.isEmpty { + if let regulationFilters = hashes[ConsentFiltering.kMPConsentRegulationFilters] as? [String: Any], + !regulationFilters.isEmpty { hasRegulationOrPurposeFilters = true } - if let purposeFilters = hashes[ConsentFiltering.kMPConsentPurposeFilters] as? [String : Any], purposeFilters.count > 0 { + if let purposeFilters = hashes[ConsentFiltering.kMPConsentPurposeFilters] as? [String: Any], + !purposeFilters.isEmpty { hasRegulationOrPurposeFilters = true } } - + if hasConsentFilters || hasRegulationOrPurposeFilters { hasConsentFilters = true } } } - + var hasInitialIdentity = false if let mpid = MParticle.sharedInstance().identity.currentUser?.userId, mpid != 0 { hasInitialIdentity = true } - + let shouldDefer = hasConsentFilters && !hasInitialIdentity if !shouldDefer { DispatchQueue.main.async { - MParticle.sharedInstance().kitContainer_PRIVATE.configureKits(config[RemoteConfig.kMPRemoteConfigKitsKey] as? [[AnyHashable : Any]]) + MParticle.sharedInstance().kitContainer_PRIVATE + .configureKits(config[RemoteConfig.kMPRemoteConfigKitsKey] as? [[AnyHashable: Any]]) } } else { - MParticle.sharedInstance().deferredKitConfiguration_PRIVATE = config[RemoteConfig.kMPRemoteConfigKitsKey] as? [[AnyHashable : Any]] + MParticle.sharedInstance() + .deferredKitConfiguration_PRIVATE = config[RemoteConfig.kMPRemoteConfigKitsKey] as? [[AnyHashable: Any]] } } - - stateMachine.configureCustomModules(config[RemoteConfig.kMPRemoteConfigCustomModuleSettingsKey] as? [[AnyHashable : Any]]) + + stateMachine + .configureCustomModules(config[RemoteConfig.kMPRemoteConfigCustomModuleSettingsKey] as? [[AnyHashable: Any]]) stateMachine.configureRampPercentage(config[RemoteConfig.kMPRemoteConfigRampKey] as? NSNumber) - stateMachine.configureTriggers(config[RemoteConfig.kMPRemoteConfigTriggerKey] as? [AnyHashable : Any]) + stateMachine.configureTriggers(config[RemoteConfig.kMPRemoteConfigTriggerKey] as? [AnyHashable: Any]) stateMachine.configureAliasMaxWindow(config[RemoteConfig.kMPRemoteConfigAliasMaxWindow] as? NSNumber) - stateMachine.configureDataBlocking(config[RemoteConfig.kMPRemoteConfigDataPlanningResults] as? [AnyHashable : Any]) - + stateMachine.configureDataBlocking(config[RemoteConfig.kMPRemoteConfigDataPlanningResults] as? [AnyHashable: Any]) + stateMachine.allowASR = config[RemoteConfig.kMPRemoteConfigAllowASR] as? Bool ?? false stateMachine.enableDirectRouting = config[RemoteConfig.kMPRemoteConfigDirectURLRouting] as? Bool ?? false - if let remoteConfigFlags = config[RemoteConfig.kMPRemoteConfigFlagsKey] as? [AnyHashable : Any] { + if let remoteConfigFlags = config[RemoteConfig.kMPRemoteConfigFlagsKey] as? [AnyHashable: Any] { if let audienceAPIFlag = remoteConfigFlags[RemoteConfig.kMPRemoteConfigAudienceAPIKey] as? String { stateMachine.enableAudienceAPI = audienceAPIFlag == "True" } } - + // Exception handling if let auxString = config[RemoteConfig.kMPRemoteConfigExceptionHandlingModeKey] as? String { stateMachine.exceptionHandlingMode = auxString NotificationCenter.default.post(Notification(name: Notifications.kMPConfigureExceptionHandlingNotification)) } - + // Crash size limiting if let crashMaxReportLength = config[RemoteConfig.kMPRemoteConfigCrashMaxPLReportLength] as? NSNumber { stateMachine.crashMaxPLReportLength = crashMaxReportLength } - + // Session timeout if let sessionTimeout = config[RemoteConfig.kMPRemoteConfigSessionTimeoutKey] as? NSNumber { - self.backendController.sessionTimeout = sessionTimeout.doubleValue - } - -#if os(iOS) - // Push notifications - if let pushNotificationDictionary = config["pn"] as? [AnyHashable : Any] { - self.configurePushNotifications(pushNotificationDictionary) - } - - // Location tracking - if let locationTrackingDictionary = config["lct"] as? [AnyHashable : Any] { - self.configureLocationTracking(locationTrackingDictionary) + backendController.sessionTimeout = sessionTimeout.doubleValue } -#endif + + #if os(iOS) + // Push notifications + if let pushNotificationDictionary = config["pn"] as? [AnyHashable: Any] { + configurePushNotifications(pushNotificationDictionary) + } + + // Location tracking + if let locationTrackingDictionary = config["lct"] as? [AnyHashable: Any] { + configureLocationTracking(locationTrackingDictionary) + } + #endif } } - -#if os(iOS) - @objc public func configureLocationTracking(_ locationDictionary: [AnyHashable : Any]) { - if let locationMode = locationDictionary[RemoteConfig.kMPRemoteConfigLocationModeKey] as? String { - stateMachine.locationTrackingMode = locationMode - -#if !MPARTICLE_LOCATION_DISABLE - if locationMode == RemoteConfig.kMPRemoteConfigForceTrue { - if let accuracy = locationDictionary[RemoteConfig.kMPRemoteConfigLocationAccuracyKey] as? NSNumber, let minimumDistance = locationDictionary[RemoteConfig.kMPRemoteConfigLocationMinimumDistanceKey] as? NSNumber { - MParticle.sharedInstance().beginLocationTracking(accuracy.doubleValue, minDistance: minimumDistance.doubleValue, authorizationRequest: MPLocationAuthorizationRequest.always) - } - } else if locationMode == RemoteConfig.kMPRemoteConfigForceFalse { - MParticle.sharedInstance().endLocationTracking() + + #if os(iOS) + @objc public func configureLocationTracking(_ locationDictionary: [AnyHashable: Any]) { + if let locationMode = locationDictionary[RemoteConfig.kMPRemoteConfigLocationModeKey] as? String { + stateMachine.locationTrackingMode = locationMode + + #if !MPARTICLE_LOCATION_DISABLE + if locationMode == RemoteConfig.kMPRemoteConfigForceTrue { + if let accuracy = locationDictionary[RemoteConfig.kMPRemoteConfigLocationAccuracyKey] as? NSNumber, + let minimumDistance = + locationDictionary[RemoteConfig.kMPRemoteConfigLocationMinimumDistanceKey] as? NSNumber { + MParticle.sharedInstance().beginLocationTracking( + accuracy.doubleValue, + minDistance: minimumDistance.doubleValue, + authorizationRequest: MPLocationAuthorizationRequest.always + ) + } + } else if locationMode == RemoteConfig.kMPRemoteConfigForceFalse { + MParticle.sharedInstance().endLocationTracking() + } + #endif } -#endif } - } - - @objc public func configurePushNotifications(_ pushNotificationDictionary: [AnyHashable : Any]) { - if let pushNotificationMode = pushNotificationDictionary[RemoteConfig.kMPRemoteConfigPushNotificationModeKey] as? String { - stateMachine.pushNotificationMode = pushNotificationMode - if !MPStateMachine_PRIVATE.isAppExtension() { - let app = MPApplication_PRIVATE.sharedUIApplication() - - if pushNotificationMode == RemoteConfig.kMPRemoteConfigForceTrue { - app?.registerForRemoteNotifications() - } else if pushNotificationMode == RemoteConfig.kMPRemoteConfigForceFalse { - app?.unregisterForRemoteNotifications() + + @objc public func configurePushNotifications(_ pushNotificationDictionary: [AnyHashable: Any]) { + if let pushNotificationMode = + pushNotificationDictionary[RemoteConfig.kMPRemoteConfigPushNotificationModeKey] as? String { + stateMachine.pushNotificationMode = pushNotificationMode + if !MPStateMachine_PRIVATE.isAppExtension() { + let app = MPApplication_PRIVATE.sharedUIApplication() + + if pushNotificationMode == RemoteConfig.kMPRemoteConfigForceTrue { + app?.registerForRemoteNotifications() + } else if pushNotificationMode == RemoteConfig.kMPRemoteConfigForceFalse { + app?.unregisterForRemoteNotifications() + } } } } - } -#endif + #endif } - diff --git a/mParticle-Apple-SDK/Utils/MPUploadSettings.swift b/mParticle-Apple-SDK/Utils/MPUploadSettings.swift index 13f95a673..3e0355544 100644 --- a/mParticle-Apple-SDK/Utils/MPUploadSettings.swift +++ b/mParticle-Apple-SDK/Utils/MPUploadSettings.swift @@ -25,27 +25,27 @@ public class MPUploadSettings: NSObject, NSCopying, NSSecureCoding { @objc public var aliasTrackingHost: String? @objc public var overridesAliasSubdirectory: Bool = false @objc public var eventsOnly: Bool = false - - @objc public override init() { - self.apiKey = "" - self.secret = "" + + @objc override public init() { + apiKey = "" + secret = "" super.init() } - - public func copy(with zone: NSZone? = nil) -> Any { - return MPUploadSettings(apiKey: self.apiKey, - secret: self.secret, - eventsHost: self.eventsHost, - eventsTrackingHost: self.eventsTrackingHost, - overridesEventsSubdirectory: self.overridesEventsSubdirectory, - aliasHost: self.aliasHost, - aliasTrackingHost: self.aliasTrackingHost, - overridesAliasSubdirectory: self.overridesAliasSubdirectory, - eventsOnly: self.eventsOnly) + + public func copy(with _: NSZone? = nil) -> Any { + return MPUploadSettings(apiKey: apiKey, + secret: secret, + eventsHost: eventsHost, + eventsTrackingHost: eventsTrackingHost, + overridesEventsSubdirectory: overridesEventsSubdirectory, + aliasHost: aliasHost, + aliasTrackingHost: aliasTrackingHost, + overridesAliasSubdirectory: overridesAliasSubdirectory, + eventsOnly: eventsOnly) } - + public static var supportsSecureCoding: Bool = true - + public func encode(with coder: NSCoder) { coder.encode(apiKey, forKey: kApiKey) coder.encode(secret, forKey: kSecret) @@ -57,25 +57,27 @@ public class MPUploadSettings: NSObject, NSCopying, NSSecureCoding { coder.encode(overridesAliasSubdirectory, forKey: kOverridesAliasSubdirectory) coder.encode(eventsOnly, forKey: kEventsOnly) } - + @objc public required init?(coder: NSCoder) { - self.apiKey = coder.decodeObject(forKey: kApiKey) as? String ?? "" - self.secret = coder.decodeObject(forKey: kSecret) as? String ?? "" - self.eventsHost = coder.decodeObject(forKey: kEventsHost) as? String - self.eventsTrackingHost = coder.decodeObject(forKey: kEventsTrackingHost) as? String - self.overridesEventsSubdirectory = coder.decodeBool(forKey: kOverridesEventsSubdirectory) - self.aliasHost = coder.decodeObject(forKey: kAliasHost) as? String - self.aliasTrackingHost = coder.decodeObject(forKey: kAliasTrackingHost) as? String - self.overridesAliasSubdirectory = coder.decodeBool(forKey: kOverridesAliasSubdirectory) - self.eventsOnly = coder.decodeBool(forKey: kEventsOnly) - + apiKey = coder.decodeObject(forKey: kApiKey) as? String ?? "" + secret = coder.decodeObject(forKey: kSecret) as? String ?? "" + eventsHost = coder.decodeObject(forKey: kEventsHost) as? String + eventsTrackingHost = coder.decodeObject(forKey: kEventsTrackingHost) as? String + overridesEventsSubdirectory = coder.decodeBool(forKey: kOverridesEventsSubdirectory) + aliasHost = coder.decodeObject(forKey: kAliasHost) as? String + aliasTrackingHost = coder.decodeObject(forKey: kAliasTrackingHost) as? String + overridesAliasSubdirectory = coder.decodeBool(forKey: kOverridesAliasSubdirectory) + eventsOnly = coder.decodeBool(forKey: kEventsOnly) } - - @objc public class func currentUploadSettings(stateMachine: MPStateMachineProtocol, networkOptions: MPNetworkOptions) -> MPUploadSettings { + + @objc public class func currentUploadSettings(stateMachine: MPStateMachineProtocol, + networkOptions: MPNetworkOptions) -> MPUploadSettings { return MPUploadSettings(apiKey: stateMachine.apiKey, secret: stateMachine.secret, networkOptions: networkOptions) } - - @objc public init(apiKey: String, secret: String, eventsHost: String? = nil, eventsTrackingHost: String? = nil, overridesEventsSubdirectory: Bool = false, aliasHost: String? = nil, aliasTrackingHost: String? = nil, overridesAliasSubdirectory: Bool = false, eventsOnly: Bool = false) { + + @objc public init(apiKey: String, secret: String, eventsHost: String? = nil, eventsTrackingHost: String? = nil, + overridesEventsSubdirectory: Bool = false, aliasHost: String? = nil, aliasTrackingHost: String? = nil, + overridesAliasSubdirectory: Bool = false, eventsOnly: Bool = false) { self.apiKey = apiKey self.secret = secret self.eventsHost = eventsHost @@ -85,21 +87,21 @@ public class MPUploadSettings: NSObject, NSCopying, NSSecureCoding { self.aliasTrackingHost = aliasTrackingHost self.overridesAliasSubdirectory = overridesAliasSubdirectory self.eventsOnly = eventsOnly - + super.init() } @objc public init(apiKey: String, secret: String, networkOptions: MPNetworkOptions) { self.apiKey = apiKey self.secret = secret - self.eventsHost = networkOptions.eventsHost - self.eventsTrackingHost = networkOptions.eventsTrackingHost - self.overridesEventsSubdirectory = networkOptions.overridesEventsSubdirectory - self.aliasHost = networkOptions.aliasHost - self.aliasTrackingHost = networkOptions.aliasTrackingHost - self.overridesAliasSubdirectory = networkOptions.overridesAliasSubdirectory - self.eventsOnly = networkOptions.eventsOnly - + eventsHost = networkOptions.eventsHost + eventsTrackingHost = networkOptions.eventsTrackingHost + overridesEventsSubdirectory = networkOptions.overridesEventsSubdirectory + aliasHost = networkOptions.aliasHost + aliasTrackingHost = networkOptions.aliasTrackingHost + overridesAliasSubdirectory = networkOptions.overridesAliasSubdirectory + eventsOnly = networkOptions.eventsOnly + super.init() } } diff --git a/mParticle-Apple-SDK/Utils/MPUserAttributeChange.swift b/mParticle-Apple-SDK/Utils/MPUserAttributeChange.swift index 601b1e5cb..49c5c71af 100644 --- a/mParticle-Apple-SDK/Utils/MPUserAttributeChange.swift +++ b/mParticle-Apple-SDK/Utils/MPUserAttributeChange.swift @@ -7,40 +7,39 @@ import Foundation -@objc public class MPUserAttributeChange : NSObject { - +@objc public class MPUserAttributeChange: NSObject { @objc public var key: String @objc public var timestamp: Date? - @objc public var userAttributes: [String : Any]? + @objc public var userAttributes: [String: Any]? @objc public var value: Any? @objc public var valueToLog: Any? @objc public private(set) var changed: Bool @objc public var deleted: Bool @objc public var isArray: Bool - - @objc public init?(userAttributes: [String : Any]? = nil, key: String, value: Any?) { + + @objc public init?(userAttributes: [String: Any]? = nil, key: String, value: Any?) { guard value == nil || value is [Any] || value is NSNull || value is String || value is NSNumber else { return nil } - + if userAttributes == nil && value == nil { return nil } - + self.key = key self.value = value - self.deleted = false - self.valueToLog = value + deleted = false + valueToLog = value self.userAttributes = userAttributes - + let existingValue = userAttributes?[key] - self.isArray = (value is [Any] || existingValue is [Any]) - self.changed = !equals(existingValue, value) + isArray = (value is [Any] || existingValue is [Any]) + changed = !equals(existingValue, value) super.init() } } -fileprivate func equals(_ x : Any?, _ y : Any?) -> Bool { +private func equals(_ x: Any?, _ y: Any?) -> Bool { guard let x = x as? AnyHashable, let y = y as? AnyHashable else { return false } diff --git a/mParticle-Apple-SDK/Utils/MPUserDefaults.swift b/mParticle-Apple-SDK/Utils/MPUserDefaults.swift index 1ea5685a4..fa24171cf 100644 --- a/mParticle-Apple-SDK/Utils/MPUserDefaults.swift +++ b/mParticle-Apple-SDK/Utils/MPUserDefaults.swift @@ -6,22 +6,22 @@ // import Foundation + private var userDefaults: MPUserDefaults? private var sharedGroupID: String? private let NSUserDefaultsPrefix = "mParticle::" -private let userSpecificKeys = ["lud", /* kMPAppLastUseDateKey */ - "lc", /* kMPAppLaunchCountKey */ - "lcu", /* kMPAppLaunchCountSinceUpgradeKey */ - "ua", /* kMPUserAttributeKey */ - "ui", /* kMPUserIdentityArrayKey */ - "ck", /* kMPRemoteConfigCookiesKey */ - "ltv", /* kMPLifeTimeValueKey */ - "is_ephemeral", /* kMPIsEphemeralKey */ - "last_date_used", /* kMPLastIdentifiedDate */ +private let userSpecificKeys = ["lud", /* kMPAppLastUseDateKey */ + "lc", /* kMPAppLaunchCountKey */ + "lcu", /* kMPAppLaunchCountSinceUpgradeKey */ + "ua", /* kMPUserAttributeKey */ + "ui", /* kMPUserIdentityArrayKey */ + "ck", /* kMPRemoteConfigCookiesKey */ + "ltv", /* kMPLifeTimeValueKey */ + "is_ephemeral", /* kMPIsEphemeralKey */ + "last_date_used", /* kMPLastIdentifiedDate */ "consent_state", /* kMPConsentStateKey */ - "fsu", /* kMPFirstSeenUser */ - "lsu" /* kMPLastSeenUser */ - ] + "fsu", /* kMPFirstSeenUser */ + "lsu" /* kMPLastSeenUser */ ] private let kMPUserIdentitySharedGroupIdentifier = "sgi" private let kMResponseConfigurationKey = "responseConfiguration" private let kMResponseConfigurationMigrationKey = "responseConfigurationMigrated" @@ -32,30 +32,38 @@ public protocol MPUserDefaultsProtocol { func synchronize() } -@objc public class MPUserDefaults : NSObject, MPUserDefaultsProtocol { +@objc public class MPUserDefaults: NSObject, MPUserDefaultsProtocol { private var stateMachine: MPStateMachine_PRIVATE? private var backendController: MPBackendController_PRIVATE? private var identity: MPIdentityApi? - - required public init(stateMachine: MPStateMachineProtocol, backendController: MPBackendControllerProtocol, identity: MPIdentityApi) { + + public required init( + stateMachine: MPStateMachineProtocol, + backendController: MPBackendControllerProtocol, + identity: MPIdentityApi + ) { self.stateMachine = stateMachine as? MPStateMachine_PRIVATE self.backendController = backendController as? MPBackendController_PRIVATE self.identity = identity super.init() } - @objc public class func standardUserDefaults(stateMachine: MPStateMachineProtocol, backendController: MPBackendControllerProtocol, identity: MPIdentityApi) -> MPUserDefaults { + @objc public class func standardUserDefaults( + stateMachine: MPStateMachineProtocol, + backendController: MPBackendControllerProtocol, + identity: MPIdentityApi + ) -> MPUserDefaults { if userDefaults == nil { userDefaults = self.init(stateMachine: stateMachine, backendController: backendController, identity: identity) } - + return userDefaults! } @objc public func mpObject(forKey key: String, userId: NSNumber) -> Any? { let prefixedKey = MPUserDefaults.prefixedKey(key, userId: userId) - - var mpObject = self.customUserDefaults().object(forKey: prefixedKey) + + var mpObject = customUserDefaults().object(forKey: prefixedKey) if mpObject == nil { mpObject = UserDefaults.standard.object(forKey: prefixedKey) } @@ -64,7 +72,7 @@ public protocol MPUserDefaultsProtocol { @objc public func setMPObject(_ value: Any?, forKey key: String, userId: NSNumber) { let prefixedKey = MPUserDefaults.prefixedKey(key, userId: userId) - + UserDefaults.standard.set(value, forKey: prefixedKey) if sharedGroupID != nil { UserDefaults(suiteName: sharedGroupID)?.set(value, forKey: prefixedKey) @@ -73,7 +81,7 @@ public protocol MPUserDefaultsProtocol { @objc public func removeMPObject(forKey key: String, userId: NSNumber) { let prefixedKey = MPUserDefaults.prefixedKey(key, userId: userId) - + UserDefaults.standard.removeObject(forKey: prefixedKey) if sharedGroupID != nil { UserDefaults(suiteName: sharedGroupID)?.removeObject(forKey: prefixedKey) @@ -81,25 +89,25 @@ public protocol MPUserDefaultsProtocol { } @objc public func removeMPObject(forKey key: String) { - self.removeMPObject(forKey: key, userId: MPPersistenceController_PRIVATE.mpId()) + removeMPObject(forKey: key, userId: MPPersistenceController_PRIVATE.mpId()) } @objc public subscript(key: String) -> Any? { get { if key == "mpid" { - return self.mpObject(forKey: key, userId: 0) + return mpObject(forKey: key, userId: 0) } - return self.mpObject(forKey: key, userId: MPPersistenceController_PRIVATE.mpId()) + return mpObject(forKey: key, userId: MPPersistenceController_PRIVATE.mpId()) } set { if let obj = newValue { if key == "mpid" { - self.setMPObject(obj, forKey: key, userId: 0) + setMPObject(obj, forKey: key, userId: 0) } else { - self.setMPObject(obj, forKey: key, userId: MPPersistenceController_PRIVATE.mpId()) + setMPObject(obj, forKey: key, userId: MPPersistenceController_PRIVATE.mpId()) } } else { - self.removeMPObject(forKey: key, userId: MPPersistenceController_PRIVATE.mpId()) + removeMPObject(forKey: key, userId: MPPersistenceController_PRIVATE.mpId()) } } } @@ -112,50 +120,55 @@ public protocol MPUserDefaultsProtocol { } @objc public func migrateUserKeys(withUserId userId: NSNumber) { - userSpecificKeys.forEach { key in + for key in userSpecificKeys { let globalKey = MPUserDefaults.globalKeyForKey(key) let userKey = MPUserDefaults.userKeyForKey(key, userId: userId) - guard let value = UserDefaults.standard.object(forKey: globalKey) else { return } - self.customUserDefaults().set(value, forKey: userKey) + guard let value = UserDefaults.standard.object(forKey: globalKey) else { continue } + customUserDefaults().set(value, forKey: userKey) } - - self.synchronize() + + synchronize() } @objc public func migrateFirstLastSeenUsers() { - let globalFirstSeenDateMs = self.mpObject(forKey: Miscellaneous.kMPAppInitialLaunchTimeKey, userId: MPPersistenceController_PRIVATE.mpId()) + let globalFirstSeenDateMs = mpObject( + forKey: Miscellaneous.kMPAppInitialLaunchTimeKey, + userId: MPPersistenceController_PRIVATE.mpId() + ) let globalLastSeenDateMs = NSNumber(value: Date().timeIntervalSince1970 * 1000) - let users: [MParticleUser] = self.identity?.getAllUsers() ?? [] + let users: [MParticleUser] = identity?.getAllUsers() ?? [] for user in users { - self.setMPObject(globalFirstSeenDateMs, forKey: Miscellaneous.kMPFirstSeenUser, userId: user.userId) - self.setMPObject(globalLastSeenDateMs, forKey: Miscellaneous.kMPLastSeenUser, userId: user.userId) + setMPObject(globalFirstSeenDateMs, forKey: Miscellaneous.kMPFirstSeenUser, userId: user.userId) + setMPObject(globalLastSeenDateMs, forKey: Miscellaneous.kMPLastSeenUser, userId: user.userId) } } @objc public func setSharedGroupIdentifier(_ groupIdentifier: String?) { - let storedGroupID = self.mpObject(forKey: kMPUserIdentitySharedGroupIdentifier, userId: MPPersistenceController_PRIVATE.mpId()) as? String - + let storedGroupID = mpObject( + forKey: kMPUserIdentitySharedGroupIdentifier, + userId: MPPersistenceController_PRIVATE.mpId() + ) as? String + if storedGroupID == groupIdentifier { - } else if let groupIdentifier = groupIdentifier, !groupIdentifier.isEmpty { - self.migrateToSharedGroupIdentifier(groupIdentifier: groupIdentifier) + migrateToSharedGroupIdentifier(groupIdentifier: groupIdentifier) } else { - self.migrateFromSharedGroupIdentifier() + migrateFromSharedGroupIdentifier() } } @objc public func migrateToSharedGroupIdentifier(groupIdentifier: String) { let standardUserDefaults = UserDefaults.standard let groupUserDefaults = UserDefaults(suiteName: groupIdentifier) - + let prefixedKey = - MPUserDefaults.prefixedKey(kMPUserIdentitySharedGroupIdentifier, userId: MPPersistenceController_PRIVATE.mpId()) + MPUserDefaults.prefixedKey(kMPUserIdentitySharedGroupIdentifier, userId: MPPersistenceController_PRIVATE.mpId()) standardUserDefaults.set(groupIdentifier, forKey: prefixedKey) groupUserDefaults?.set(groupIdentifier, forKey: prefixedKey) - + let predicate = NSPredicate(format: "SELF CONTAINS %@", NSUserDefaultsPrefix) let mParticleKeys = UserDefaults.standard.dictionaryRepresentation().keys.filter { predicate.evaluate(with: $0) } - + for key in mParticleKeys { groupUserDefaults?.set(standardUserDefaults.object(forKey: key), forKey: key) } @@ -164,114 +177,120 @@ public protocol MPUserDefaultsProtocol { @objc public func migrateFromSharedGroupIdentifier() { let standardUserDefaults = UserDefaults.standard let groupUserDefaults = UserDefaults(suiteName: sharedGroupID) - + let predicate = NSPredicate(format: "SELF CONTAINS %@", NSUserDefaultsPrefix) let mParticleKeys = UserDefaults.standard.dictionaryRepresentation().keys.filter { predicate.evaluate(with: $0) } - + for key in mParticleKeys { groupUserDefaults?.removeObject(forKey: key) } - + let prefixedKey = - MPUserDefaults.prefixedKey(kMPUserIdentitySharedGroupIdentifier, userId: MPPersistenceController_PRIVATE.mpId()) + MPUserDefaults.prefixedKey(kMPUserIdentitySharedGroupIdentifier, userId: MPPersistenceController_PRIVATE.mpId()) standardUserDefaults.removeObject(forKey: prefixedKey) groupUserDefaults?.removeObject(forKey: prefixedKey) } - @objc public func getConfiguration() -> [AnyHashable : Any]? { - guard let userID = self.identity?.currentUser?.userId else {return nil} - + @objc public func getConfiguration() -> [AnyHashable: Any]? { + guard let userID = identity?.currentUser?.userId else { return nil } + if UserDefaults.standard.object(forKey: kMResponseConfigurationMigrationKey) == nil { migrateConfiguration() } - - let configurationData = self.mpObject(forKey: kMResponseConfigurationKey, userId: userID) as? Data + + let configurationData = mpObject(forKey: kMResponseConfigurationKey, userId: userID) as? Data guard let configurationData = configurationData else { return nil } - - let configuration = NSKeyedUnarchiver.unarchiveObject(with: configurationData) as? [AnyHashable : Any] - + + let configuration = NSKeyedUnarchiver.unarchiveObject(with: configurationData) as? [AnyHashable: Any] + return configuration } @objc public func getKitConfigurations() -> [Any]? { - return self.getConfiguration()?[RemoteConfig.kMPRemoteConfigKitsKey] as? [Any] + return getConfiguration()?[RemoteConfig.kMPRemoteConfigKitsKey] as? [Any] } - @objc public func setConfiguration(_ responseConfiguration: [AnyHashable : Any], eTag: String, requestTimestamp: TimeInterval, currentAge: TimeInterval, maxAge: NSNumber?) { + @objc public func setConfiguration( + _ responseConfiguration: [AnyHashable: Any], + eTag: String, + requestTimestamp: TimeInterval, + currentAge: TimeInterval, + maxAge: NSNumber? + ) { let configurationData = NSKeyedArchiver.archivedData(withRootObject: responseConfiguration) - let userID = self.identity?.currentUser?.userId ?? 0 - - self.setMPObject(eTag, forKey: Miscellaneous.kMPHTTPETagHeaderKey, userId: userID) - self.setMPObject(configurationData, forKey: kMResponseConfigurationKey, userId: userID) - self.setMPObject(requestTimestamp - currentAge, forKey: Miscellaneous.kMPConfigProvisionedTimestampKey, userId: userID) - self.setMPObject(maxAge, forKey: Miscellaneous.kMPConfigMaxAgeHeaderKey, userId: userID) + let userID = identity?.currentUser?.userId ?? 0 + + setMPObject(eTag, forKey: Miscellaneous.kMPHTTPETagHeaderKey, userId: userID) + setMPObject(configurationData, forKey: kMResponseConfigurationKey, userId: userID) + setMPObject(requestTimestamp - currentAge, forKey: Miscellaneous.kMPConfigProvisionedTimestampKey, userId: userID) + setMPObject(maxAge, forKey: Miscellaneous.kMPConfigMaxAgeHeaderKey, userId: userID) } @objc public func migrateConfiguration() { - guard let userID = self.identity?.currentUser?.userId else {return} - let eTag = self.mpObject(forKey: Miscellaneous.kMPHTTPETagHeaderKey, userId: userID) as? String - + guard let userID = identity?.currentUser?.userId else { return } + let eTag = mpObject(forKey: Miscellaneous.kMPHTTPETagHeaderKey, userId: userID) as? String + let fileManager = FileManager.default guard let cachesURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first else { return } let stateMachineURL = cachesURL.appendingPathComponent("StateMachine") let configurationURL = stateMachineURL.appendingPathComponent("RequestConfig.cfg") - let configuration = self.mpObject(forKey: kMResponseConfigurationKey, userId: userID) - + let configuration = mpObject(forKey: kMResponseConfigurationKey, userId: userID) + if fileManager.fileExists(atPath: configurationURL.path) { do { try fileManager.removeItem(at: configurationURL) } catch { MPLog.error("Failed to remove old configuration file: \(error)") } - self.deleteConfiguration() - MPLog.debug( "Configuration Migration Complete") + deleteConfiguration() + MPLog.debug("Configuration Migration Complete") } else if (eTag != nil && configuration == nil) || (eTag == nil && configuration != nil) { - self.deleteConfiguration() - MPLog.debug( "Configuration Migration Complete") + deleteConfiguration() + MPLog.debug("Configuration Migration Complete") } - + UserDefaults.standard.set(1, forKey: kMResponseConfigurationMigrationKey) } @objc public func deleteConfiguration() { - self.removeMPObject(forKey: kMResponseConfigurationKey) - self.removeMPObject(forKey: Miscellaneous.kMPHTTPETagHeaderKey) - self.removeMPObject(forKey: Miscellaneous.kMPConfigProvisionedTimestampKey) - self.removeMPObject(forKey: Miscellaneous.kMPConfigMaxAgeHeaderKey) - self.removeMPObject(forKey: Miscellaneous.kMPConfigParameters) + removeMPObject(forKey: kMResponseConfigurationKey) + removeMPObject(forKey: Miscellaneous.kMPHTTPETagHeaderKey) + removeMPObject(forKey: Miscellaneous.kMPConfigProvisionedTimestampKey) + removeMPObject(forKey: Miscellaneous.kMPConfigMaxAgeHeaderKey) + removeMPObject(forKey: Miscellaneous.kMPConfigParameters) - MPLog.debug( "Configuration Deleted") + MPLog.debug("Configuration Deleted") } @objc public func resetDefaults() { let dict = UserDefaults.standard.dictionaryRepresentation() let predicate = NSPredicate(format: "SELF CONTAINS %@", NSUserDefaultsPrefix) let mParticleKeys = dict.keys.filter { predicate.evaluate(with: $0) } - + if sharedGroupID != nil { - self.setSharedGroupIdentifier(nil) + setSharedGroupIdentifier(nil) } - + for key in mParticleKeys { UserDefaults.standard.removeObject(forKey: key) } userDefaults = nil - + UserDefaults.standard.synchronize() } @objc public func isExistingUserId(_ userId: NSNumber) -> Bool { - let dateLastIdentified = self.mpObject(forKey: Miscellaneous.kMPLastIdentifiedDate, userId: userId) - + let dateLastIdentified = mpObject(forKey: Miscellaneous.kMPLastIdentifiedDate, userId: userId) + return dateLastIdentified != nil } @objc public func userIDsInUserDefaults() -> [NSNumber] { - let keyArray = self.customUserDefaults().dictionaryRepresentation().keys - + let keyArray = customUserDefaults().dictionaryRepresentation().keys + var uniqueUserIDs: [NSNumber] = [] for key in keyArray { - if let _ = self.customUserDefaults().object(forKey: key) { + if let _ = customUserDefaults().object(forKey: key) { let keyComponents = key.components(separatedBy: "::") if keyComponents.count == 3 { let UserID = NSNumber(value: Int64(keyComponents[1]) ?? 0) @@ -279,16 +298,19 @@ public protocol MPUserDefaultsProtocol { } } } - + return uniqueUserIDs } @objc public func isConfigurationExpired() -> Bool { - var isConfigurationExpired: Bool = true - - let configProvisioned = self.mpObject(forKey: Miscellaneous.kMPConfigProvisionedTimestampKey, userId: MPPersistenceController_PRIVATE.mpId()) as? NSNumber - let maxAge = self.mpObject(forKey: Miscellaneous.kMPConfigMaxAgeHeaderKey, userId: MPPersistenceController_PRIVATE.mpId()) - + var isConfigurationExpired = true + + let configProvisioned = mpObject( + forKey: Miscellaneous.kMPConfigProvisionedTimestampKey, + userId: MPPersistenceController_PRIVATE.mpId() + ) as? NSNumber + let maxAge = mpObject(forKey: Miscellaneous.kMPConfigMaxAgeHeaderKey, userId: MPPersistenceController_PRIVATE.mpId()) + if let configProvisioned = configProvisioned { let intervalConfigProvisioned = configProvisioned.doubleValue let intervalNow = Date().timeIntervalSince1970 @@ -299,7 +321,7 @@ public protocol MPUserDefaultsProtocol { } isConfigurationExpired = delta > expirationAge } - + return isConfigurationExpired } @@ -322,26 +344,27 @@ public protocol MPUserDefaultsProtocol { @objc public func lastUploadSettings() -> MPUploadSettings? { let data = mpObject(forKey: Miscellaneous.kMPLastUploadSettingsUserDefaultsKey, userId: 0) as? Data - + if let data = data { return NSKeyedUnarchiver.unarchiveObject(with: data) as? MPUploadSettings } else { return nil } } - + @objc public class func isOlderThanConfigMaxAgeSeconds() -> Bool { - var shouldConfigurationBeDeleted: Bool = false - - if let userDefaults = userDefaults { + var shouldConfigurationBeDeleted = false + + if let userDefaults = userDefaults { let configProvisioned = userDefaults[Miscellaneous.kMPConfigProvisionedTimestampKey] as? NSNumber let maxAgeSeconds = MParticle.sharedInstance().configMaxAgeSeconds - + if let configProvisioned = configProvisioned, let maxAgeSeconds = maxAgeSeconds, maxAgeSeconds.doubleValue > 0 { let intervalConfigProvisioned: TimeInterval = configProvisioned.doubleValue - shouldConfigurationBeDeleted = (Date().timeIntervalSince1970 - intervalConfigProvisioned) > maxAgeSeconds.doubleValue + shouldConfigurationBeDeleted = (Date().timeIntervalSince1970 - intervalConfigProvisioned) > maxAgeSeconds + .doubleValue } - + if shouldConfigurationBeDeleted { userDefaults.deleteConfiguration() } @@ -350,20 +373,25 @@ public protocol MPUserDefaultsProtocol { } @objc public class func stringFromDeviceToken(_ deviceToken: Data) -> String? { - if deviceToken.count == 0 { return nil } - + if deviceToken.isEmpty { return nil } + return deviceToken.map { String(format: "%02x", $0) }.joined() } @objc public class func restore() -> MPResponseConfig? { if let userDefaults = userDefaults { - if let configuration = userDefaults.getConfiguration(), let stateMachine = userDefaults.stateMachine, let backendController = userDefaults.backendController { - let responseConfig = MPResponseConfig(configuration: configuration, stateMachine: stateMachine, backendController: backendController) - + if let configuration = userDefaults.getConfiguration(), let stateMachine = userDefaults.stateMachine, + let backendController = userDefaults.backendController { + let responseConfig = MPResponseConfig( + configuration: configuration, + stateMachine: stateMachine, + backendController: backendController + ) + return responseConfig } } - + return nil } @@ -372,8 +400,7 @@ public protocol MPUserDefaultsProtocol { userDefaults.deleteConfiguration() } } - - + // Private Methods private class func globalKeyForKey(_ keyName: String) -> String { return "\(NSUserDefaultsPrefix)\(keyName)" @@ -382,7 +409,7 @@ public protocol MPUserDefaultsProtocol { private class func userKeyForKey(_ keyName: String, userId: NSNumber) -> String { return "\(NSUserDefaultsPrefix)\(userId)::\(keyName)" } - + private class func prefixedKey(_ keyName: String, userId: NSNumber) -> String { var prefixedKey: String? if userSpecificKeys.contains(keyName) { @@ -392,7 +419,7 @@ public protocol MPUserDefaultsProtocol { } return prefixedKey ?? "" } - + private func customUserDefaults() -> UserDefaults { if let sharedGroupID = sharedGroupID { return UserDefaults(suiteName: sharedGroupID) ?? .standard diff --git a/mParticle-Apple-SDK/Utils/MPZip.swift b/mParticle-Apple-SDK/Utils/MPZip.swift index a1c0868ab..c1d9460f7 100644 --- a/mParticle-Apple-SDK/Utils/MPZip.swift +++ b/mParticle-Apple-SDK/Utils/MPZip.swift @@ -1,32 +1,41 @@ import Foundation import zlib -@objc final public class MPZip_PRIVATE: NSObject { +@objc public final class MPZip_PRIVATE: NSObject { @objc(compressedDataFromData:) public static func compressedData(from data: Data?) -> Data? { guard let data = data, !data.isEmpty else { return nil } - + var failed = false let chunkSize = 16384 var output = Data(capacity: chunkSize) - + let dataCount = data.count data.withUnsafeBytes { inputPointer in guard let inputBaseAddress = inputPointer.bindMemory(to: Bytef.self).baseAddress else { failed = true return } - + var stream = z_stream() stream.next_in = UnsafeMutablePointer(mutating: inputBaseAddress) stream.avail_in = uInt(truncatingIfNeeded: dataCount) - - guard deflateInit2_(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (15+16), 8, Z_DEFAULT_STRATEGY, ZLIB_VERSION, Int32(MemoryLayout.stride)) == Z_OK else { + + guard deflateInit2_( + &stream, + Z_DEFAULT_COMPRESSION, + Z_DEFLATED, + 15 + 16, + 8, + Z_DEFAULT_STRATEGY, + ZLIB_VERSION, + Int32(MemoryLayout.stride) + ) == Z_OK else { failed = true return } - + repeat { let totalOut = Int(truncatingIfNeeded: stream.total_out) if totalOut >= output.count { @@ -39,18 +48,18 @@ import zlib failed = true return } - + stream.next_out = outputBaseAddress.advanced(by: totalOut) stream.avail_out = uInt(truncatingIfNeeded: outputCount - totalOut) - + failed = (deflate(&stream, Z_FINISH) != Z_OK) } } while stream.avail_out == 0 && !failed - + failed = (deflateEnd(&stream) != Z_OK) output.count = Int(truncatingIfNeeded: stream.total_out) } - + return failed ? nil : output } } diff --git a/mParticle-Apple-SDK/Utils/MParticleWebView.swift b/mParticle-Apple-SDK/Utils/MParticleWebView.swift index 7c6e0fe59..fba810642 100644 --- a/mParticle-Apple-SDK/Utils/MParticleWebView.swift +++ b/mParticle-Apple-SDK/Utils/MParticleWebView.swift @@ -7,105 +7,104 @@ // NOTE: @objc specifier added to private properties to support existing Obj-C unit tests -@objc public class MParticleWebView_PRIVATE : NSObject { - +@objc public class MParticleWebView_PRIVATE: NSObject { @objc public var userAgent: String? { resolvedUserAgent ?? defaultUserAgent } @objc public var originalDefaultUserAgent: String? { "mParticle Apple SDK/\(kMParticleSDKVersion)" } - + private var messageQueue: DispatchQueue private var customUserAgent: String? = nil private var shouldCollect = false private var defaultUserAgent: String? = nil - + @objc private var initializedDate: Date? = nil @objc private var resolvedUserAgent: String? = nil // final result @objc private var isCollecting: Bool = false @objc private var retryCount: Int = 0 - -#if os(iOS) - @objc private var webView: WKWebView? = nil -#endif - + + #if os(iOS) + @objc private var webView: WKWebView? + #endif + @objc public init(messageQueue: DispatchQueue) { self.messageQueue = messageQueue super.init() } - + @objc public func start(customUserAgent: String?, shouldCollect: Bool, defaultUserAgentOverride: String?) { - self.initializedDate = Date() + initializedDate = Date() self.customUserAgent = customUserAgent -#if os(iOS) - self.shouldCollect = shouldCollect -#endif - self.defaultUserAgent = defaultUserAgentOverride ?? originalDefaultUserAgent - self.retryCount = 0 + #if os(iOS) + self.shouldCollect = shouldCollect + #endif + defaultUserAgent = defaultUserAgentOverride ?? originalDefaultUserAgent + retryCount = 0 startCollectionIfNecessary() } - + private func startCollectionIfNecessary() { if let customUserAgent = customUserAgent { - resolvedUserAgent = customUserAgent; + resolvedUserAgent = customUserAgent } else if !shouldCollect { - resolvedUserAgent = defaultUserAgent; + resolvedUserAgent = defaultUserAgent } - + if let _ = resolvedUserAgent { return } - -#if os(iOS) - evaluateAgent() -#endif + + #if os(iOS) + evaluateAgent() + #endif } - -#if os(iOS) - private func evaluateAgent() { - messageQueue.async { - self.isCollecting = true - DispatchQueue.main.async { - if self.webView == nil { - self.webView = WKWebView(frame: .zero) - } - MPLog.verbose("Getting user agent") - self.webView?.evaluateJavaScript("navigator.userAgent") { result, error in - if result == nil, let error = error as? NSError { - MPLog.verbose("Error collecting user agent: %@", error) + + #if os(iOS) + private func evaluateAgent() { + messageQueue.async { + self.isCollecting = true + DispatchQueue.main.async { + if self.webView == nil { + self.webView = WKWebView(frame: .zero) } - if let result = result as? String { - MPLog.verbose("Finished getting user agent") - self.resolvedUserAgent = result - } else { - if self.retryCount < 10 { - self.retryCount += 1 - MPLog.verbose("User agent collection failed (count=%@), retrying", self.retryCount) - self.webView = nil - DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { - self.evaluateAgent() - } - return + MPLog.verbose("Getting user agent") + self.webView?.evaluateJavaScript("navigator.userAgent") { result, error in + if result == nil, let error = error as? NSError { + MPLog.verbose("Error collecting user agent: %@", error) + } + if let result = result as? String { + MPLog.verbose("Finished getting user agent") + self.resolvedUserAgent = result } else { - MPLog.verbose("Falling back on default user agent") - self.resolvedUserAgent = self.defaultUserAgent + if self.retryCount < 10 { + self.retryCount += 1 + MPLog.verbose("User agent collection failed (count=%@), retrying", self.retryCount) + self.webView = nil + DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { + self.evaluateAgent() + } + return + } else { + MPLog.verbose("Falling back on default user agent") + self.resolvedUserAgent = self.defaultUserAgent + } + } + self.webView = nil + self.messageQueue.async { + self.isCollecting = false } - } - self.webView = nil - self.messageQueue.async { - self.isCollecting = false } } } } - } -#endif - + #endif + private var printedMessage = false private var printedMessageDelay = false @objc public func shouldDelayUpload(_ maxWaitTime: TimeInterval) -> Bool { guard let initializedDate = initializedDate, resolvedUserAgent == nil, isCollecting else { return false } - + if -initializedDate.timeIntervalSinceNow > maxWaitTime { if !printedMessage { printedMessage = true diff --git a/mParticle-Apple-SDK/Utils/NSArray+MPCaseInsensitive.swift b/mParticle-Apple-SDK/Utils/NSArray+MPCaseInsensitive.swift index d15ca622f..23ed274e6 100644 --- a/mParticle-Apple-SDK/Utils/NSArray+MPCaseInsensitive.swift +++ b/mParticle-Apple-SDK/Utils/NSArray+MPCaseInsensitive.swift @@ -7,8 +7,8 @@ import Foundation -extension NSArray { - @objc public func caseInsensitiveContainsObject(_ object: String) -> Bool { +public extension NSArray { + @objc func caseInsensitiveContainsObject(_ object: String) -> Bool { return contains { item in guard let item = item as? String else { return false @@ -18,8 +18,8 @@ extension NSArray { } } -extension Array { - public func caseInsensitiveContainsObject(_ object: String) -> Bool { +public extension Array { + func caseInsensitiveContainsObject(_ object: String) -> Bool { return (self as NSArray).caseInsensitiveContainsObject(object) } } diff --git a/mParticle-Apple-SDK/Utils/NSNumber+MPFormatter.swift b/mParticle-Apple-SDK/Utils/NSNumber+MPFormatter.swift index 93c6cb85f..b024ee8a2 100644 --- a/mParticle-Apple-SDK/Utils/NSNumber+MPFormatter.swift +++ b/mParticle-Apple-SDK/Utils/NSNumber+MPFormatter.swift @@ -9,11 +9,11 @@ import Foundation @objc public extension NSNumber { - @objc func formatWithNonScientificNotation() -> NSNumber { - let minThreshold = 1.0E-5 - let selfAbsoluteValue = fabs(self.doubleValue) + func formatWithNonScientificNotation() -> NSNumber { + let minThreshold = 1.0e-5 + let selfAbsoluteValue = fabs(doubleValue) var formattedNumber: NSNumber = 0 - + if selfAbsoluteValue >= minThreshold { let numberFormatter = NumberFormatter() numberFormatter.numberStyle = .decimal @@ -24,7 +24,7 @@ import Foundation formattedNumber = self } } - + return formattedNumber } } diff --git a/mParticle-Apple-SDK/Utils/NSString+MPPercentEscape.swift b/mParticle-Apple-SDK/Utils/NSString+MPPercentEscape.swift index ac86d7bd5..61fce5479 100644 --- a/mParticle-Apple-SDK/Utils/NSString+MPPercentEscape.swift +++ b/mParticle-Apple-SDK/Utils/NSString+MPPercentEscape.swift @@ -7,17 +7,17 @@ import Foundation -extension NSString { - @objc public func percentEscape() -> String? { +public extension NSString { + @objc func percentEscape() -> String? { var allowed = CharacterSet() allowed.insert(charactersIn: "; ") allowed = allowed.inverted - return self.addingPercentEncoding(withAllowedCharacters: allowed) + return addingPercentEncoding(withAllowedCharacters: allowed) } } -extension String { - public func percentEscape() -> String? { +public extension String { + func percentEscape() -> String? { return (self as NSString).percentEscape() } } diff --git a/mParticle_Apple_SDK.json b/mParticle_Apple_SDK.json index ec02964a6..2860a9ebf 100644 --- a/mParticle_Apple_SDK.json +++ b/mParticle_Apple_SDK.json @@ -1,123 +1,123 @@ { - "7.7.4": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.7.4/mParticle_Apple_SDK.framework.zip", - "7.7.5": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.7.5/mParticle_Apple_SDK.framework.zip", - "7.8.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.8.0/mParticle_Apple_SDK.framework.zip", - "7.8.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.8.1/mParticle_Apple_SDK.framework.zip", - "7.8.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.8.2/mParticle_Apple_SDK.framework.zip", - "7.8.3": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.8.3/mParticle_Apple_SDK.framework.zip", - "7.8.4": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.8.4/mParticle_Apple_SDK.framework.zip", - "7.8.5": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.8.5/mParticle_Apple_SDK.framework.zip", - "7.8.6": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.8.6/mParticle_Apple_SDK.framework.zip", - "7.9.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.9.0/mParticle_Apple_SDK.framework.zip", - "7.9.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.9.1/mParticle_Apple_SDK.framework.zip", - "7.9.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.9.2/mParticle_Apple_SDK.framework.zip", - "7.10.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.10.0/mParticle_Apple_SDK.framework.zip", - "7.10.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.10.1/mParticle_Apple_SDK.framework.zip", - "7.10.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.10.2/mParticle_Apple_SDK.framework.zip", - "7.10.3": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.10.3/mParticle_Apple_SDK.framework.zip", - "7.10.4": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.10.4/mParticle_Apple_SDK.framework.zip", - "7.10.5": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.10.5/mParticle_Apple_SDK.framework.zip", - "7.11.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.11.0/mParticle_Apple_SDK.framework.zip", - "7.12.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.12.0/mParticle_Apple_SDK.framework.zip", - "7.12.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.12.1/mParticle_Apple_SDK.framework.zip", - "7.12.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.12.2/mParticle_Apple_SDK.framework.zip", - "7.12.3": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.12.3/mParticle_Apple_SDK.framework.zip", - "7.12.4": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.12.4/mParticle_Apple_SDK.framework.zip", - "7.12.5": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.12.5/mParticle_Apple_SDK.framework.zip", - "7.12.6": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.12.6/mParticle_Apple_SDK.framework.zip", - "7.12.7": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.12.7/mParticle_Apple_SDK.framework.zip", - "7.13.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.13.0/mParticle_Apple_SDK.framework.zip", - "7.14.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.14.0/mParticle_Apple_SDK.framework.zip", - "7.15.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.15.0/mParticle_Apple_SDK.framework.zip", - "7.15.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.15.1/mParticle_Apple_SDK.framework.zip", - "7.15.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.15.2/mParticle_Apple_SDK.framework.zip", - "7.15.3": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.15.3/mParticle_Apple_SDK.framework.zip", - "7.15.4": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.15.4/mParticle_Apple_SDK.framework.zip", - "7.15.5": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.15.5/mParticle_Apple_SDK.framework.zip", - "7.15.6": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.15.6/mParticle_Apple_SDK.framework.zip", - "7.15.7": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.15.7/mParticle_Apple_SDK.framework.zip", - "7.15.8": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.15.8/mParticle_Apple_SDK.framework.zip", - "7.15.9": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.15.9/mParticle_Apple_SDK.framework.zip", - "7.15.10": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.15.10/mParticle_Apple_SDK.framework.zip", - "7.15.11": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.15.11/mParticle_Apple_SDK.framework.zip", - "7.16.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.16.0/mParticle_Apple_SDK.framework.zip", - "7.16.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.16.1/mParticle_Apple_SDK.framework.zip", - "7.16.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.16.2/mParticle_Apple_SDK.framework.zip", - "8.0.0-beta1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.0.0-beta1/mParticle_Apple_SDK.framework.zip", - "8.0.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.0.1/mParticle_Apple_SDK.framework.zip", - "8.1.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.1.0/mParticle_Apple_SDK.framework.zip", - "8.1.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.1.1/mParticle_Apple_SDK.framework.zip", - "8.1.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.1.2/mParticle_Apple_SDK.framework.zip", - "8.1.3": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.1.3/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.1.3/mParticle_Apple_SDK.xcframework.zip", - "8.1.4": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.1.4/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.1.4/mParticle_Apple_SDK.xcframework.zip", - "8.2.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.2.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.2.0/mParticle_Apple_SDK.xcframework.zip", - "8.3.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.3.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.3.0/mParticle_Apple_SDK.xcframework.zip", - "8.3.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.3.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.3.1/mParticle_Apple_SDK.xcframework.zip", - "8.3.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.3.2/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.3.2/mParticle_Apple_SDK.xcframework.zip", - "8.3.3": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.3.3/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.3.3/mParticle_Apple_SDK.xcframework.zip", - "8.4.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.4.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.4.0/mParticle_Apple_SDK.xcframework.zip", - "8.5.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.5.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.5.0/mParticle_Apple_SDK.xcframework.zip", - "8.5.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.5.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.5.1/mParticle_Apple_SDK.xcframework.zip", - "8.5.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.5.2/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.5.2/mParticle_Apple_SDK.xcframework.zip", - "8.5.3": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.5.3/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.5.3/mParticle_Apple_SDK.xcframework.zip", - "8.5.4": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.5.4/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.5.4/mParticle_Apple_SDK.xcframework.zip", - "8.6.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.6.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.6.0/mParticle_Apple_SDK.xcframework.zip", - "8.7.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.7.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.7.0/mParticle_Apple_SDK.xcframework.zip", - "8.8.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.8.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.8.0/mParticle_Apple_SDK.xcframework.zip", - "8.8.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.8.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.8.1/mParticle_Apple_SDK.xcframework.zip", - "8.9.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.9.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.9.0/mParticle_Apple_SDK.xcframework.zip", - "8.9.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.9.2/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.9.2/mParticle_Apple_SDK.xcframework.zip", - "8.10.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.10.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.10.0/mParticle_Apple_SDK.xcframework.zip", - "8.11.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.11.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.11.0/mParticle_Apple_SDK.xcframework.zip", - "8.11.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.11.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.11.1/mParticle_Apple_SDK.xcframework.zip", - "8.11.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.11.2/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.11.2/mParticle_Apple_SDK.xcframework.zip", - "8.12.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.12.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.12.0/mParticle_Apple_SDK.xcframework.zip", - "8.13.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.13.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.13.0/mParticle_Apple_SDK.xcframework.zip", - "8.14.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.14.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.14.1/mParticle_Apple_SDK.xcframework.zip", - "8.14.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.14.2/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.14.2/mParticle_Apple_SDK.xcframework.zip", - "8.15.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.15.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.15.0/mParticle_Apple_SDK.xcframework.zip", - "8.15.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.15.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.15.1/mParticle_Apple_SDK.xcframework.zip", - "8.16.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.16.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.16.0/mParticle_Apple_SDK.xcframework.zip", - "8.17.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.17.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.17.0/mParticle_Apple_SDK.xcframework.zip", - "8.18.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.18.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.18.0/mParticle_Apple_SDK.xcframework.zip", - "8.19.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.19.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.19.0/mParticle_Apple_SDK.xcframework.zip", - "8.20.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.20.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.20.0/mParticle_Apple_SDK.xcframework.zip", - "8.21.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.21.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.21.0/mParticle_Apple_SDK.xcframework.zip", - "8.21.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.21.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.21.1/mParticle_Apple_SDK.xcframework.zip", - "8.22.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.22.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.22.0/mParticle_Apple_SDK.xcframework.zip", - "8.23.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.23.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.23.0/mParticle_Apple_SDK.xcframework.zip", - "8.23.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.23.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.23.1/mParticle_Apple_SDK.xcframework.zip", - "8.24.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.24.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.24.0/mParticle_Apple_SDK.xcframework.zip", - "8.24.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.24.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.24.1/mParticle_Apple_SDK.xcframework.zip", - "8.24.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.24.2/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.24.2/mParticle_Apple_SDK.xcframework.zip", - "8.24.3": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.24.3/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.24.3/mParticle_Apple_SDK.xcframework.zip", - "8.25.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.25.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.25.0/mParticle_Apple_SDK.xcframework.zip", - "8.25.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.25.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.25.1/mParticle_Apple_SDK.xcframework.zip", - "8.26.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.26.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.26.0/mParticle_Apple_SDK.xcframework.zip", - "8.27.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.27.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.27.0/mParticle_Apple_SDK.xcframework.zip", - "8.27.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.27.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.27.1/mParticle_Apple_SDK.xcframework.zip", - "8.27.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.27.2/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.27.2/mParticle_Apple_SDK.xcframework.zip", - "8.27.3": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.27.3/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.27.3/mParticle_Apple_SDK.xcframework.zip", - "8.27.4": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.27.4/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.27.4/mParticle_Apple_SDK.xcframework.zip", - "8.27.5": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.27.5/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.27.5/mParticle_Apple_SDK.xcframework.zip", - "8.28.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.28.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.28.0/mParticle_Apple_SDK.xcframework.zip", - "8.28.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.28.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.28.1/mParticle_Apple_SDK.xcframework.zip", - "8.29.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.29.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.29.0/mParticle_Apple_SDK.xcframework.zip", - "8.30.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.30.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.30.0/mParticle_Apple_SDK.xcframework.zip", - "8.30.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.30.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.30.1/mParticle_Apple_SDK.xcframework.zip", - "8.30.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.30.2/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.30.2/mParticle_Apple_SDK.xcframework.zip", - "8.30.3": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.30.3/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.30.3/mParticle_Apple_SDK.xcframework.zip", - "8.31.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.31.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.31.0/mParticle_Apple_SDK.xcframework.zip", - "8.31.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.31.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.31.1/mParticle_Apple_SDK.xcframework.zip", - "8.31.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.31.2/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.31.2/mParticle_Apple_SDK.xcframework.zip", - "8.32.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.32.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.32.0/mParticle_Apple_SDK.xcframework.zip", - "8.33.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.33.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.33.0/mParticle_Apple_SDK.xcframework.zip", - "8.34.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.34.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.34.0/mParticle_Apple_SDK.xcframework.zip", - "8.34.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.34.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.34.1/mParticle_Apple_SDK.xcframework.zip", - "8.35.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.35.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.35.0/mParticle_Apple_SDK.xcframework.zip", - "8.36.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.36.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.36.0/mParticle_Apple_SDK.xcframework.zip", - "8.37.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.37.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.37.0/mParticle_Apple_SDK.xcframework.zip", - "8.37.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.37.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.37.1/mParticle_Apple_SDK.xcframework.zip", - "8.38.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.38.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.38.0/mParticle_Apple_SDK.xcframework.zip", - "8.39.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.39.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.39.0/mParticle_Apple_SDK.xcframework.zip" + "7.7.4": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.7.4/mParticle_Apple_SDK.framework.zip", + "7.7.5": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.7.5/mParticle_Apple_SDK.framework.zip", + "7.8.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.8.0/mParticle_Apple_SDK.framework.zip", + "7.8.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.8.1/mParticle_Apple_SDK.framework.zip", + "7.8.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.8.2/mParticle_Apple_SDK.framework.zip", + "7.8.3": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.8.3/mParticle_Apple_SDK.framework.zip", + "7.8.4": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.8.4/mParticle_Apple_SDK.framework.zip", + "7.8.5": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.8.5/mParticle_Apple_SDK.framework.zip", + "7.8.6": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.8.6/mParticle_Apple_SDK.framework.zip", + "7.9.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.9.0/mParticle_Apple_SDK.framework.zip", + "7.9.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.9.1/mParticle_Apple_SDK.framework.zip", + "7.9.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.9.2/mParticle_Apple_SDK.framework.zip", + "7.10.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.10.0/mParticle_Apple_SDK.framework.zip", + "7.10.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.10.1/mParticle_Apple_SDK.framework.zip", + "7.10.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.10.2/mParticle_Apple_SDK.framework.zip", + "7.10.3": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.10.3/mParticle_Apple_SDK.framework.zip", + "7.10.4": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.10.4/mParticle_Apple_SDK.framework.zip", + "7.10.5": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.10.5/mParticle_Apple_SDK.framework.zip", + "7.11.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.11.0/mParticle_Apple_SDK.framework.zip", + "7.12.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.12.0/mParticle_Apple_SDK.framework.zip", + "7.12.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.12.1/mParticle_Apple_SDK.framework.zip", + "7.12.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.12.2/mParticle_Apple_SDK.framework.zip", + "7.12.3": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.12.3/mParticle_Apple_SDK.framework.zip", + "7.12.4": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.12.4/mParticle_Apple_SDK.framework.zip", + "7.12.5": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.12.5/mParticle_Apple_SDK.framework.zip", + "7.12.6": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.12.6/mParticle_Apple_SDK.framework.zip", + "7.12.7": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.12.7/mParticle_Apple_SDK.framework.zip", + "7.13.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.13.0/mParticle_Apple_SDK.framework.zip", + "7.14.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.14.0/mParticle_Apple_SDK.framework.zip", + "7.15.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.15.0/mParticle_Apple_SDK.framework.zip", + "7.15.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.15.1/mParticle_Apple_SDK.framework.zip", + "7.15.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.15.2/mParticle_Apple_SDK.framework.zip", + "7.15.3": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.15.3/mParticle_Apple_SDK.framework.zip", + "7.15.4": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.15.4/mParticle_Apple_SDK.framework.zip", + "7.15.5": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.15.5/mParticle_Apple_SDK.framework.zip", + "7.15.6": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.15.6/mParticle_Apple_SDK.framework.zip", + "7.15.7": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.15.7/mParticle_Apple_SDK.framework.zip", + "7.15.8": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.15.8/mParticle_Apple_SDK.framework.zip", + "7.15.9": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.15.9/mParticle_Apple_SDK.framework.zip", + "7.15.10": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.15.10/mParticle_Apple_SDK.framework.zip", + "7.15.11": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.15.11/mParticle_Apple_SDK.framework.zip", + "7.16.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.16.0/mParticle_Apple_SDK.framework.zip", + "7.16.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.16.1/mParticle_Apple_SDK.framework.zip", + "7.16.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/7.16.2/mParticle_Apple_SDK.framework.zip", + "8.0.0-beta1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.0.0-beta1/mParticle_Apple_SDK.framework.zip", + "8.0.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.0.1/mParticle_Apple_SDK.framework.zip", + "8.1.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.1.0/mParticle_Apple_SDK.framework.zip", + "8.1.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.1.1/mParticle_Apple_SDK.framework.zip", + "8.1.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.1.2/mParticle_Apple_SDK.framework.zip", + "8.1.3": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.1.3/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.1.3/mParticle_Apple_SDK.xcframework.zip", + "8.1.4": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.1.4/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.1.4/mParticle_Apple_SDK.xcframework.zip", + "8.2.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.2.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.2.0/mParticle_Apple_SDK.xcframework.zip", + "8.3.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.3.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.3.0/mParticle_Apple_SDK.xcframework.zip", + "8.3.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.3.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.3.1/mParticle_Apple_SDK.xcframework.zip", + "8.3.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.3.2/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.3.2/mParticle_Apple_SDK.xcframework.zip", + "8.3.3": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.3.3/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.3.3/mParticle_Apple_SDK.xcframework.zip", + "8.4.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.4.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/8.4.0/mParticle_Apple_SDK.xcframework.zip", + "8.5.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.5.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.5.0/mParticle_Apple_SDK.xcframework.zip", + "8.5.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.5.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.5.1/mParticle_Apple_SDK.xcframework.zip", + "8.5.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.5.2/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.5.2/mParticle_Apple_SDK.xcframework.zip", + "8.5.3": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.5.3/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.5.3/mParticle_Apple_SDK.xcframework.zip", + "8.5.4": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.5.4/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.5.4/mParticle_Apple_SDK.xcframework.zip", + "8.6.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.6.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.6.0/mParticle_Apple_SDK.xcframework.zip", + "8.7.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.7.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.7.0/mParticle_Apple_SDK.xcframework.zip", + "8.8.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.8.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.8.0/mParticle_Apple_SDK.xcframework.zip", + "8.8.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.8.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.8.1/mParticle_Apple_SDK.xcframework.zip", + "8.9.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.9.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.9.0/mParticle_Apple_SDK.xcframework.zip", + "8.9.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.9.2/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.9.2/mParticle_Apple_SDK.xcframework.zip", + "8.10.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.10.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.10.0/mParticle_Apple_SDK.xcframework.zip", + "8.11.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.11.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.11.0/mParticle_Apple_SDK.xcframework.zip", + "8.11.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.11.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.11.1/mParticle_Apple_SDK.xcframework.zip", + "8.11.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.11.2/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.11.2/mParticle_Apple_SDK.xcframework.zip", + "8.12.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.12.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.12.0/mParticle_Apple_SDK.xcframework.zip", + "8.13.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.13.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.13.0/mParticle_Apple_SDK.xcframework.zip", + "8.14.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.14.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.14.1/mParticle_Apple_SDK.xcframework.zip", + "8.14.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.14.2/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.14.2/mParticle_Apple_SDK.xcframework.zip", + "8.15.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.15.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.15.0/mParticle_Apple_SDK.xcframework.zip", + "8.15.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.15.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.15.1/mParticle_Apple_SDK.xcframework.zip", + "8.16.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.16.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.16.0/mParticle_Apple_SDK.xcframework.zip", + "8.17.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.17.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.17.0/mParticle_Apple_SDK.xcframework.zip", + "8.18.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.18.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.18.0/mParticle_Apple_SDK.xcframework.zip", + "8.19.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.19.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.19.0/mParticle_Apple_SDK.xcframework.zip", + "8.20.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.20.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.20.0/mParticle_Apple_SDK.xcframework.zip", + "8.21.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.21.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.21.0/mParticle_Apple_SDK.xcframework.zip", + "8.21.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.21.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.21.1/mParticle_Apple_SDK.xcframework.zip", + "8.22.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.22.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.22.0/mParticle_Apple_SDK.xcframework.zip", + "8.23.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.23.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.23.0/mParticle_Apple_SDK.xcframework.zip", + "8.23.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.23.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.23.1/mParticle_Apple_SDK.xcframework.zip", + "8.24.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.24.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.24.0/mParticle_Apple_SDK.xcframework.zip", + "8.24.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.24.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.24.1/mParticle_Apple_SDK.xcframework.zip", + "8.24.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.24.2/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.24.2/mParticle_Apple_SDK.xcframework.zip", + "8.24.3": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.24.3/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.24.3/mParticle_Apple_SDK.xcframework.zip", + "8.25.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.25.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.25.0/mParticle_Apple_SDK.xcframework.zip", + "8.25.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.25.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.25.1/mParticle_Apple_SDK.xcframework.zip", + "8.26.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.26.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.26.0/mParticle_Apple_SDK.xcframework.zip", + "8.27.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.27.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.27.0/mParticle_Apple_SDK.xcframework.zip", + "8.27.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.27.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.27.1/mParticle_Apple_SDK.xcframework.zip", + "8.27.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.27.2/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.27.2/mParticle_Apple_SDK.xcframework.zip", + "8.27.3": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.27.3/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.27.3/mParticle_Apple_SDK.xcframework.zip", + "8.27.4": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.27.4/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.27.4/mParticle_Apple_SDK.xcframework.zip", + "8.27.5": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.27.5/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.27.5/mParticle_Apple_SDK.xcframework.zip", + "8.28.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.28.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.28.0/mParticle_Apple_SDK.xcframework.zip", + "8.28.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.28.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.28.1/mParticle_Apple_SDK.xcframework.zip", + "8.29.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.29.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.29.0/mParticle_Apple_SDK.xcframework.zip", + "8.30.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.30.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.30.0/mParticle_Apple_SDK.xcframework.zip", + "8.30.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.30.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.30.1/mParticle_Apple_SDK.xcframework.zip", + "8.30.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.30.2/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.30.2/mParticle_Apple_SDK.xcframework.zip", + "8.30.3": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.30.3/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.30.3/mParticle_Apple_SDK.xcframework.zip", + "8.31.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.31.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.31.0/mParticle_Apple_SDK.xcframework.zip", + "8.31.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.31.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.31.1/mParticle_Apple_SDK.xcframework.zip", + "8.31.2": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.31.2/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.31.2/mParticle_Apple_SDK.xcframework.zip", + "8.32.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.32.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.32.0/mParticle_Apple_SDK.xcframework.zip", + "8.33.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.33.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.33.0/mParticle_Apple_SDK.xcframework.zip", + "8.34.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.34.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.34.0/mParticle_Apple_SDK.xcframework.zip", + "8.34.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.34.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.34.1/mParticle_Apple_SDK.xcframework.zip", + "8.35.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.35.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.35.0/mParticle_Apple_SDK.xcframework.zip", + "8.36.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.36.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.36.0/mParticle_Apple_SDK.xcframework.zip", + "8.37.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.37.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.37.0/mParticle_Apple_SDK.xcframework.zip", + "8.37.1": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.37.1/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.37.1/mParticle_Apple_SDK.xcframework.zip", + "8.38.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.38.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.38.0/mParticle_Apple_SDK.xcframework.zip", + "8.39.0": "https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.39.0/mParticle_Apple_SDK.framework.zip?alt=https://github.com/mParticle/mparticle-apple-sdk/releases/download/v8.39.0/mParticle_Apple_SDK.xcframework.zip" } diff --git a/migration-guide-v8.md b/migration-guide-v8.md index d90e9735f..80ca10f32 100644 --- a/migration-guide-v8.md +++ b/migration-guide-v8.md @@ -11,7 +11,7 @@ The mParticle platform has been adapting to these changes and we've made several - mParticle released Apple SDK 8.2.0 in February 2021, in anticipation of the iOS 14.5 release. Version 8.2.0 exposes a new API to collect the device's App Tracking Transparency authorization status - mParticle is continually releasing updates for both server-side integrations and client-side kit integrations, as the respective partner APIs and SDKs adapt -## Preparing for iOS 14 +## Preparing for iOS 14 Under these new privacy guidelines each app must ensure that all user data processing obeys user consent elections and ultimately protects them from breaching App Store Review guidelines. @@ -37,10 +37,9 @@ The mParticle Apple SDK automatically collects the publisher-sandboxed IDFV, but - mParticle has introduced a new `att_authorization_status` field to [our data model](https://docs.mparticle.com/developers/server/json-reference/), which surfaces the same values as Apple's [`ATTrackingManagerAuthorizationStatus` enumeration](https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanagerauthorizationstatus) - mParticle has also introduced an optional `att_timestamp_unixtime_ms` field representing the time when the user responded to the ATT prompt or their status was otherwise updated - The Apple SDK lets you set these two fields, and the `MPATTAuthorizationStatus` enumeration maps directly to Apple’s `ATTrackingManagerAuthorizationStatus` enumeration. -- All customers implementing the Apple SDK or sending iOS data server-to-server are encouraged to begin collecting and sending the status field. +- All customers implementing the Apple SDK or sending iOS data server-to-server are encouraged to begin collecting and sending the status field. - **At a future date, this field will become required when providing mParticle with an IDFA** - ### Collecting ATT Status with Apple SDK 8.2.0+ Once provided to the SDK, the ATT status will be stored by the SDK on the device and continually included with all future uploads, for all MPIDs for the device. If not provided, the timestamp will be set to the current time. The SDK will ignore API calls to change the ATT status, if the ATT status hasn’t changed from the previous API call. This allows the SDK to keep track of the originally provided timestamp. @@ -50,7 +49,7 @@ There are two locations where you should provide the ATT status: #### 1. On SDK Initialization ```swift -let options = MParticleOptions(key: "REPLACE WITH APP KEY", secret: "REPLACE WITH APP SECRET") +let options = MParticleOptions(key: "REPLACE WITH APP KEY", secret: "REPLACE WITH APP SECRET") options.attStatus = NSNumber.init(value: ATTrackingManager.trackingAuthorizationStatus.rawValue) MParticle.sharedInstance().start(with: options) ``` @@ -67,7 +66,7 @@ ATTrackingManager.requestTrackingAuthorization { status in switch status { case .authorized: MParticle.sharedInstance().setATTStatus((MPATTAuthorizationStatus)status, withTimestampMillis: nil) - + // Now that we are authorized we can get the IDFA, supply to mParticle Identity API as needed var identityRequest = MPIdentityApiRequest.withEmptyUser() identityRequest.setIdentity(ASIdentifierManager.shared().advertisingIdentifier.uuidString, identityType: MPIdentity.iosAdvertiserId) @@ -122,14 +121,15 @@ MPIdentityApiRequest *identityRequest = [MPIdentityApiRequest requestWithUser:cu [[[MParticle sharedInstance] identity] modify:identityRequest completion:identityCallback]; ``` -*Note*: Starting in 2021, to collect the IDFA with Apple SDK 8 you will need to [follow Apple's guidelines](https://developer.apple.com/documentation/apptrackingtransparency) to implement the AppTrackingTransparancy framework. If the user consents to tracking, providing the IDFA proceeds as already described. If they do not or the AppTrackingTransparancy framework is not implemented, ASIdentifierManager's `advertisingIdentifier` API will return a nil, all-zero IDFA. +_Note_: Starting in 2021, to collect the IDFA with Apple SDK 8 you will need to [follow Apple's guidelines](https://developer.apple.com/documentation/apptrackingtransparency) to implement the AppTrackingTransparancy framework. If the user consents to tracking, providing the IDFA proceeds as already described. If they do not or the AppTrackingTransparancy framework is not implemented, ASIdentifierManager's `advertisingIdentifier` API will return a nil, all-zero IDFA. #### Common IDFA Use-cases The following are some common use-cases and best practices: -1. If you are looking to collect IDFA, you should *always* provide it to the mParticle SDK when creating an identity request + +1. If you are looking to collect IDFA, you should _always_ provide it to the mParticle SDK when creating an identity request 2. On first launch of your app, the mParticle SDK will make an initial identify request. If the user has never consented to IDFA collection, IDFA will be unavailable to you, and as such you will not be able to provide it on your initial identity request. If and when the IDFA is made available to your app, you should perform an `identify` request or a `modify` request, supplying all known IDs of the current user as well as the newly known IDFA. -3. When a user logs out of your application, be sure to provide IDFA to the identity `logout` API - it will *NOT* automatically be passed from one user to the next. You must provide it for *every identity request*. +3. When a user logs out of your application, be sure to provide IDFA to the identity `logout` API - it will _NOT_ automatically be passed from one user to the next. You must provide it for _every identity request_. [See the example application](https://github.com/mParticle/mparticle-apple-sdk/tree/master/Example) in the Apple SDK repository for a full implementation of the AppTrackingTransparency framework. @@ -137,7 +137,7 @@ The following are some common use-cases and best practices: ## App Clips -Apple SDK 8 is compatible with App Clips. The SDK is designed to be light-weight and has few dependencies on outside frameworks, and as such functions without issue within the limited capacity of an App Clip. [See Apple's guidelines here](https://developer.apple.com/documentation/app_clips/developing_a_great_app_clip) for the frameworks and identifers available in an App Clip. +Apple SDK 8 is compatible with App Clips. The SDK is designed to be light-weight and has few dependencies on outside frameworks, and as such functions without issue within the limited capacity of an App Clip. [See Apple's guidelines here](https://developer.apple.com/documentation/app_clips/developing_a_great_app_clip) for the frameworks and identifers available in an App Clip. **Notably, IDFV is not available in an App Clip, so you cannot rely on this identifier for App Clip data collected via mParticle.** @@ -156,7 +156,7 @@ The mParticle Apple SDK's API is unchanged, but you can now provide this reduced ## Kit Dependencies -Historically mParticle has centrally managed and released most kits. This allowed us to rapidly improve the APIs exposed to kits, while also providing app developers with a consistent experience. Specifically, with SDK version 7 and earlier, the mParticle engineering team would release *matching* versions of all kits. So for example, your Podfile (or Cartfile) should have looked something like this, with *all versions matching*: +Historically mParticle has centrally managed and released most kits. This allowed us to rapidly improve the APIs exposed to kits, while also providing app developers with a consistent experience. Specifically, with SDK version 7 and earlier, the mParticle engineering team would release _matching_ versions of all kits. So for example, your Podfile (or Cartfile) should have looked something like this, with _all versions matching_: ```ruby pod 'mParticle-Apple-SDK', '7.16.2' @@ -176,4 +176,4 @@ pod 'mParticle-Appboy', '~> 8.0' pod 'mParticle-BranchMetrics','~> 8.0' ``` -The above Podfile may eventually resolve to different versions of each kit. However, mParticle has committed to making *no breaking API changes to kit APIs prior to the next major version, 9.0*. This means that it's always in your best interest to update to the latest versions of all kits as well as the Core SDK, and you do not need to worry about matching versions across your kit dependencies. +The above Podfile may eventually resolve to different versions of each kit. However, mParticle has committed to making _no breaking API changes to kit APIs prior to the next major version, 9.0_. This means that it's always in your best interest to update to the latest versions of all kits as well as the Core SDK, and you do not need to worry about matching versions across your kit dependencies. diff --git a/release.config.js b/release.config.js index 74bdf262e..11ef3d4e5 100644 --- a/release.config.js +++ b/release.config.js @@ -1,42 +1,43 @@ module.exports = { - branches: ["main"], - tagFormat: "v${version}", - plugins: [ - [ - "@semantic-release/commit-analyzer", - { - preset: "angular", - }, - ], - [ - "@semantic-release/release-notes-generator", - { - preset: "angular", - }, - ], - [ - "@semantic-release/changelog", - { - changelogFile: "CHANGELOG.md", - }, - ], - [ - "@semantic-release/exec", - { - prepareCmd: "sh ./Scripts/release.sh ${nextRelease.version} \"${nextRelease.notes}\"", - }, - ], - [ - "@semantic-release/github", - { - assets: [ - "mParticle_Apple_SDK.framework.zip", - "mParticle_Apple_SDK_NoLocation.framework.zip", - "mParticle_Apple_SDK.xcframework.zip", - "mParticle_Apple_SDK_NoLocation.xcframework.zip", - "generated-docs.zip", - ], - }, - ], + branches: ["main"], + tagFormat: "v${version}", + plugins: [ + [ + "@semantic-release/commit-analyzer", + { + preset: "angular", + }, ], - }; + [ + "@semantic-release/release-notes-generator", + { + preset: "angular", + }, + ], + [ + "@semantic-release/changelog", + { + changelogFile: "CHANGELOG.md", + }, + ], + [ + "@semantic-release/exec", + { + prepareCmd: + 'sh ./Scripts/release.sh ${nextRelease.version} "${nextRelease.notes}"', + }, + ], + [ + "@semantic-release/github", + { + assets: [ + "mParticle_Apple_SDK.framework.zip", + "mParticle_Apple_SDK_NoLocation.framework.zip", + "mParticle_Apple_SDK.xcframework.zip", + "mParticle_Apple_SDK_NoLocation.xcframework.zip", + "generated-docs.zip", + ], + }, + ], + ], +};