Skip to content
This repository was archived by the owner on Mar 7, 2026. It is now read-only.

Commit e2af31a

Browse files
authored
Update DownloadSignManager.swift
1 parent 1503356 commit e2af31a

1 file changed

Lines changed: 80 additions & 103 deletions

File tree

Sources/prostore/signing/DownloadSignManager.swift

Lines changed: 80 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -7,60 +7,37 @@ class DownloadSignManager: ObservableObject {
77
@Published var status: String = ""
88
@Published var isProcessing: Bool = false
99
@Published var showSuccess: Bool = false
10-
10+
1111
private var downloadTask: URLSessionDownloadTask?
1212
private var cancellables = Set<AnyCancellable>()
13-
private var hideTimer: Timer?
14-
13+
1514
func downloadAndSign(app: AltApp) {
1615
guard let downloadURL = app.downloadURL else {
17-
self.showTemporaryError("No download URL available")
16+
self.status = "No download URL available"
1817
return
1918
}
20-
19+
2120
guard let selectedCertFolder = UserDefaults.standard.string(forKey: "selectedCertificateFolder") else {
22-
self.showTemporaryError("Please add and select a certificate first!")
21+
self.status = "No certificate selected"
2322
return
2423
}
25-
24+
2625
self.isProcessing = true
2726
self.progress = 0.0
2827
self.status = "Starting download..."
2928
self.showSuccess = false
30-
29+
3130
DispatchQueue.global(qos: .userInitiated).async {
3231
self.performDownloadAndSign(downloadURL: downloadURL, appName: app.name, certFolder: selectedCertFolder)
3332
}
3433
}
3534

36-
private func showTemporaryError(_ message: String) {
37-
DispatchQueue.main.async {
38-
self.isProcessing = true
39-
self.progress = 0.0
40-
self.status = message
41-
self.showSuccess = false
42-
43-
// Cancel any existing timer
44-
self.hideTimer?.invalidate()
45-
46-
// Hide the bar after 5 seconds
47-
self.hideTimer = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: false) { _ in
48-
DispatchQueue.main.async {
49-
self.isProcessing = false
50-
self.progress = 0.0
51-
self.status = ""
52-
self.showSuccess = false
53-
}
54-
}
55-
}
56-
}
57-
5835
private func performDownloadAndSign(downloadURL: URL, appName: String, certFolder: String) {
5936
// Step 1: Setup directories
6037
let fm = FileManager.default
6138
let appFolder = self.getAppFolder()
6239
let tempDir = appFolder.appendingPathComponent("temp")
63-
40+
6441
do {
6542
if !fm.fileExists(atPath: tempDir.path) {
6643
try fm.createDirectory(at: tempDir, withIntermediateDirectories: true)
@@ -72,13 +49,13 @@ class DownloadSignManager: ObservableObject {
7249
}
7350
return
7451
}
75-
52+
7653
let tempIPAURL = tempDir.appendingPathComponent("\(UUID().uuidString).ipa")
77-
54+
7855
// Step 2: Download the IPA
7956
self.downloadIPA(from: downloadURL, to: tempIPAURL) { [weak self] result in
8057
guard let self = self else { return }
81-
58+
8259
switch result {
8360
case .success:
8461
// Step 3: Get certificate files
@@ -89,38 +66,38 @@ class DownloadSignManager: ObservableObject {
8966
}
9067
return
9168
}
92-
69+
9370
// Step 4: Sign the IPA
9471
self.signIPA(ipaURL: tempIPAURL, p12URL: p12URL, provURL: provURL, password: password, appName: appName)
95-
72+
9673
case .failure(let error):
9774
DispatchQueue.main.async {
9875
self.status = "Download failed: \(error.localizedDescription)"
9976
self.isProcessing = false
10077
}
101-
78+
10279
// Clean up temp file if it exists
10380
try? fm.removeItem(at: tempIPAURL)
10481
}
10582
}
10683
}
107-
84+
10885
private func downloadIPA(from url: URL, to destination: URL, completion: @escaping (Result<Void, Error>) -> Void) {
10986
let semaphore = DispatchSemaphore(value: 0)
110-
87+
11188
let task = URLSession.shared.downloadTask(with: url) { tempURL, response, error in
11289
defer { semaphore.signal() }
113-
90+
11491
if let error = error {
11592
completion(.failure(error))
11693
return
11794
}
118-
95+
11996
guard let tempURL = tempURL else {
12097
completion(.failure(NSError(domain: "Download", code: -1, userInfo: [NSLocalizedDescriptionKey: "No temp URL returned"])))
12198
return
12299
}
123-
100+
124101
do {
125102
let fm = FileManager.default
126103
if fm.fileExists(atPath: destination.path) {
@@ -132,7 +109,7 @@ class DownloadSignManager: ObservableObject {
132109
completion(.failure(error))
133110
}
134111
}
135-
112+
136113
// Observe download progress
137114
var observation: NSKeyValueObservation?
138115
observation = task.progress.observe(\.fractionCompleted) { [weak self] progress, _ in
@@ -143,104 +120,103 @@ class DownloadSignManager: ObservableObject {
143120
self?.status = "Downloading... (\(percent)%)"
144121
}
145122
}
146-
123+
147124
self.downloadTask = task
148125
task.resume()
149-
126+
150127
// Wait for download to complete
151128
DispatchQueue.global(qos: .userInitiated).async {
152129
semaphore.wait()
153130
observation?.invalidate()
154131
}
155132
}
156-
157-
private func getCertificateFiles(for folderName: String) -> (p12URL: URL, provURL: URL, password: String)? {
133+
134+
private func getCertificateFiles(for folderName: String) -> (p12URL: URL, provURL: URL, password: String)? {
158135
let fm = FileManager.default
159136
let certsDir = CertificateFileManager.shared.certificatesDirectory.appendingPathComponent(folderName)
160-
137+
161138
let p12URL = certsDir.appendingPathComponent("certificate.p12")
162139
let provURL = certsDir.appendingPathComponent("profile.mobileprovision")
163140
let passwordURL = certsDir.appendingPathComponent("password.txt")
164-
141+
165142
guard fm.fileExists(atPath: p12URL.path),
166143
fm.fileExists(atPath: provURL.path),
167144
fm.fileExists(atPath: passwordURL.path) else {
168145
return nil
169146
}
170-
147+
171148
do {
172149
let password = try String(contentsOf: passwordURL, encoding: .utf8).trimmingCharacters(in: .whitespacesAndNewlines)
173150
return (p12URL, provURL, password)
174151
} catch {
175152
return nil
176153
}
177154
}
178-
179-
private func signIPA(ipaURL: URL, p12URL: URL, provURL: URL, password: String, appName: String) {
180-
DispatchQueue.main.async {
181-
self.status = "Starting signing process..."
182-
self.progress = 0.5
183-
}
184-
185-
signer.sign(
186-
ipaURL: ipaURL,
187-
p12URL: p12URL,
188-
provURL: provURL,
189-
p12Password: password,
190-
progressUpdate: { [weak self] status, progress in
191-
DispatchQueue.main.async {
192-
let overallProgress = 0.5 + (progress * 0.5)
193-
self?.progress = overallProgress
194-
let percent = Int(overallProgress * 100)
195-
self?.status = "\(status) (\(percent)%)"
196-
}
197-
},
198-
completion: { [weak self] result in
199-
DispatchQueue.main.async {
200-
switch result {
201-
case .success(let signedIPAURL):
202-
self?.progress = 1.0
203-
self?.status = "✅ Successfully signed ipa! Installing app now..."
204-
self?.showSuccess = true
205-
206-
Task {
207-
do {
208-
try await installApp(from: signedIPAURL)
209-
} catch {
210-
self?.status = "❌ Install failed: \(error.localizedDescription)"
211-
}
212-
}
213-
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
214-
self?.isProcessing = false
215-
self?.showSuccess = false
216-
self?.progress = 0.0
217-
self?.status = ""
155+
156+
private func signIPA(ipaURL: URL, p12URL: URL, provURL: URL, password: String, appName: String) {
157+
DispatchQueue.main.async {
158+
self.status = "Starting signing process..."
159+
self.progress = 0.5
160+
}
161+
162+
signer.sign(
163+
ipaURL: ipaURL,
164+
p12URL: p12URL,
165+
provURL: provURL,
166+
p12Password: password,
167+
progressUpdate: { [weak self] status, progress in
168+
DispatchQueue.main.async {
169+
let overallProgress = 0.5 + (progress * 0.5)
170+
self?.progress = overallProgress
171+
let percent = Int(overallProgress * 100)
172+
self?.status = "\(status) (\(percent)%)"
173+
}
174+
},
175+
completion: { [weak self] result in
176+
DispatchQueue.main.async {
177+
switch result {
178+
case .success(let signedIPAURL):
179+
self?.progress = 1.0
180+
self?.status = "✅ Successfully signed ipa! Installing app now..."
181+
self?.showSuccess = true
182+
183+
Task {
184+
do {
185+
try await installApp(from: signedIPAURL)
186+
} catch {
187+
self?.status = "❌ Install failed: \(error.localizedDescription)"
218188
}
219-
220-
// Clean up original downloaded IPA
221-
try? FileManager.default.removeItem(at: ipaURL)
222-
223-
case .failure(let error):
224-
self?.status = "❌ Signing failed: \(error.localizedDescription)"
189+
}
190+
191+
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
225192
self?.isProcessing = false
226-
try? FileManager.default.removeItem(at: ipaURL)
193+
self?.showSuccess = false
194+
self?.progress = 0.0
195+
self?.status = ""
227196
}
197+
198+
// Clean up original downloaded IPA
199+
try? FileManager.default.removeItem(at: ipaURL)
200+
201+
case .failure(let error):
202+
self?.status = "❌ Signing failed: \(error.localizedDescription)"
203+
self?.isProcessing = false
204+
try? FileManager.default.removeItem(at: ipaURL)
228205
}
229206
}
230-
)
231-
}
232-
207+
}
208+
)
209+
}
210+
233211
func cancel() {
234212
downloadTask?.cancel()
235-
hideTimer?.invalidate()
236213
DispatchQueue.main.async {
237214
self.isProcessing = false
238215
self.status = "Cancelled"
239216
self.progress = 0.0
240-
self.showSuccess = false
241217
}
242218
}
243-
219+
244220
private func getAppFolder() -> URL {
245221
let fm = FileManager.default
246222
let documents = fm.urls(for: .documentDirectory, in: .userDomainMask).first!
@@ -250,4 +226,5 @@ class DownloadSignManager: ObservableObject {
250226
}
251227
return appFolder
252228
}
229+
253230
}

0 commit comments

Comments
 (0)