Adds time-based trial and easy license verification using CocoaFob to your macOS app.
For setup instructions of your own store and app preparation with FastSpring, have a look at my book Make Money Outside the Mac App Store!
dependencies: [
.package(url: "https://github.com/CleanCocoa/TrialLicensing.git", .upToNextMajor(from: Version(3, 0, 0))),
]
Add package depencency via Xcode by using this URL: https://github.com/CleanCocoa/TrialLicensing.git
CocoaFob is automatically linked statically for you, no need to do anything.
- Include the
Trial
andTrialLicense
libraries in your project. - Include the CocoaFob (Swift 5) library in your project, too. (You have to link this in the app because a library cannot embed another library.)
- Create an
AppLicensing
instance withlicenseChangeBlock
andinvalidLicenseInformationBlock
handling change events. - Set up and start the trial.
Example:
import TrialLicense
let publicKey = [
"-----BEGIN DSA PUBLIC KEY-----\n",
// ...
"-----END DSA PUBLIC KEY-----\n"
].join("")
let configuration = LicenseConfiguration(appName: "AmazingApp!", publicKey: publicKey)
class MyApp: AppLicensingDelegate {
init() {
AppLicensing.setUp(
configuration: configuration,
initialTrialDuration: Days(30),
// Set up the callbacks:
licenseChangeBlock: self.licenseDidChange(licenseInfo:),
invalidLicenseInformationBlock: self.didEnterInvalidLicenseCode(name:licenseCode:),
// Get notified about initial state to unlock the app immediately:
fireInitialState: true)
}
func licenseDidChange(licenseInformation: LicenseInformation) {
switch licenseInformation {
case .onTrial(_):
// Changing back to trial may be possible if you support unregistering
// form the app (and the trial period is still good.)
return
case .registered(_):
// For example:
// displayThankYouAlert()
// unlockApp()
case .trialUp:
// For example:
// displayTrialUpAlert()
// lockApp()
// showRegisterApp()
}
}
func didEnterInvalidLicenseCode(name: String, licenseCode: String) {
// For example:
// displayInvalidLicenseAlert()
// -- or show an error label in the license window.
}
}
let myApp = MyApp()
The package declares usage of UserDefaults
API because it ships with these mechanisms to read/write information in principle. That's it.
If you use this to store actual customer names and/or email addresses in your app, depending on the licensing scheme you use, you should check that your app has a NSPrivacyCollectedDataTypes
entry with e.g. a value of NSPrivacyCollectedDataTypeEmailAddress
.
LicenseInformation
reveals the state your app is in:
enum LicenseInformation {
case registered(License)
case onTrial(TrialPeriod)
case trialUp
}
The associated types provide additional information, for example to display details in a settings window or show remaining trial days in the title bar of your app.
License
represents a valid name--license code pair:
struct License {
let name: String
let licenseCode: String
}
TrialPeriod
encapsulates the duration of the trial.
struct TrialPeriod {
let startDate: Date
let endDate: Date
}
TrialPeriod
also provides these convenience methods:
ended() -> Bool
daysLeft() -> Days
... where Days
encapsulates the remainder for easy conversion to TimeInterval
and exposing userFacingAmount: Int
for display.
Copyright (c) 2016 by Christian Tietze. Distributed under the MIT License. See the LICENSE file for details.