Skip to content

Commit 2e1b8e8

Browse files
committed
Merge branch 'develop'
2 parents 55b4ef5 + 127f762 commit 2e1b8e8

27 files changed

+474
-155
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## 2.12.4 - 2024-09-17
6+
7+
[NEW] Option to show/hide Account ID
8+
[IMPROVED] Error handling for in-app purchases
9+
[FIXED] Location marker disappearing when the app wakes up from the background (iOS 18)
10+
[FIXED] Privacy overlay not working (iOS 18)
11+
[FIXED] Widget actions to Connect/Disconnect not working (iOS 18)
12+
[FIXED] Actions not appearing in the Shortcuts app (iOS 18)
13+
514
## 2.12.3 - 2024-06-04
615

716
[IMPROVED] Post-Quantum library updated to the latest version

IVPNClient.xcodeproj/project.pbxproj

Lines changed: 40 additions & 22 deletions
Large diffs are not rendered by default.

IVPNClient/AppDelegate.swift

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -96,16 +96,9 @@ class AppDelegate: UIResponder {
9696

9797
private func showSecurityScreen() {
9898
var showWindow = false
99+
let topVC = UIApplication.topViewController()
99100

100-
if UIApplication.topViewController() as? AccountViewController != nil {
101-
showWindow = true
102-
}
103-
104-
if UIApplication.topViewController() as? LoginViewController != nil {
105-
showWindow = true
106-
}
107-
108-
if UIApplication.topViewController() as? CreateAccountViewController != nil {
101+
if topVC is AccountViewController || topVC is LoginViewController || topVC is CreateAccountViewController {
109102
showWindow = true
110103
}
111104

@@ -439,3 +432,12 @@ extension AppDelegate: PurchaseManagerDelegate {
439432
}
440433

441434
}
435+
436+
enum UserActivityType {
437+
static let Connect = "net.ivpn.clients.ios.Connect"
438+
static let Disconnect = "net.ivpn.clients.ios.Disconnect"
439+
static let AntiTrackerEnable = "net.ivpn.clients.ios.AntiTracker.enable"
440+
static let AntiTrackerDisable = "net.ivpn.clients.ios.AntiTracker.disable"
441+
static let CustomDNSEnable = "net.ivpn.clients.ios.CustomDNS.enable"
442+
static let CustomDNSDisable = "net.ivpn.clients.ios.CustomDNS.disable"
443+
}

IVPNClient/Enums/UserActivityTitle.swift

Lines changed: 0 additions & 33 deletions
This file was deleted.

IVPNClient/Enums/UserActivityType.swift

Lines changed: 0 additions & 33 deletions
This file was deleted.

IVPNClient/Managers/ConnectionManager.swift

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,6 @@ class ConnectionManager {
9696
self.updateOpenVPNLogFile()
9797
self.updateWireGuardLogFile()
9898
self.reconnectAutomatically = false
99-
if self.actionType == .connect {
100-
self.evaluateCloseApp()
101-
}
10299
}
103100
DispatchQueue.delay(2.5) {
104101
if UserDefaults.shared.isV2ray && !V2RayCore.shared.reconnectWithV2ray {
@@ -128,10 +125,6 @@ class ConnectionManager {
128125
}
129126
}
130127
}
131-
132-
if status == .disconnected && self.actionType == .disconnect {
133-
self.evaluateCloseApp()
134-
}
135128

136129
completion(status)
137130
}
@@ -575,12 +568,10 @@ class ConnectionManager {
575568
}
576569
}
577570

