Skip to content

Commit 07168a2

Browse files
feat: implement session cookie persistence and restoration on iOS
1 parent 37f4104 commit 07168a2

File tree

4 files changed

+97
-12
lines changed

4 files changed

+97
-12
lines changed

example/ios/MendixNativeExample/AppDelegate.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class AppDelegate: RCTAppDelegate {
1515
super.application(application, didFinishLaunchingWithOptions: launchOptions)
1616

1717
//Start - For MendixApplication compatibility only, not part of React Native template
18+
NativeCookieModule.restoreSessionCookies()
1819
MxConfiguration.update(from:
1920
MendixApp.init(
2021
identifier: nil,
@@ -32,6 +33,14 @@ class AppDelegate: RCTAppDelegate {
3233
return true
3334
}
3435

36+
override func applicationDidEnterBackground(_ application: UIApplication) {
37+
NativeCookieModule.persistSessionCookies()
38+
}
39+
40+
override func applicationWillTerminate(_ application: UIApplication) {
41+
NativeCookieModule.persistSessionCookies()
42+
}
43+
3544
override func sourceURL(for bridge: RCTBridge) -> URL? {
3645
self.bundleURL()
3746
}

example/ios/Podfile.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ PODS:
88
- hermes-engine (0.78.2):
99
- hermes-engine/Pre-built (= 0.78.2)
1010
- hermes-engine/Pre-built (0.78.2)
11-
- MendixNative (0.1.3):
11+
- MendixNative (0.3.0):
1212
- DoubleConversion
1313
- glog
1414
- hermes-engine
@@ -1851,7 +1851,7 @@ SPEC CHECKSUMS:
18511851
fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd
18521852
glog: eb93e2f488219332457c3c4eafd2738ddc7e80b8
18531853
hermes-engine: 2771b98fb813fdc6f92edd7c9c0035ecabf9fee7
1854-
MendixNative: 36190d86a65cb57b351c6396bc1349a7823206b0
1854+
MendixNative: a55e00448d33a66d59bd4b5c5d3057123d34337c
18551855
op-sqlite: 12554de3e1a0cb86cbad3cf1f0c50450f57d3855
18561856
OpenSSL-Universal: 6082b0bf950e5636fe0d78def171184e2b3899c2
18571857
RCT-Folly: e78785aa9ba2ed998ea4151e314036f6c49e6d82

ios/Modules/AppPreferences/AppPreferences.swift

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,29 @@ public class AppPreferences: NSObject {
1717
private static var _packagerPort: Int
1818

1919
public static var remoteDebuggingPackagerPort: Int {
20-
get {
21-
return AppUrl.ensurePort(_packagerPort)
22-
}
23-
set {
24-
_packagerPort = newValue
25-
}
20+
get { AppUrl.ensurePort(_packagerPort) }
21+
set { _packagerPort = newValue }
2622
}
2723

28-
public static var appUrl = _appUrl
29-
public static var devModeEnabled = _devModeEnabled
30-
public static var remoteDebuggingEnabled = _remoteDebuggingEnabled
31-
public static var elementInspectorEnabled = _elementInspectorEnabled
24+
public static var appUrl: String? {
25+
get { _appUrl }
26+
set { _appUrl = newValue }
27+
}
28+
29+
public static var devModeEnabled: Bool {
30+
get { _devModeEnabled }
31+
set { _devModeEnabled = newValue }
32+
}
33+
34+
public static var remoteDebuggingEnabled: Bool {
35+
get { _remoteDebuggingEnabled }
36+
set { _remoteDebuggingEnabled = newValue }
37+
}
38+
39+
public static var elementInspectorEnabled: Bool {
40+
get { _elementInspectorEnabled }
41+
set { _elementInspectorEnabled = newValue }
42+
}
3243

3344
public static var safeAppUrl: String {
3445
return appUrl ?? ""

ios/Modules/NativeCookieModule/NativeCookieModule.swift

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,70 @@ public class NativeCookieModule: NSObject {
1212
for cookie in (storage.cookies ?? []) {
1313
storage.deleteCookie(cookie)
1414
}
15+
SessionCookieStore.clear()
16+
}
17+
18+
public static func persistSessionCookies() {
19+
SessionCookieStore.persist()
20+
}
21+
22+
public static func restoreSessionCookies() {
23+
SessionCookieStore.restore()
24+
}
25+
26+
final class SessionCookieStore {
27+
28+
private static let bundleIdentifier = Bundle.main.bundleIdentifier ?? "com.mendix.app"
29+
private static let storageKey = bundleIdentifier + "sessionCookies"
30+
private static let queue = DispatchQueue(label: bundleIdentifier + ".session-cookie-store", qos: .utility)
31+
32+
// MARK: - Public API
33+
public static func restore() {
34+
35+
guard
36+
let data = UserDefaults.standard.data(forKey: storageKey),
37+
let cookies = try? NSKeyedUnarchiver.unarchivedObject(ofClasses: [NSArray.self, HTTPCookie.self], from: data) as? [HTTPCookie]
38+
else {
39+
NSLog("SessionCookieStore: No cookies to restore")
40+
return
41+
}
42+
43+
let storage = HTTPCookieStorage.shared
44+
let existing = Set(storage.cookies ?? [])
45+
46+
cookies.filter { !existing.contains($0) }.forEach { storage.setCookie($0) }
47+
48+
// Clear stored cookies after restoration to avoid any side effects
49+
clear()
50+
}
51+
52+
public static func persist() {
53+
queue.async {
54+
55+
let cookies = HTTPCookieStorage.shared.cookies ?? []
56+
let sessionCookies = cookies.filter { isSessionCookie($0) }
57+
58+
guard !sessionCookies.isEmpty else {
59+
clear()
60+
NSLog("SessionCookieStore: Clear existing session cookies from storage")
61+
return
62+
}
63+
64+
do {
65+
let data = try NSKeyedArchiver.archivedData(withRootObject: sessionCookies, requiringSecureCoding: false)
66+
UserDefaults.standard.set(data, forKey: storageKey)
67+
} catch {
68+
NSLog("SessionCookieStore: Failed to persist session cookies: \(error.localizedDescription)")
69+
}
70+
}
71+
}
72+
73+
public static func clear() {
74+
UserDefaults.standard.removeObject(forKey: storageKey)
75+
}
76+
77+
public static func isSessionCookie(_ cookie: HTTPCookie) -> Bool {
78+
return cookie.expiresDate == nil
79+
}
1580
}
1681
}

0 commit comments

Comments
 (0)