Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 50 additions & 60 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,97 +6,87 @@

# 🔔 UpgradeAlert

> Easily update your app
> Easy update notifications.

## Table of Contents
- [Problem](#problem)
- [Solution](#solution)
- [Screenshots](#screenshots)
- [Example](#example)
- [FAQ](#faq)
- [Gotchas](#gotchas)
- [Screenshots](#screenshots)
- [Why?](#why)
- [How](#how)
- [Todo](#todo)
- [License](#license)

### Problem:
- 🖥 macOS app does not auto update by default, unless user has set this specifically in app-store.
- 📲 iOS auto update by default, but a few might have turned it off.
- 🕸 Users might be stuck on old OS. that we no longer support. In that case we need to "soft-brick" the app
- 🪦 Supporting 6+ month old app versions in your backend
- 🥶 Supporting multiple versions of your app you will result in bloated app code that is hard to iterate on
- 🤬 Users will stop complaining about issues that are already fixed in the last update
- 🥵 Users will stop giving bad reviews because of errors with old software
- 🔥 Avoid crashes by staying compatible with the latest device API changes and platform updates
- 🚨 Getting urgent security updates out to as many users as possible as quickly as possible

### Solution:
- When the current app version is outdated. The user is prompted with a link to AppStore where the user can update
- Two different alerts can be prompted. One where there is an option to update later and one where the user required to update
- You can customize alert title, message and button text

> **Warning**
> Setting `isRequired = true` bricks the app until it's updated

### Screenshots:

**For iOS:**

<img width="405" alt="ios" src="iOS.png">

**For macOS:**

<img width="480" alt="ios" src="macOS.png">

### Example:
```swift
import UpgradeAlert

guard Bundle.isBeta else { Swift.print("App is beta or simulator, skip checking for update"); return }
UpgradeAlert.config = UAConfig( // Config the alert
guard Bundle.isBeta else { print("App is beta or simulator, skip checking for update"); return }

UpgradeAlert.config = UAConfig( // Configure the alert
isRequired: false, // Require users to update
alertTitle: "Update required", // alert title
alertMessage: { version in "Version: \(version) is out!" }, // alert msg
laterButtonTitle: "Later", // skip button title
updateButtonTitle: "Update Now" // go to appstore btn
alertTitle: "👋 A new version of (your app)'s on the App Store!", // alert title
alertMessage: { version, appName in
"Please update now, so you can get the latest bug fixes and features."
}, // Alert message
laterButtonTitle: "Later", // Skip update button title
updateButtonTitle: "Update Now" // Go to App Store
)
UpgradeAlert.checkForUpdates { outcome in // check apple endpoint if there is a new update
if case .err(let err) = outcome {
Swift.print("Err: \(err.localizedDescription)")
} else { // opportunity to track user action here with GA etc
swift.print("Outcome: \(String(describing: outcome))") // notNow, notNeeded, appStoreOpened

UpgradeAlert.checkForUpdates { outcome in // Check Apple endpoint for updates
if case .error(let err) = outcome {
print("Err: \(err.localizedDescription)")
} else { // Opportunity to track user action here with GA etc
print("Outcome: \(String(describing: outcome))") // notNow, notNeeded, appStoreOpened
}
}
```
**For debugging**

```swift
// UA prompt alert test. so we can see how it looks etc.
// Show a test alert, to make sure everything looks good.
UpgradeAlert.showAlert(appInfo: .init(version: "1.0.1", trackViewUrl: "https://apps.apple.com/app/id/com.MyCompany.MyApp"))
```

### FAQ:
**Q:** What is an Upgrade-Wall?
**A:** Upgrade-Wall or Update-Wall is a system/service that prevents mobile app users from using the app who are still using the older versions of the app.
> **Warnings**
> Setting `isRequired = true` bricks the app until it's updated
> For macOS `applicationDidBecomeActive` will be called after dismissing the UpgradeAlert, make sure you init UpgradeAlert from another method or else it will create an inescapable loop. This does not apply for iOS.

### Screenshots:

**iOS:**

**Q:** Why do we need Upgrade-Wall?
**A:** A required upgrade may be required when there are breaking changes in the backend API which will result in an app crash or when there are security issues in older apps and a new version of the app is released and you may want to require users to update to the newly released version. Also in cases where you want to encourage users to update your app to the newly released versions because you have launched a new cool feature and want users to explore and use it. In these scenarios, Upgrade-Wall is necessary to have in place.
<img width="405" alt="ios" src="iOS.png">

**macOS:**

<img width="480" alt="ios" src="macOS.png">

**Q:** How to Implement Upgrade-Wall?
**A:** Upgrade-Wall can be implemented with two strategies, hard and soft Upgrade-Walls. A Hard Upgrade-Wall completely restricts the users from using the app and requires them to update the app. A Soft Upgrade-Wall offers greater flexibility to users, generally giving users the freedom to either update the app or skip the update to a later time. Both the strategies can be implemented by showing a popup/alert to users. When the user opens the app, Hard Upgrade-Wall will show a non-dismissible popup with only an update button. Users cannot skip the popup and will have only one option to update the app. On pressing the update button the app should open the play store or AppStore of the app from where the user can update the app to the latest version. Soft Upgrade-Wall will show a dismissible popup to the user with options to either update the app or skip. Users can skip and continue using the app. An example of Hard Upgrade-Wall and Soft Upgrade-Wall. You can skip the pain of building an Upgrade-Wall yourself and use solutions which are already there.
### Why?
- 🖥 macOS doesn't auto-update apps by default.
- 📲 iOS auto-updates apps by default, but a users might have turn auto-updates off.
- 🕸 Users might be on older OSes no longer supported by your app, in which case you'd need to "soft-brick" the app.
- 🪦 No more supporting 6+ month old app versions in your backend
- 🥶 Supporting multiple versions of your app results in bloated app code that is hard to iterate on
- 🤬 Users will stop complaining about issues that have already been fixed in the last update
- 🥵 Users will stop giving bad reviews because of errors with old software
- 🔥 Avoid crashes by staying compatible with the latest device API changes and platform updates
- 🚨 Getting urgent security updates out to as many users as possible as quickly as possible

### Gotchas:
- For macOS `applicationDidBecomeActive` will be called after dismissing the UpgradeAlert, make sure you init UpgradeAlert from another method or else it will create an inescapable loop. This does not apply for iOS.
### How:
- UpgradeAlert checks the App Store for updates, and shows an alert when one's available (as seen below).
- You can pick between an alert that notifies users of updates and allows dismissal, and an alert that requires the user to update, and "soft-bricks" the app until it's updated.
- Alert titles, messages, and button labels are completely customizable.

### Todo:
- Add screenshot from a test app? ✅
- Add support for testflight. There is a repo in issues with a link to another repo that recently added support for this
### TODO:
- Add screenshot from a test app? ✅
- Add support for SwiftUI ✅
- Add support for TestFlight (There's a repo in Issues with a link to another repo that recently added support for this).
- Add country-code to json. en -> english etc. (later)
- Add localization support
- Add support for: SKStoreProductViewController allowing the update to be initiated in-app. see https://github.com/rwbutler/Updates/ for code
- Maybe add 1 day delay to showing update alert: to avoid an issue where Apple updates the JSON faster than the app binary propogates to the App Store. https://github.com/amebalabs/AppVersion/blob/master/AppVersion/Source/%20Extensions/Date%2BAppVersion.swift
- Doc params
- Clean up comments
- Add support for swiftui

## License
This project is licensed under the terms of the MIT license. See the [LICENSE](LICENSE) file.