578-
private func evaluateCloseApp() {
571+
func evaluateCloseApp() {
579572
if closeApp {
580573
closeApp = false
581-
DispatchQueue.delay(1.5) {
582-
UIControl().sendAction(#selector(NSXPCConnection.suspend), to: UIApplication.shared, for: nil)
583-
}
574+
UIControl().sendAction(#selector(NSXPCConnection.suspend), to: UIApplication.shared, for: nil)
584575
}
585576
}
586577

IVPNClient/Managers/PurchaseManager.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,11 @@ class PurchaseManager: NSObject {
8686
log(.info, message: "[Store] Completing successful in-app purchase \(productId)")
8787
self.complete(transaction)
8888
break
89-
case .success(.unverified(_, _)):
89+
case .success(.unverified(_, let result)):
9090
// Successful purchase but transaction/receipt can't be verified
9191
// Could be a jailbroken phone
9292
log(.info, message: "[Store] Purchase \(productId): success, unverified")
93-
delegate?.purchaseError(error: ErrorResult(status: 500, message: "Purchase is unverified."))
93+
delegate?.purchaseError(error: ErrorResult(status: 500, message: "Purchase is unverified: \(result.localizedDescription)."))
9494
break
9595
case .pending:
9696
// Transaction waiting on SCA (Strong Customer Authentication) or
@@ -117,6 +117,10 @@ class PurchaseManager: NSObject {
117117
continue
118118
}
119119

120+
guard ProductId.all.contains(transaction.productID) else {
121+
continue
122+
}
123+
120124
if transaction.revocationDate == nil {
121125
log(.info, message: "[Store] Completing unfinished purchase \(transaction.productID)")
122126
complete(transaction)

IVPNClient/Models/AppIntents.swift

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
//
2+
// AddNoteIntent.swift
3+
// IVPN iOS app
4+
// https://github.com/ivpn/ios-app
5+
//
6+
// Created by Juraj Hilje on 2024-09-04.
7+
// Copyright (c) 2024 IVPN Limited.
8+
//
9+
// This file is part of the IVPN iOS app.
10+
//
11+
// The IVPN iOS app is free software: you can redistribute it and/or
12+
// modify it under the terms of the GNU General Public License as published by the Free
13+
// Software Foundation, either version 3 of the License, or (at your option) any later version.
14+
//
15+
// The IVPN iOS app is distributed in the hope that it will be useful,
16+
// but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17+
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
18+
// details.
19+
//
20+
// You should have received a copy of the GNU General Public License
21+
// along with the IVPN iOS app. If not, see <https://www.gnu.org/licenses/>.
22+
//
23+
24+
25+
import AppIntents
26+
27+
@available(iOS 16, *)
28+
struct Connect: AppIntent {
29+
static var title = LocalizedStringResource("Connect VPN")
30+
static var description = IntentDescription("Connect to the VPN")
31+
32+
func perform() async throws -> some IntentResult {
33+
log(.info, message: "App Intent handler: Connect")
34+
NotificationCenter.default.post(name: Notification.Name.IntentConnect, object: nil)
35+
return .result()
36+
}
37+
}
38+
39+
@available(iOS 16, *)
40+
struct Disconnect: AppIntent {
41+
static var title = LocalizedStringResource("Disconnect VPN")
42+
static var description = IntentDescription("Disconnect from the VPN")
43+
44+
func perform() async throws -> some IntentResult {
45+
log(.info, message: "App Intent handler: Disconnect")
46+
NotificationCenter.default.post(name: Notification.Name.IntentDisconnect, object: nil)
47+
return .result()
48+
}
49+
}
50+
51+
@available(iOS 16, *)
52+
struct AntiTrackerEnable: AppIntent {
53+
static var title = LocalizedStringResource("Enable AntiTracker")
54+
static var description = IntentDescription("Enables the AntiTracker")
55+
56+
func perform() async throws -> some IntentResult {
57+
log(.info, message: "App Intent handler: EnableAntiTracker")
58+
NotificationCenter.default.post(name: Notification.Name.IntentAntiTrackerEnable, object: nil)
59+
return .result()
60+
}
61+
}
62+
63+
@available(iOS 16, *)
64+
struct AntiTrackerDisable: AppIntent {
65+
static var title = LocalizedStringResource("Disable AntiTracker")
66+
static var description = IntentDescription("Disables the AntiTracker")
67+
68+
func perform() async throws -> some IntentResult {
69+
log(.info, message: "App Intent handler: DisableAntiTracker")
70+
NotificationCenter.default.post(name: Notification.Name.IntentAntiTrackerDisable, object: nil)
71+
return .result()
72+
}
73+
}
74+
75+
@available(iOS 16, *)
76+
struct CustomDNSEnable: AppIntent {
77+
static var title = LocalizedStringResource("Enable Custom DNS")
78+
static var description = IntentDescription("Enables the Custom DNS")
79+
80+
func perform() async throws -> some IntentResult {
81+
log(.info, message: "App Intent handler: EnableCustomDNS")
82+
NotificationCenter.default.post(name: Notification.Name.IntentCustomDNSEnable, object: nil)
83+
return .result()
84+
}
85+
}
86+
87+
@available(iOS 16, *)
88+
struct CustomDNSDisable: AppIntent {
89+
static var title = LocalizedStringResource("Disable Custom DNS")
90+
static var description = IntentDescription("Disables the Custom DNS")
91+
92+
func perform() async throws -> some IntentResult {
93+
log(.info, message: "App Intent handler: DisableCustomDNS")
94+
NotificationCenter.default.post(name: Notification.Name.IntentCustomDNSDisable, object: nil)
95+
return .result()
96+
}
97+
}

IVPNClient/PrivacyInfo.xcprivacy

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>NSPrivacyAccessedAPITypes</key>
6+
<array>
7+
<dict>
8+
<key>NSPrivacyAccessedAPIType</key>
9+
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
10+
<key>NSPrivacyAccessedAPITypeReasons</key>
11+
<array>
12+
<string>C617.1</string>
13+
</array>
14+
</dict>
15+
<dict>
16+
<key>NSPrivacyAccessedAPIType</key>
17+
<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
18+
<key>NSPrivacyAccessedAPITypeReasons</key>
19+
<array>
20+
<string>35F9.1</string>
21+
</array>
22+
</dict>
23+
<dict>
24+
<key>NSPrivacyAccessedAPIType</key>
25+
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
26+
<key>NSPrivacyAccessedAPITypeReasons</key>
27+
<array>
28+
<string>CA92.1</string>
29+
<string>1C8F.1</string>
30+
</array>
31+
</dict>
32+
</array>
33+
</dict>
34+
</plist>

IVPNClient/Scenes/AccountScreen/AccountViewController.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,18 @@ class AccountViewController: UITableViewController {
7777
}
7878
}
7979

80+
@IBAction func toggleAccountHidden(_ sender: Any) {
81+
let hidden = accountView.isAccountHidden
82+
accountView.toggleAccountVisibility(hide: !hidden)
83+
accountView.isAccountHidden = !hidden
84+
}
85+
8086
// MARK: - View Lifecycle -
8187

8288
override func viewDidLoad() {
8389
super.viewDidLoad()
8490
tableView.backgroundColor = UIColor.init(named: Theme.ivpnBackgroundQuaternary)
91+
NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
8592
initNavigationBar()
8693
addObservers()
8794
accountView.setupView(viewModel: viewModel)
@@ -93,6 +100,10 @@ class AccountViewController: UITableViewController {
93100
sessionManager.getSessionStatus()
94101
}
95102

103+
@objc func willEnterForeground(notification: NSNotification) {
104+
accountView.setupView(viewModel: viewModel)
105+
}
106+
96107
// MARK: - Observers -
97108

98109
func addObservers() {

0 commit comments

Comments
 (0)