Skip to Content
macOS (Swift)Migrating from Electron or Tauri

Migrating from Electron or Tauri

Rewriting your Mac app in Swift doesn’t cost your customers their activation. The macOS SDK reads what the Electron SDK and the Tauri SDK stored, and computes the same fingerprint:

  • the key is found: the customer isn’t asked for it again,
  • the fingerprint is the same: the Mac stays the same machine of the license, and doesn’t take a new place,
  • the stored token still works: the app is .active offline right away.

Keep the same product: same product id, same public key.

Keep the same Keychain service

The Keychain items are found under the service they were written with:

Previous SDKService
Electron SDK 1.2 and laterThe app’s bundle id, or the keychainService option you passed
Electron SDK 1.1, Tauri SDKdev.licensemanager.sdk

The Swift SDK uses your app’s bundle id by default. When it’s the same as before, there’s nothing to do. Otherwise, pass the previous service:

LicenseManager.Options(keychainService: "dev.licensemanager.sdk") // moving from Tauri

When a value is only found in the files, the SDK copies it to its Keychain service: once moved, the previous service is no longer needed.

Keep the same fingerprint

If you passed a fingerprint option to the Electron or Tauri SDK, pass the same value to the Swift SDK. Otherwise, don’t pass any: the default machine id is the same IOPlatformUUID.

Keep the same version numbers

Keep numbering your versions from where the previous app was: releases and the token’s mv compare them. A Swift rewrite that restarts at 1.0 would slip under every version lock of your licenses.

What the customer sees

The first launch of the Swift build reads the Keychain items written by the previous build. They’re owned by the previous app’s code signature, so macOS asks the customer, once, to allow your new app to read them:

“Acme Photo wants to use your confidential information stored in “com.acme.photo” in your keychain.”

When the customer clicks Always Allow, it never shows again. When they deny it, the SDK reads the same values from the files, and stays activated: only for apps that aren’t sandboxed, since a sandboxed app can’t read files outside its container.

The prompt can’t be avoided: the previous SDKs created the items with the Keychain’s default access list, which only trusts the app that created them. Mention it in your release notes, so customers know it’s expected.

Mapping of the APIs

ElectronTauri (JS)Swift
new LicenseManager({ productId, publicKey })Builder::new(id, key)try LicenseManager(productID:publicKey:options:)
getState()getState()state
await ready()await ready()await ready()
onStateChange(fn)watchLicense(fn)LicenseObserver, states, onStateChange(_:)
await setLicenseKey(key)await setLicenseKey(key)try await setLicenseKey(_:)
await refresh()await refresh()await refresh()
getOfflineState()getOfflineState()offlineState
getLatestAllowedVersion()getLatestAllowedVersion()latestAllowedVersion
getPortalUrl()getPortalUrl()portalURL, openPortal()
getLicenseKey()getLicenseKey()licenseKey, licenseKeyHint
await getFingerprint()getFingerprint()await fingerprint()
isClockTampered()isClockTampered()isClockTampered
"ACTIVE", "not_found"…the same.active, .notFound… with the same rawValue
minOfflineDurationMsmin_offline_durationminOfflineDuration (seconds)

Edge cases

The previous app’s data was deleted, like by a cleaner app. The customer activates again, and the Mac is a new machine.

Sandboxed Swift app, prompt denied. The files of the previous app are outside the container: the customer activates again. Their Mac keeps its fingerprint only if the install id could be read.

Customers still on the previous app. Both builds can run on the same Mac, and share the same data: activating one activates the other.