# What's new in 3.1

SDK 3.1.0 for iOS and Android adds content commitments, and proofs now bind the region they answer for. The React Native wrapper ships alongside it. 3.1.1 and 3.1.2 change only how the iOS framework is packaged, with no change to the API or to proofs. If you add the framework with Carthage or by hand, set it to Embed & Sign from 3.1.2 (see [Carthage](/docs/mobile/getting-started/ios-quickstart/#carthage)). Android is unchanged. The full release notes are in the [`octet-sdk-ios`](https://github.com/octetproof/octet-sdk-ios/blob/main/CHANGELOG.md) and [`octet-sdk-android`](https://github.com/octetproof/octet-sdk-android/blob/main/CHANGELOG.md) changelogs, and the 3.0 docs stay at [/docs/v3.0/](/docs/v3.0/).

## What you may need to change

- **Update your verifier to `octet-verify` 1.8.0 or later.** A 3.1 proof uses semantic binding v3, which `octet-verify` 1.5.0 and later check. Older verifiers fail every 3.1 proof. Checking content commitments needs 1.8.0, built with `--features caller-metadata`. Update the verifier before your apps ship 3.1. See [Verifying a commitment](/docs/mobile/concepts/content-commitments/#verifying-a-commitment).
- **No confidence score or assurance tier.** To keep the answer simple, 3.1 reports neither: `confidence` holds `0` and empty lists, `spoofingVerdict` is `UNSPECIFIED`, and `requireVerdict` is ignored. Act on `result` and `reason`, which don't change. If you need more device intelligence or your own scoring logic, Octet offers it as a custom feature or license. See [`OctetVerdict`](/docs/mobile/api-reference/octet-verdict/#confidence).
- **`CheckStatus` has a new case, `inconclusive`.** A `switch` (Swift) or `when` (Kotlin) over `CheckStatus` without a default branch no longer compiles. Add the case or a default branch. See [`Octet.verify`](/docs/mobile/api-reference/octet-verify/).
- **`isAuthentic` is false when a check is `INCONCLUSIVE`.** Today only the content check can be inconclusive, so this changes nothing unless you pass `callerMetadata`.
- **Handle a license that stops while the app runs.** Predicates can now return `INDETERMINATE` with reason `licenseInactive` / `LICENSE_INACTIVE`, and `LicenseState` has a new case, `revoked` / `REVOKED`. A `switch` (Swift) or `when` (Kotlin) over `ReasonCode` or `LicenseState` without a default branch no longer compiles. On Android, the same goes for a `when` over `BootstrapReason`. See [License Types](/docs/mobile/api-reference/license-types/#licensestate).
- **Android: recompile.** `AdvancedConfig` has a new constructor parameter, so code compiled against 3.0 that calls its constructor or `copy` must be recompiled.

## Deprecated

These still work in 3.1 and are removed in 4.0.

- **`OctetConfig.licenseKey`.** `Octet.start` doesn't use it, so leave it out: `OctetConfig()` needs no arguments. Code that still passes it builds with a deprecation warning.
- **`overallScore`, `spoofingRiskScore`, `sensorContributions` and `flags` on `ConfidenceSummary`, and `VerifyOptions.requireVerdict`.**
- **`Octet.creditStatus()` and `CreditStatus`.** Usage reporting never refuses, so they always reported that you're not over quota. To detect the free-plan device limit, handle the `newDevicesBlocked` start error (`NEW_DEVICES_BLOCKED` in React Native) and open its `upgradeUrl`. See [Handling `newDevicesBlocked`](/docs/mobile/api-reference/license-types/#handling-newdevicesblocked).

## New

- **Content commitments.** Pass `content` to `isWithin`, `isOutside`, or `contains`, and the device signs a commitment to your content (a note, a photo, a video, a document) into the proof. The proof lists the items as `contentCommitments`. The SDK salts each item by default. Caller content must be enabled for your license. See [Content Commitments](/docs/mobile/concepts/content-commitments/).
- **Hash large files first.** `Octet.hashContent` hashes a file of any size before the proof call. Pass the result as a `digest` item.
- **Upload content to your storage.** If enabled for your license, the SDK uploads items you mark with `upload` to your own storage after the proof is made, never to Octet. Register `Octet.setContentUploadProvider`. See [Uploading content](/docs/mobile/concepts/content-commitments/#uploading-content-to-your-storage).
- **Check content on the device.** `VerifyOptions.callerMetadata` checks a commitment against the content, and `requireCallerMetadata` fails a proof that commits none. See [`Octet.verify`](/docs/mobile/api-reference/octet-verify/#caller-metadata).
- **Proofs bind the region they answer for (semantic binding v3).** A proof can't be presented as the answer to a different region.
- **`BootstrapReason.appPendingContested`.** `Octet.start` fails with it when another license claims the same app and your pending registration lost that claim. Register the app again, or contact Octet support.
- **Check your session nonce offline.** Pass the `sessionNonce` you asked with as `VerifyOptions.expectedSessionNonce`. The `session-binding` check fails a proof made for another nonce, or for none. See [Proof Binding](/docs/mobile/concepts/proof-binding/#session-binding-sessionnonce).
- **Android: set the location notification.** `AdvancedConfig.foregroundNotification` sets the title, text, icon, channel and tap action of the notification Android shows while the SDK collects location, or lets you build the whole notification. See [`AdvancedConfig`](/docs/mobile/api-reference/octet-start/#advancedconfig).
- **React Native.** `@octetproof/react-native` 0.1.0, the wrapper's first release, ships with this release and uses native SDK 3.1.0. `content` on `PredicateOpts`, `Octet.hashContent` and content uploads are in the wrapper. Uploads run in the foreground only. `Octet.verify` stays native-only. See [React Native](/docs/mobile/getting-started/react-native/).

## Changed

- **A license that is withdrawn or expires stops the running session.** Predicates then return `INDETERMINATE` with reason `licenseInactive` / `LICENSE_INACTIVE` and make no proof, and `licenseStatus.state` reads `REVOKED` or `EXPIRED`. The next `Octet.start` throws a `LicenseError`.
- **Positions at sea next to Crimea, Sevastopol and the other occupied Ukrainian regions resolve to Ukraine.** Within 22 km of their coast, the country is `UA` and the region is that Ukrainian region.
- **Android dependencies:** `androidx.work:work-runtime-ktx` 2.12.0 and `bcprov-jdk18on` 1.86. `minSdk` stays 30.

## Fixed

- **The first proof after `Octet.start` waits for a usable fix.** Since 3.0 a proof asked for during startup waits for the SDK to start. Once it had started, a fresh proof used to return `noFix` / `NO_FIX` straight away while positioning warmed up. It now waits up to 30 seconds for a usable fix, so allow for this if your app times out its first call.

- **Country proofs work with approximate location.** When the user allows only approximate location (Precise Location off on iOS, Approximate on Android), country proofs now work. Finer levels return `INSUFFICIENT_PRECISION`, and a proof from approximate location is never `VERIFIED`.
- **Proof uploads ride out a busy server.** When your proof upload endpoint answers `503` or `429`, the SDK waits as `Retry-After` asks and keeps retrying, instead of dropping the proof after three quick retries.
- **Proofs you ask for after a pause are uploaded again.** The SDK fetches a fresh upload challenge first when the prepared one has expired.
- **iOS: the privacy manifest declares coarse location for Analytics**, as well as for App Functionality. Check your App Store privacy label. See [Data collection](/docs/mobile/concepts/data-collection/#ios-privacy-manifest).
- **iOS: `Octet.start` throws a `LicenseError` on a device without App Attest**, `.bootstrapFailed(reason: .attestationInvalid)`, instead of the system error. See [`LicenseError`](/docs/mobile/api-reference/license-types/#licenseerror).
- **Android: location keeps running while your app is off screen.** Collection could fail to start its foreground service after `Octet.start`, and then stopped when your app left the screen. It now starts reliably, and the SDK restores it each time your app comes on screen.
- **License problems you can fix are written to the device log**, so you can see why a start fails.
- **`OctetConfig.advanced.logLevel` takes effect.** See [`AdvancedConfig`](/docs/mobile/api-reference/octet-start/#advancedconfig).
