Skip to content

3.0.0

Latest

Choose a tag to compare

@dobreandl dobreandl released this 14 Sep 12:56
· 2 commits to main since this release

Binary distribution

GrovsSDK.xcframework.zip below is the prebuilt framework (device + simulator, library evolution enabled). Its module is GrovsSDK — use import GrovsSDK; Swift Package Manager and CocoaPods use import Grovs.

Supersedes 2.4, which was bumped in the podspec but never tagged or published.

Added

  • Custom event tracking: Grovs.track(_:properties:tags:), Grovs.setGlobalTags(_:), and
    batched dispatch with retry.
  • Screen view tracking: automatic UIKit tracking, Grovs.trackScreenView(_:properties:),
    the GrovsScreenTracking protocol, Grovs.setScreenAliases(_:),
    Grovs.screenNameProvider, and the SwiftUI View.grovsScreen() modifier.
  • Purchase tracking: Grovs.logInAppPurchase(transactionID:completion:) and
    Grovs.logCustomPurchase(type:priceInCents:currency:productID:startDate:completion:).
  • Clipboard-assisted deferred deep link matching, gated on a gd parameter and a domain
    allowlist (clipboardDomains: on configure), plus a copyToClipboardiOS link flag.
  • Error reporting to the host app through the optional
    GrovsDelegate.grovsDidEncounterError(_:message:).
  • PrivacyInfo.xcprivacy privacy manifest, shipped for SPM, CocoaPods, and the
    xcframework.
  • A hosted test harness (scripts/run_hosted_tests.sh) so the keychain tests assert
    instead of skipping, and CI running tests, Thread Sanitizer, hosted keychain tests, and
    a version-drift gate.

Changed

  • Logging goes through os_log and is redacted in release builds; Grovs.setDebug(level:)
    now takes the public LogLevel.
  • The device payload and purchase events carry session_id.
  • The raw device identifier is sent instead of a mapped model name.
  • vendor_id is omitted while identifierForVendor is unavailable (before first unlock
    after a reboot) instead of sending a shared "unknown" that the backend would match as
    one device.
  • The privacy manifest declares collected data as linked to the user, since the host's
    userIdentifier is stored against the same device record.
  • Custom purchases carry a client-minted transaction_id, so a retry of a request the
    backend already committed is deduplicated instead of counted twice.
  • A user agent fetched on an earlier launch is reused until the OS version changes, so
    WebKit is no longer spun up on every cold launch.
  • CocoaPods ships the XIBs inside the Grovs resource bundle rather than loose in the
    host app, where a nib with the same name would collide.
  • Cached event archives require secure coding.
  • Requests are never sent without a parseable User-Agent.
  • The SDK version has a single source of truth (GrovsVersion.current), checked against
    the podspec and MARKETING_VERSION in CI.
  • Internal types that were unnecessarily public are internal again; the supported surface
    is Grovs, GrovsDelegate, GrovsError, GrovsScreenTracking, GrovsScreenName,
    LogLevel, TransactionType, CustomLinkRedirect/CustomRedirects, and
    View.grovsScreen().

Fixed

  • Disabling the SDK now stops all collection — including identifier, attribute, and push
    token updates, and lifecycle events already read from storage when consent is withdrawn —
    and payloads without a link are still delivered.
  • Purchases persisted by an earlier launch are retried as soon as the SDK authenticates,
    instead of waiting for the next foreground.
  • A superseded screen-alias response no longer discards newer aliases that are still
    pending.
  • The message view stops its spinner when a page fails before the navigation commits
    (offline, DNS, TLS).
  • Auto-displayed messages are no longer suppressed after a failed presentation, nor shown
    twice by overlapping display chains.
  • Messages list pagination: a page superseded by a refresh is discarded, an older refresh
    can't overwrite a newer one, and a failed page is retried rather than skipped.
  • Duplicate device resolves no longer cancel in-flight requests or release held events
    early.
  • Keychain writes survive protection-class changes, and the SDK self-heals when the
    backend rejects the device identifier.
  • Retain cycles, identity-recovery ordering, observer cleanup, and several data races
    (the suite runs clean under Thread Sanitizer).
  • The AutoScreenTracker swizzle composes with other viewDidAppear swizzlers, and no
    longer replaces a completion block the host set on its own CATransaction.
  • An unparseable baseURL refuses configuration and reports false instead of trapping.
  • Retry-After is capped at 60 seconds.
  • The clipboard flow reads the pasteboard once, so a denied paste alert isn't shown twice.

Security

  • Message content can only open http, https, mailto, tel, and sms links
    externally; every other scheme is ignored.