Skip to content
Merged
Show file tree
Hide file tree
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
3 changes: 2 additions & 1 deletion KiaExtension/CarListHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import Foundation
import Intents
import UIKit
import os.log

class CarListHandler: NSObject, INListCarsIntentHandling, Handler {
private let api: Api
Expand Down Expand Up @@ -86,7 +87,7 @@ extension Vehicle {

// Get Bluetooth and iAP2 identifiers for this vehicle
let headUnitIds = headUnitIdentifiers()
print("CarListHandler: Vehicle '\(nickname)' - Bluetooth: \(headUnitIds.bluetooth ?? "none"), iAP2: \(headUnitIds.iap2 ?? "none")")
os_log(.debug, log: Logger.extension, "CarListHandler: Vehicle '%{public}@' - Bluetooth: %{public}@, iAP2: %{public}@", nickname, headUnitIds.bluetooth ?? "none", headUnitIds.iap2 ?? "none")

let car: INCar = .init(
carIdentifier: vehicleId.uuidString,
Expand Down
11 changes: 6 additions & 5 deletions KiaExtension/CredentialsHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//

import Foundation
import os.log

class CredentialsHandler {
private let api: Api
Expand Down Expand Up @@ -37,7 +38,7 @@ class CredentialsHandler {
}

do {
print("CredentialsHandler: Using credentials from local server for reauthorization")
os_log(.info, log: Logger.extension, "CredentialsHandler: Using credentials from local server for reauthorization")
let authorization = try await api.login(
username: credentials.username,
password: credentials.password
Expand All @@ -55,7 +56,7 @@ class CredentialsHandler {
}

private func updateCredentials() async {
print("CredentialsHandler: Updating credentials")
os_log(.info, log: Logger.extension, "CredentialsHandler: Updating credentials")

if let credentials = try? await credentialClient.fetchCredentials() {
api.authorization = credentials.authorization
Expand All @@ -67,17 +68,17 @@ class CredentialsHandler {

// Store username and password if available for future use
if let username = credentials.username, let password = credentials.password {
print("CredentialsHandler: Successfully received username and password from local server")
os_log(.info, log: Logger.extension, "CredentialsHandler: Successfully received username and password from local server")
LoginCredentialManager.store(
credentials: LoginCredentials(
username: username,
password: password
)
)
}
print("CredentialsHandler: Successfully updated authorization from local server")
os_log(.info, log: Logger.extension, "CredentialsHandler: Successfully updated authorization from local server")
} else {
print("CredentialsHandler: Failed to fetch credentials from local server")
os_log(.default, log: Logger.extension, "CredentialsHandler: Failed to fetch credentials from local server")
// Fallback to locally stored in keychain
api.authorization = Authorization.authorization
}
Expand Down
19 changes: 10 additions & 9 deletions KiaMaps/App/ApiExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//

import Foundation
import os.log

/// Extension to Api class that handles automatic token refresh and retry logic
extension Api {
Expand All @@ -22,15 +23,15 @@ extension Api {
} catch {
// Check if this is an unauthorized error (401) indicating expired token
if let apiError = error as? ApiError, case .unauthorized = apiError {
print("ApiAutoRefresh: Detected expired token, attempting automatic login retry")
os_log(.info, log: Logger.auth, "Detected expired token, attempting automatic login retry")

// Try to refresh the token using stored credentials
if await refreshTokenIfPossible() {
print("ApiAutoRefresh: Token refreshed successfully, retrying operation")
os_log(.info, log: Logger.auth, "Token refreshed successfully, retrying operation")
// Retry the operation with fresh token
return try await operation()
} else {
print("ApiAutoRefresh: Token refresh failed, throwing original error")
os_log(.error, log: Logger.auth, "Token refresh failed, throwing original error")
// If refresh failed, throw the original unauthorized error
throw error
}
Expand All @@ -46,18 +47,18 @@ extension Api {
private func refreshTokenIfPossible() async -> Bool {
// Check if we have stored login credentials
guard let storedCredentials = LoginCredentialManager.retrieveCredentials() else {
print("ApiAutoRefresh: No stored credentials available for token refresh")
os_log(.default, log: Logger.auth, "No stored credentials available for token refresh")
return false
}

// Check if current token is actually expired before attempting refresh
if let currentAuth = authorization, !isTokenExpired(currentAuth) {
print("ApiAutoRefresh: Current token is not expired, no refresh needed")
os_log(.debug, log: Logger.auth, "Current token is not expired, no refresh needed")
return true
}

do {
print("ApiAutoRefresh: Attempting to login with stored credentials")
os_log(.info, log: Logger.auth, "Attempting to login with stored credentials")
let newAuthData = try await login(
username: storedCredentials.username,
password: storedCredentials.password
Expand All @@ -67,15 +68,15 @@ extension Api {
Authorization.store(data: newAuthData)
self.authorization = newAuthData

print("ApiAutoRefresh: Successfully refreshed token")
os_log(.info, log: Logger.auth, "Successfully refreshed token")
return true

} catch {
print("ApiAutoRefresh: Failed to refresh token with error: \(error)")
os_log(.error, log: Logger.auth, "Failed to refresh token with error: %{public}@", error.localizedDescription)

// If login fails, clear the stored credentials as they might be invalid
if error is ApiError {
print("ApiAutoRefresh: Clearing invalid stored credentials")
os_log(.default, log: Logger.auth, "Clearing invalid stored credentials")
LoginCredentialManager.clearCredentials()
}

Expand Down
37 changes: 19 additions & 18 deletions KiaMaps/App/AppDelegate.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import SwiftUI
import UIKit
import BackgroundTasks
import os.log

class AppDelegate: NSObject, UIApplicationDelegate {
var localClient: LocalCredentialClient! = nil
Expand All @@ -14,7 +15,7 @@ class AppDelegate: NSObject, UIApplicationDelegate {

// Start the local credential server
LocalCredentialServer.shared.start { success in
print("AppDelegate: Server start success: \(success)")
os_log(.info, log: Logger.server, "Server start success: %{public}@", success ? "true" : "false")
}
return true
}
Expand All @@ -23,7 +24,7 @@ class AppDelegate: NSObject, UIApplicationDelegate {
// Stop the local credential server
LocalCredentialServer.shared.stop()
BackgroundTaskManager.shared.cleanup()
print("AppDelegate: Stopped local credential server")
os_log(.info, log: Logger.server, "Stopped local credential server")
}
}

Expand All @@ -42,11 +43,11 @@ class BackgroundTaskManager: ObservableObject {
BGTaskScheduler.shared.register(forTaskWithIdentifier: Self.backgroundTaskIdentifier, using: nil) { task in
self.handleBackgroundServerMaintenance(task: task as! BGAppRefreshTask)
}
print("BackgroundTaskManager: Registered background task: \(Self.backgroundTaskIdentifier)")
os_log(.info, log: Logger.app, "Registered background task: %{public}@", Self.backgroundTaskIdentifier)
}

func handleAppDidEnterBackground() {
print("BackgroundTaskManager: App entered background, maintaining server")
os_log(.info, log: Logger.app, "App entered background, maintaining server")

// Start background task to keep server running
startBackgroundTask()
Expand All @@ -56,7 +57,7 @@ class BackgroundTaskManager: ObservableObject {
}

func handleAppWillEnterForeground() {
print("BackgroundTaskManager: App entering foreground")
os_log(.info, log: Logger.app, "App entering foreground")

// End background task if running
endBackgroundTask()
Expand All @@ -77,27 +78,27 @@ class BackgroundTaskManager: ObservableObject {

do {
try BGTaskScheduler.shared.submit(request)
print("BackgroundTaskManager: Scheduled background refresh task")
os_log(.info, log: Logger.app, "Scheduled background refresh task")
} catch {
print("BackgroundTaskManager: Failed to schedule background refresh: \(error)")
os_log(.error, log: Logger.app, "Failed to schedule background refresh: %{public}@", error.localizedDescription)
}
}

private func handleBackgroundServerMaintenance(task: BGAppRefreshTask) {
print("BackgroundTaskManager: Handling background server maintenance")
os_log(.info, log: Logger.app, "Handling background server maintenance")

// Schedule next refresh
scheduleBackgroundRefresh()

task.expirationHandler = {
print("BackgroundTaskManager: Background task expired")
os_log(.info, log: Logger.app, "Background task expired")
task.setTaskCompleted(success: false)
}

// Check and restart server if needed
DispatchQueue.global(qos: .default).async {
if !LocalCredentialServer.shared.isRunning {
print("BackgroundTaskManager: Restarting server during background refresh")
os_log(.info, log: Logger.app, "Restarting server during background refresh")
LocalCredentialServer.shared.start()

// Wait a moment for server to start
Expand All @@ -113,7 +114,7 @@ class BackgroundTaskManager: ObservableObject {
private func startBackgroundTask() {
backgroundTask = UIApplication.shared.beginBackgroundTask(withName: "LocalServerMaintenance") {
[weak self] in
print("BackgroundTaskManager: Background task expired, ending task")
os_log(.info, log: Logger.app, "Background task expired, ending task")
self?.endBackgroundTask()
}

Expand All @@ -132,21 +133,21 @@ class BackgroundTaskManager: ObservableObject {
}

private func maintainServerInBackground() {
print("BackgroundTaskManager: Maintaining server in background")
os_log(.info, log: Logger.app, "Maintaining server in background")

// Keep the server alive for as long as possible in background
while backgroundTask != .invalid && UIApplication.shared.backgroundTimeRemaining > 5.0 {
// Check server status periodically
if !LocalCredentialServer.shared.isRunning {
print("BackgroundTaskManager: Restarting server in background")
os_log(.info, log: Logger.app, "Restarting server in background")
LocalCredentialServer.shared.start()
}

// Sleep for a short interval
Thread.sleep(forTimeInterval: 1.0)
}

print("BackgroundTaskManager: Background maintenance ending, time remaining: \(UIApplication.shared.backgroundTimeRemaining)")
os_log(.info, log: Logger.app, "Background maintenance ending, time remaining: %{public}f", UIApplication.shared.backgroundTimeRemaining)
}
}

Expand Down Expand Up @@ -179,19 +180,19 @@ struct Application: App {
private func handleScenePhaseChange(_ phase: ScenePhase) {
switch phase {
case .active:
print("Application: Scene became active")
os_log(.debug, log: Logger.app, "Scene became active")
backgroundManager.handleAppWillEnterForeground()

case .inactive:
print("Application: Scene became inactive")
os_log(.debug, log: Logger.app, "Scene became inactive")
// Handle brief inactive state (e.g., incoming call, control center)

case .background:
print("Application: Scene entered background")
os_log(.debug, log: Logger.app, "Scene entered background")
backgroundManager.handleAppDidEnterBackground()

@unknown default:
print("Application: Unknown scene phase: \(phase)")
os_log(.default, log: Logger.app, "Unknown scene phase: %{public}@", String(describing: phase))
}
}
}
3 changes: 2 additions & 1 deletion KiaMaps/App/LoginView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//

import SwiftUI
import os.log

struct LoginView: View {
@State private var username: String = ""
Expand Down Expand Up @@ -291,6 +292,6 @@ struct KiaTextFieldStyle: TextFieldStyle {

#Preview {
LoginView(configuration: AppConfiguration.self) { authData in
print("Login successful with user: \(authData)")
os_log(.info, log: Logger.auth, "Login successful for user")
}
}
3 changes: 2 additions & 1 deletion KiaMaps/App/MainView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//

import SwiftUI
import os.log

struct MainView: View {
let configuration: AppConfiguration.Type
Expand Down Expand Up @@ -293,7 +294,7 @@ struct MainView: View {
await loadData()
if lastUpdateDate < selectedVehicleStatus.lastUpdateTime {
self.lastUpdateDate = nil
print("Updated")
os_log(.debug, log: Logger.ui, "Vehicle status updated")
}
} else {
_ = try await api.refreshVehicleWithAutoRefresh(selectedVehicle.vehicleId)
Expand Down
15 changes: 8 additions & 7 deletions KiaMaps/Core/Api/Api.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//

import Foundation
import os.log

/**
* Api - Main interface for Kia/Hyundai/Genesis vehicle API communication
Expand Down Expand Up @@ -76,15 +77,15 @@ class Api {
let referer: String
do {
referer = try await fetchConnectorAuthorization()
print("Retrieved referer: \(referer)")
os_log(.info, log: Logger.api, "Retrieved referer: %{private}@", referer)
} catch {
print("Client connector authorization failed \(error.localizedDescription)")
os_log(.error, log: Logger.api, "Client connector authorization failed: %{public}@", error.localizedDescription)
throw AuthenticationError.clientConfigurationFailed
}

// Step 1: Get client configuration
let clientConfig = try await fetchClientConfiguration(referer: referer)
print("Client configured for: \(clientConfig.clientName)")
os_log(.info, log: Logger.api, "Client configured for: %{public}@", clientConfig.clientName)

// Step 2: Check if password encryption is enabled
let encryptionSettings = try await fetchPasswordEncryptionSettings(referer: referer)
Expand All @@ -97,7 +98,7 @@ class Api {
do {
rsaKey = try await fetchRSACertificate(referer: referer)
} catch {
print("Fetch RSA Certificate failed \(error.localizedDescription)")
os_log(.error, log: Logger.api, "Fetch RSA Certificate failed: %{public}@", error.localizedDescription)
throw AuthenticationError.certificateRetrievalFailed
}
// Step 4: Initialize OAuth2 flow
Expand All @@ -117,7 +118,7 @@ class Api {
do {
tokenResponse = try await exchangeCodeForTokens(authorizationCode: authorizationCode)
} catch {
print("Exchange code for token failed \(error.localizedDescription)")
os_log(.error, log: Logger.api, "Exchange code for token failed: %{public}@", error.localizedDescription)
throw AuthenticationError.tokenExchangeFailed
}

Expand Down Expand Up @@ -145,9 +146,9 @@ class Api {
func logout() async throws {
do {
try await provider.request(with: .post, endpoint: .logout).empty()
print("Successfully logout")
os_log(.info, log: Logger.auth, "Successfully logout")
} catch {
print("Failed to logout: " + error.localizedDescription)
os_log(.error, log: Logger.auth, "Failed to logout: %{public}@", error.localizedDescription)
}
provider.authorization = nil
cleanCookies()
Expand Down
Loading