Docs

iOS SDK 3.0

What changes when you move the Grovs iOS SDK from 2.x to 3.0

3.0.0 is a major release: it removes four public types that were SDK internals and changes one closure signature. Most apps upgrade by bumping the version, deciding on automatic screen tracking, and checking how they use setSDK(enabled:).

Requirements are unchanged: iOS 13.0, Swift 5.9 (Xcode 15).

Checklist

  1. Bump the dependency to 3.0.0.
  2. Decide on automatic screen tracking — it is on by default.
  3. Remove references to types that are now internal.
  4. Update GrovsDeviceDataClosureClosure if you name it.
  5. Review your consent gatingsetSDK(enabled: false) now stops everything, and configure has an enabled: parameter.
  6. Check the other behavior changes — the clipboard paste prompt, links in messages, and your App Store privacy details.

1. Bump the version

Swift Package Manager — in Xcode, open your project's Package Dependencies, select the Grovs package, and set the rule to Up to Next Major Version from 3.0.0. A rule pinned to 2.x will not pick up 3.0 on its own. In a Package.swift:

Swift
.package(url: "https://github.com/grovs-io/grovs-iOS.git", from: "3.0.0")

CocoaPods — in your Podfile:

Ruby
pod 'Grovs', '~> 3.0'

Then run pod update Grovs.

2. Decide on automatic screen tracking

This changes behavior without any code edit on your side.

autoTrackScreenViews defaults to true. An app that only recompiles starts hooking UIViewController.viewDidAppear and sending a screen_view event for each screen.

Keep it if you want screen analytics — see Events & Screen Tracking for how names are chosen and how to override them.

To opt out, pass false:

Swift
Grovs.configure(
    APIKey: "your-api-key",
    useTestEnvironment: false,
    autoTrackScreenViews: false,
    delegate: self
)

Existing configure calls compile unchanged — every new parameter has a default.

3. Remove references to types that are now internal

Four types were public in 2.x and are internal in 3.0. They were SDK implementation details, but if your code referenced or subclassed one, the build fails:

TypeWasReplacement
DataCacheopen class, plus DataCache.instanceNone. Use your own cache.
BaseServiceopen classNone. Use URLSession directly.
ImageFormatpublic enumNone.
JSONClosurepublic typealiasDefine your own closure type.

Everything else public in 2.x is still public and source-compatible.

4. Update GrovsDeviceDataClosureClosure if you use it

The typealias gained a leading success flag so a transport failure can be told apart from an empty result:

Swift
// 2.x
(_ dictionary: [String: Any]?, _ link: String?, _ tracking: [String: Any]?) -> Void
 
// 3.0
(_ success: Bool, _ dictionary: [String: Any]?, _ link: String?, _ tracking: [String: Any]?) -> Void

No public method uses this type. If you declared a variable or parameter with it, add the leading parameter.

setSDK(enabled: false) now stops everything. In 2.x it blocked link generation and deep link resolution but left lifecycle event collection running. In 3.0, while disabled, the SDK does not authenticate, resolve the device, or send lifecycle events, custom events, screen views, or purchases. Changes to userIdentifier, userAttributes, pushToken, and screen aliases are held and sent when you enable it again. Events already queued stay on disk.

Start disabled with enabled:. Calling setSDK(enabled: false) right after configure is too late — configuring starts the first round of collection. If you gate on consent, pass it to configure instead:

Swift
// 2.x — collection has already started when setSDK runs
Grovs.configure(APIKey: "your-api-key", useTestEnvironment: false, delegate: self)
if !hasConsent {
    Grovs.setSDK(enabled: false)
}
 
// 3.0
Grovs.configure(APIKey: "your-api-key", useTestEnvironment: false, enabled: hasConsent, delegate: self)

The value is not persisted, so pass your stored consent on every launch. A disabled configure reports false to its completion without attempting authentication — if that completion feeds your error reporting, don't count it as a failure. See Privacy & Consent.

6. Check the other behavior changes

Clipboard-assisted deferred deep linking is on. On the first launch after a fresh install, the SDK can read a Grovs link from the clipboard to attribute the install, and iOS may show its paste confirmation. This only happens if the backend reports recent clicks on copy-to-clipboard links for your project (currently a 48-hour window) and the device's clipboard holds a web URL. If you never enable copy-to-clipboard for your project or its links, the prompt never appears. See Clipboard-assisted deferred deep linking.

Links in messages are restricted. Message content now opens only http, https, mailto, tel, and sms links. Any other scheme is ignored — if your messages link to a custom scheme such as yourapp://, switch those to a universal link.

The SDK ships a privacy manifest. PrivacyInfo.xcprivacy is bundled for Swift Package Manager and CocoaPods and is merged into your app's privacy report. Check your App Store privacy details against what the SDK collects.

Logging moved to os_log. setDebug(level:) works as before. In release builds, message content is marked private and appears as <private> in Console.app.

Device model is reported as Apple's identifier. The SDK sends the hardware identifier (for example iPhone15,2) instead of a name mapped inside the SDK, so new devices are reported without an SDK update.

Queued events survive the upgrade. 3.0 reads event archives written by 2.x, so nothing pending on a user's device is lost.

What's new in 3.0

Nothing here is required:

Verifying the upgrade

Turn on info logging before configure and confirm the completion reports true:

Swift
Grovs.setDebug(level: .info)
Grovs.configure(APIKey: "your-api-key", useTestEnvironment: true, delegate: self) { success in
    print("Grovs configured: \(success)")
}

Then check that deep links still reach grovsReceivedPayloadFromDeeplink, and — if you kept automatic screen tracking — that screen views appear in the dashboard under names you recognize. Use setScreenAliases to rename any that read like class names.

See also

Edit this page on GitHubLast updated 2026-09-15