Especially useful on macOS and tvOS where Network Extension does not
retain this information when the profile is disabled. On these
platforms, there's no native way to tell the last used profile, so save
it to UserDefaults and fall back to it when tunnel.currentProfile is
nil.
This was not apparent on TestFlight, but features from single iOS and
macOS "Full version" purchases were not being credited on the Apple TV
because of the incomplete `#if` conditionals.
When level is .beta, it was relying on beta receipt exclusively without
falling back to production receipt.
This was preventing the sandbox receipt ("production" in TestFlight)
from being read unless the AppUserLevel was explicitly set to .freemium
(0).
The remote container is shared by ProfileManager and
PreferencesManager, but it must be the same for CloudKit sync
to work properly.
Externalize the logic of onEligibleFeatures() so that the
AppContext singleton can update the managers (and their
repositories) with the new remote store.
Now that the remote profile repository is reloaded every time that
eligible features change, the .removeDuplicates() may also be
restored. Just add a .dropFirst() to skip the initially empty
value of eligible features. Even when features are eventually empty,
a value is always emitted after IAPManager.reloadReceipt()
Lastly, enable Core Data lightweight migration.
Regressions from #1017
Only offer compensations to former purchasers:
- .appleTV to .full purchasers
- .full to .appleTV purchasers
Always suggest .fullTV to new purchasers.
Finally rename:
- .full to .iOS_macOS
- .fullTV to .allFeatures (lifetime)
Even if they haven't changed since the app was last sent to the
background.
Regression from #1019 where the initial .reloadReceipt() call was
wrapped in a Task to make it asynchronous.
Suggest whenever .fullTV is suggested. For this reason, subscriptions
are not suggested to existing full version purchasers, because they only
miss the one-time .appleTV purchase. Group purchases by feature products
and full version products, e.g.:
- Features
- Apple TV
- Full version
- Yearly
- Monthly
- Full
- Full + TV
Additionally, fix reloadReceipt() slowing down onLaunch() sometimes. The
warning sign would appear on restricted profiles until the receipt is
loaded.
- Move non-CI scripts to "scripts"
- Use lowercase variables consistently
- Work with relative paths
- Work with environment
- Parametrize Xcode build/version number (move uniq last)
- Present paywall only on save/connect because PurchaseRequiredButton
instances were presenting paywalls with partial requirements
- Retain PurchaseRequiredButton just to flag paid features visually, but
do nothing on tap
- Suggest paywall products via IAPManager and required features, rather
than from views
- Handle .sharing/.appleTV requirements in ProfileCoordinator, rather
than in StorageSection
- Discontinue platform purchases, but treat as full if iOS + macOS
Before anything, remove any code related to App Group containers from
tvOS target because they are not available. Include the beta receipt
override, it's broken for that reason.
In short:
- Store all Core Data containers locally. Do not use the App Group for
Core Data for consistency across platforms.
- Store logs in the App Group on iOS/macOS, but locally on tvOS (see
`urlForCaches`).
Then, rather than one container per model, merge models into:
- Local: Providers
- Remote: Profiles + Preferences (now in the same CloudKit container)
Reuse the remote model for backups too.
This change is safe because:
- Local profiles are stored via Network Extension in the keychain, not
Core Data
- Remote profiles are re-imported via CloudKit sync
- Providers are re-downloaded on first use
- Preferences are lost, but they are "cheap" data
- Profile backups are lost, but they were hidden anyway
- Simplify badges
- Drop app description, annoying to maintain (refer to the website)
- Drop screenshots (refer to the App Store)
- Update Credits
- Inform about private PassepartoutKit
Fixes#613