# iOS SDK 3.0

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

Source: https://docs.grovs.io/docs/upgrade-guides/ios-3-0

3.0.0 removes four public types that were SDK internals and changes one closure signature. Most apps bump the version, decide on automatic screen tracking, and check how they use `setSDK(enabled:)`.

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

## Checklist

1. [Bump the dependency](#1-bump-the-version) to 3.0.0.
2. [Decide on automatic screen tracking](#2-decide-on-automatic-screen-tracking). It's on by default.
3. [Remove references to types that are now internal](#3-remove-references-to-types-that-are-now-internal).
4. [Update `GrovsDeviceDataClosureClosure`](#4-update-grovsdevicedataclosureclosure-if-you-use-it) if you name it.
5. [Review your consent gating](#5-review-your-consent-gating): `setSDK(enabled: false)` now stops everything, and `configure` has an `enabled:` parameter.
6. [Check the other behavior changes](#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 your project's **Package Dependencies**, select Grovs and set the rule to **Up to Next Major Version** from `3.0.0`. A rule pinned to 2.x won't pick up 3.0. In a `Package.swift`:

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

**CocoaPods:** in your `Podfile`, then run `pod update Grovs`:

```ruby
pod 'Grovs', '~> 3.0'
```

## 2. Decide on automatic screen tracking

> **Warning:** This changes behavior with no code change 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 for screen analytics. [Events & Screen Tracking](https://docs.grovs.io/docs/sdk/ios/analytics#automatic-screen-tracking) explains how names are chosen and overridden.

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 public in 2.x are internal in 3.0. They were implementation details, but code that referenced or subclassed one won't build:

| Type          | Was                                     | Replacement                      |
| ------------- | --------------------------------------- | -------------------------------- |
| `DataCache`   | `open class`, plus `DataCache.instance` | None. Use your own cache.        |
| `BaseService` | `open class`                            | None. Use `URLSession` directly. |
| `ImageFormat` | `public enum`                           | None.                            |
| `JSONClosure` | `public typealias`                      | Define 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 differs 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.

## 5. Review your consent gating

**`setSDK(enabled: false)` now stops everything.** In 2.x it blocked link generation and deep link resolution but kept collecting lifecycle events. In 3.0, while disabled, the SDK doesn't authenticate, resolve the device, or send lifecycle events, custom events, screen views or purchases. Changes to `userIdentifier`, `userAttributes`, `pushToken` and screen aliases are held until you re-enable it. Queued events 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`:

```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 isn't persisted, so pass your stored consent on every launch. A disabled `configure` reports `false` without authenticating. If that completion feeds your error reporting, don't count it as a failure. See [Privacy & Consent](https://docs.grovs.io/docs/sdk/ios/privacy).

## 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 prompt. It happens only if the backend reports recent clicks on copy-to-clipboard links for your project (currently a 48-hour window) and the clipboard holds a web URL. If you never enable copy-to-clipboard for the project or its links, the prompt never appears. See [Clipboard-assisted deferred deep linking](https://docs.grovs.io/docs/sdk/ios/deep-linking#clipboard-assisted-deferred-deep-linking).

**Links in messages are restricted.** Message content now opens only `http`, `https`, `mailto`, `tel`, and `sms` links. Other schemes are ignored. Switch links that use a custom scheme such as `yourapp://` to a universal link.

**The SDK ships a privacy manifest.** `PrivacyInfo.xcprivacy` is bundled for Swift Package Manager and CocoaPods and merged into your app's privacy report. Check your App Store privacy details against [what the SDK collects](https://docs.grovs.io/docs/sdk/ios/privacy#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 Apple's identifier.** The SDK sends the hardware identifier (for example `iPhone15,2`) instead of a mapped name, so new devices need no SDK update.

**Queued events survive the upgrade.** 3.0 reads 2.x event archives, so nothing pending is lost.

## What's new in 3.0

Nothing here is required.

- **[Custom events and screen tracking](https://docs.grovs.io/docs/sdk/ios/analytics)**: `track`, `trackScreenView`, global tags, screen aliases, `.grovsScreen()` for SwiftUI, and `GrovsScreenTracking` for UIKit.
- **[Consent gating](https://docs.grovs.io/docs/sdk/ios/privacy)**: the `enabled:` parameter on `configure`, and a `setSDK(enabled:)` that stops all collection.
- **[Error callbacks](https://docs.grovs.io/docs/sdk/ios/deep-linking#handling-sdk-errors)**: an optional `grovsDidEncounterError(_:message:)` on `GrovsDelegate`. It has a default implementation, so existing delegates need no change.
- **[Clipboard-assisted deferred deep linking](https://docs.grovs.io/docs/sdk/ios/deep-linking#clipboard-assisted-deferred-deep-linking)**: deterministic install attribution on first launch, with `clipboardDomains` for custom link domains.
- **[`copyToClipboardiOS` / `copyToClipboardAndroid`](https://docs.grovs.io/docs/sdk/ios/link-creation)**: per-link override of the project's copy-to-clipboard setting.
- **`displayMessagesViewController(completion:onFailure:)`**: tells a dismissal apart from a presentation that never happened. The messages inbox was later removed in [3.1](https://docs.grovs.io/docs/upgrade-guides/ios-3-1).

## 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`. If you kept automatic screen tracking, check that screen views appear in the dashboard under names you recognize. Rename any that read like class names with [`setScreenAliases`](https://docs.grovs.io/docs/sdk/ios/analytics#screen-name-aliases).

## See also

- [Quick Start](https://docs.grovs.io/docs/sdk/ios/quick-start): full configuration reference
- [API Reference](https://docs.grovs.io/docs/sdk/ios/api-reference): every property, method, and type
- [SDK Releases](https://docs.grovs.io/docs/sdk/releases): where release notes are published
