Skip to content

Commit 64ff934

Browse files
committed
Update README.md
1 parent 9696203 commit 64ff934

File tree

1 file changed

+119
-30
lines changed

1 file changed

+119
-30
lines changed

README.md

+119-30
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,20 @@
1919
- [License](#license)
2020

2121
### Problem:
22-
- 🖥 macOS app does not auto update by default, unless user has set this specifically in app-store.
23-
- 📲 iOS auto update by default, but a few might have turned it off.
24-
- 🕸 Users might be stuck on old OS. that we no longer support. In that case we need to "soft-brick" the app
25-
- 🪦 Supporting 6+ month old app versions in your backend
22+
- 🖥 macOS apps do not auto-update by default unless the user has enabled this in the App Store settings.
23+
- 📲 While iOS apps auto-update by default, some users may have disabled this feature.
24+
- 🕸 Users may be stuck on an old OS version that is no longer supported.
25+
- 🪦 Supporting outdated app versions can burden your backend and complicate code maintenance.
2626
- 🥶 Supporting multiple versions of your app you will result in bloated app code that is hard to iterate on
27-
- 🤬 Users will stop complaining about issues that are already fixed in the last update
28-
- 🥵 Users will stop giving bad reviews because of errors with old software
29-
- 🔥 Avoid crashes by staying compatible with the latest device API changes and platform updates
30-
- 🚨 Getting urgent security updates out to as many users as possible as quickly as possible
27+
- 🤬 Users may complain about issues already fixed in newer versions.
28+
- 🥵 Outdated apps may lead to negative reviews due to bugs that have been resolved.
29+
- 🔥 Avoid crashes by ensuring compatibility with the latest device APIs and platform updates.
30+
- 🚨 Deliver urgent security updates to users promptly.
3131

3232
### Solution:
33-
- When the current app version is outdated. The user is prompted with a link to AppStore where the user can update
34-
- Two different alerts can be prompted. One where there is an option to update later and one where the user required to update
35-
- You can customize alert title, message and button text
33+
- When the current app version is outdated, the user is prompted with a link to the App Store to update.
34+
- Two different alerts can be displayed: one where the user has the option to update later, and one where the update is mandatory.
35+
- You can customize the alert title, message, and button texts.
3636

3737
> **Warning**
3838
> Setting `isRequired = true` bricks the app until it's updated
@@ -51,20 +51,33 @@
5151
```swift
5252
import UpgradeAlert
5353

54-
guard Bundle.isBeta else { Swift.print("App is beta or simulator, skip checking for update"); return }
55-
UpgradeAlert.config = UAConfig( // Config the alert
56-
isRequired: false, // Require users to update
57-
alertTitle: "Update required", // alert title
58-
alertMessage: { version in "Version: \(version) is out!" }, // alert msg
59-
laterButtonTitle: "Later", // skip button title
60-
updateButtonTitle: "Update Now" // go to appstore btn
54+
// Skip checking for updates if the app is running in beta (e.g., simulator or TestFlight)
55+
guard !Bundle.isBeta else {
56+
Swift.print("App is beta or simulator, skip checking for update")
57+
return
58+
}
59+
60+
// Configure the alert
61+
UpgradeAlert.config = UAConfig(
62+
isRequired: false, // Require users to update
63+
alertTitle: "Update required", // Alert title
64+
alertMessage: { appName, version in "Version \(version) is out!" }, // Alert message
65+
laterButtonTitle: "Later", // Skip button title
66+
updateButtonTitle: "Update Now" // Go to App Store button
6167
)
62-
UpgradeAlert.checkForUpdates { outcome in // check apple endpoint if there is a new update
63-
if case .err(let err) = outcome {
64-
Swift.print("Err: \(err.localizedDescription)")
65-
} else { // opportunity to track user action here with GA etc
66-
swift.print("Outcome: \(String(describing: outcome))") // notNow, notNeeded, appStoreOpened
67-
}
68+
69+
// Check Apple endpoint to see if there is a new update
70+
UpgradeAlert.checkForUpdates { outcome in
71+
switch outcome {
72+
case .error(let error):
73+
Swift.print("Error: \(error.localizedDescription)")
74+
case .notNow:
75+
Swift.print("User chose to update later.")
76+
case .updateNotNeeded:
77+
Swift.print("App is up-to-date.")
78+
case .didOpenAppStoreToUpdate:
79+
Swift.print("Redirected user to App Store for update.")
80+
}
6881
}
6982
```
7083
**For debugging**
@@ -75,14 +88,35 @@ UpgradeAlert.showAlert(appInfo: .init(version: "1.0.1", trackViewUrl: "https://a
7588
```
7689

7790
### FAQ:
91+
7892
**Q:** What is an Upgrade-Wall?
79-
**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.
93+
**A:** An **Upgrade-Wall** (or **Update-Wall**) is a system that prevents mobile app users from using the app if they are still on older versions. It ensures that all users operate on the latest version of the app.
94+
95+
**Q:** Why do we need an Upgrade-Wall?
96+
**A:** An Upgrade-Wall is necessary when you need users to update to a new version due to breaking changes, security issues, or to promote new features. For instance:
97+
98+
- **Breaking Changes:** If there are significant changes in the backend API that would cause older versions of the app to crash.
99+
- **Security Issues:** When older app versions have vulnerabilities that are fixed in newer releases.
100+
- **Feature Promotion:** To encourage users to experience new features you've introduced.
80101

81-
**Q:** Why do we need Upgrade-Wall?
82-
**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.
102+
In these scenarios, an Upgrade-Wall ensures users update to the latest version, providing a consistent and secure experience.
83103

84-
**Q:** How to Implement Upgrade-Wall?
85-
**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.
104+
**Q:** How do you implement an Upgrade-Wall?
105+
**A:** An Upgrade-Wall can be implemented using two strategies: **hard** and **soft** Upgrade-Walls.
106+
107+
- **Hard Upgrade-Wall:** Completely restricts users from using the app until they update.
108+
109+
- Displays a non-dismissible popup with only an **Update** button when the app is opened.
110+
- Users cannot skip this popup and must update to continue.
111+
- Pressing the **Update** button redirects to the App Store or Play Store to download the latest version.
112+
113+
- **Soft Upgrade-Wall:** Offers flexibility, allowing users to choose whether to update immediately or later.
114+
115+
- Shows a dismissible popup with options to **Update** or **Skip**.
116+
- Users can skip the update and continue using the app.
117+
- Encourages but does not force the update.
118+
119+
Both strategies involve showing a popup or alert to users upon opening the app. You can streamline this process by utilizing existing solutions that provide Upgrade-Wall functionality.
86120

87121
### Gotchas:
88122
- 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.
@@ -109,7 +143,7 @@ UpgradeAlert.showAlert(appInfo: .init(version: "1.0.1", trackViewUrl: "https://a
109143
Issue: The current implementation of asynchronous methods uses custom closures with optional parameters for error handling. This can be improved by leveraging Swift's Result type, which provides a clearer and more structured way to handle success and failure cases.
110144
Improvement: Refactor asynchronous methods to use Result instead of optional parameters. This will make the code more readable and maintainable.
111145

112-
```
146+
```swift
113147
public final class UpgradeAlert {
114148
public static func checkForUpdates(completion: @escaping (Result<Void, UAError>) -> Void) {
115149
DispatchQueue.global(qos: .background).async {
@@ -171,3 +205,58 @@ private static func getAppInfo(completion: @escaping (Result<AppInfo, UAError>)
171205
}
172206
```
173207

208+
- Improve NSAlert Presentation
209+
Issue: In NSAlert+Ext.swift, the code can be refactored to reduce duplication and handle more cases.
210+
Improvement: Create a general method to
211+
212+
```swift
213+
extension NSAlert {
214+
internal static func present(
215+
messageText: String,
216+
informativeText: String,
217+
style: NSAlert.Style,
218+
buttons: [String],
219+
completion: ((NSApplication.ModalResponse) -> Void)? = nil
220+
) {
221+
let alert = NSAlert()
222+
alert.messageText = messageText
223+
alert.informativeText = informativeText
224+
alert.alertStyle = style
225+
buttons.forEach { alert.addButton(withTitle: $0) }
226+
if let window = NSApplication.shared.windows.first {
227+
alert.beginSheetModal(for: window, completionHandler: completion)
228+
} else {
229+
print("Error: No window available to present alert.")
230+
}
231+
}
232+
}
233+
```
234+
- Add Support for SwiftUI Alerts
235+
Issue: The current implementation does not support SwiftUI, limiting its use in SwiftUI-based apps.
236+
Improvement: Add methods to present alerts using SwiftUI.
237+
Example Implementation:
238+
239+
```swift
240+
import SwiftUI
241+
242+
@available(iOS 13.0, macOS 10.15, *)
243+
public struct UpgradeAlertView: View {
244+
@State private var isPresented = false
245+
public var body: some View {
246+
Text("") // Placeholder
247+
.alert(isPresented: $isPresented) {
248+
Alert(
249+
title: Text(config.alertTitle),
250+
message: Text(config.alertMessage(nil, appInfo.version)),
251+
primaryButton: .default(Text(config.updateButtonTitle), action: {
252+
// Handle update action
253+
}),
254+
secondaryButton: config.isRequired ? nil : .cancel(Text(config.laterButtonTitle))
255+
)
256+
}
257+
.onAppear {
258+
isPresented = true
259+
}
260+
}
261+
}
262+
```

0 commit comments

Comments
 (0)