Skip to content

Commit 4cf1966

Browse files
author
Oct4pie
committed
v1.2.0 fix, helper extension, universal apps view
1 parent 737851b commit 4cf1966

22 files changed

Lines changed: 878 additions & 516 deletions

archify.xcodeproj/project.pbxproj

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
B22648CC2C29B5AA00A54ADB /* BatchProcessing.swift in Sources */ = {isa = PBXBuildFile; fileRef = B22648CB2C29B5AA00A54ADB /* BatchProcessing.swift */; };
11+
B22648CE2C29B6AF00A54ADB /* SizeCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = B22648CD2C29B6AF00A54ADB /* SizeCalculation.swift */; };
12+
B22648D02C29CAFB00A54ADB /* UniversalAppsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B22648CF2C29CAFB00A54ADB /* UniversalAppsView.swift */; };
1013
B22671EA2C244477006D8ADF /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = B22671E92C244477006D8ADF /* Info.plist */; };
1114
B22671EE2C245802006D8ADF /* HelperToolProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B22671ED2C245802006D8ADF /* HelperToolProtocol.swift */; };
1215
B22671F62C25C9F3006D8ADF /* BatchProcessingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B22671F52C25C9F3006D8ADF /* BatchProcessingView.swift */; };
@@ -93,6 +96,9 @@
9396
/* End PBXCopyFilesBuildPhase section */
9497

9598
/* Begin PBXFileReference section */
99+
B22648CB2C29B5AA00A54ADB /* BatchProcessing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatchProcessing.swift; sourceTree = "<group>"; };
100+
B22648CD2C29B6AF00A54ADB /* SizeCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SizeCalculation.swift; sourceTree = "<group>"; };
101+
B22648CF2C29CAFB00A54ADB /* UniversalAppsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UniversalAppsView.swift; sourceTree = "<group>"; };
96102
B22671E92C244477006D8ADF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
97103
B22671EB2C244D39006D8ADF /* archifyhelper.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = archifyhelper.entitlements; sourceTree = "<group>"; };
98104
B22671ED2C245802006D8ADF /* HelperToolProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HelperToolProtocol.swift; path = archifyhelper/HelperToolProtocol.swift; sourceTree = "<group>"; };
@@ -193,20 +199,23 @@
193199
isa = PBXGroup;
194200
children = (
195201
B22671E92C244477006D8ADF /* Info.plist */,
202+
B2C0EBF02C1AB05300132B38 /* ContentView.swift */,
196203
B2C0EC192C1AB14200132B38 /* AppState.swift */,
204+
B2C0EBEE2C1AB05300132B38 /* archifyApp.swift */,
197205
B2C0EC1B2C1AB17500132B38 /* FileOperations.swift */,
198206
B2C0EC1F2C1AB1DB00132B38 /* Extensions.swift */,
199207
B22671ED2C245802006D8ADF /* HelperToolProtocol.swift */,
200208
B2C0EC1D2C1AB1B000132B38 /* Signer.swift */,
201-
B2C0EBEE2C1AB05300132B38 /* archifyApp.swift */,
202209
B2C0EBF22C1AB05400132B38 /* Assets.xcassets */,
203210
B2C0EBF72C1AB05400132B38 /* archify.entitlements */,
204211
B2C0EBF42C1AB05400132B38 /* Preview Content */,
205212
B2C0EC3A2C1AEE5800132B38 /* UniversalApps.swift */,
206-
B2C0EBF02C1AB05300132B38 /* ContentView.swift */,
213+
B22648CF2C29CAFB00A54ADB /* UniversalAppsView.swift */,
207214
B22671F52C25C9F3006D8ADF /* BatchProcessingView.swift */,
215+
B22648CB2C29B5AA00A54ADB /* BatchProcessing.swift */,
208216
B2C0EC3C2C1AF49A00132B38 /* AppProcessingView.swift */,
209217
B2C0EC3E2C1AF5DD00132B38 /* SizeCalculationView.swift */,
218+
B22648CD2C29B6AF00A54ADB /* SizeCalculation.swift */,
210219
B249E79E2C22C8CC002822CA /* LanguageCleaner.swift */,
211220
B249E7A02C22C908002822CA /* LanguageCleanerView.swift */,
212221
B249E7B92C23E219002822CA /* HelperTool.swift */,
@@ -368,8 +377,10 @@
368377
B2C0EC202C1AB1DB00132B38 /* Extensions.swift in Sources */,
369378
B22671EE2C245802006D8ADF /* HelperToolProtocol.swift in Sources */,
370379
B2C0EC1A2C1AB14200132B38 /* AppState.swift in Sources */,
380+
B22648D02C29CAFB00A54ADB /* UniversalAppsView.swift in Sources */,
371381
B2BABC312C240E37009AAF01 /* PermissionsManager.swift in Sources */,
372382
B2BABC2F2C240E13009AAF01 /* FileOperationsManager.swift in Sources */,
383+
B22648CC2C29B5AA00A54ADB /* BatchProcessing.swift in Sources */,
373384
B2C0EC3D2C1AF49A00132B38 /* AppProcessingView.swift in Sources */,
374385
B249E79F2C22C8CD002822CA /* LanguageCleaner.swift in Sources */,
375386
B2C0EBF12C1AB05300132B38 /* ContentView.swift in Sources */,
@@ -378,6 +389,7 @@
378389
B2C0EC3B2C1AEE5800132B38 /* UniversalApps.swift in Sources */,
379390
B2C0EC3F2C1AF5DD00132B38 /* SizeCalculationView.swift in Sources */,
380391
B2C0EC1C2C1AB17500132B38 /* FileOperations.swift in Sources */,
392+
B22648CE2C29B6AF00A54ADB /* SizeCalculation.swift in Sources */,
381393
B22671F62C25C9F3006D8ADF /* BatchProcessingView.swift in Sources */,
382394
);
383395
runOnlyForDeploymentPostprocessing = 0;
@@ -404,7 +416,7 @@
404416
CODE_SIGN_INJECT_BASE_ENTITLEMENTS = YES;
405417
CODE_SIGN_STYLE = Manual;
406418
CREATE_INFOPLIST_SECTION_IN_BINARY = YES;
407-
CURRENT_PROJECT_VERSION = 1.0;
419+
CURRENT_PROJECT_VERSION = 1.1.0;
408420
DEVELOPMENT_TEAM = "";
409421
DONT_GENERATE_INFOPLIST_FILE = NO;
410422
EAGER_LINKING = NO;
@@ -443,7 +455,7 @@
443455
CODE_SIGN_INJECT_BASE_ENTITLEMENTS = YES;
444456
CODE_SIGN_STYLE = Manual;
445457
CREATE_INFOPLIST_SECTION_IN_BINARY = YES;
446-
CURRENT_PROJECT_VERSION = 1.0;
458+
CURRENT_PROJECT_VERSION = 1.1.0;
447459
DEVELOPMENT_TEAM = "";
448460
DONT_GENERATE_INFOPLIST_FILE = NO;
449461
EAGER_LINKING = NO;
@@ -621,7 +633,7 @@
621633
"@executable_path/../Frameworks",
622634
);
623635
MACOSX_DEPLOYMENT_TARGET = 11.0;
624-
MARKETING_VERSION = 1.0;
636+
MARKETING_VERSION = 1.1.0;
625637
ONLY_ACTIVE_ARCH = YES;
626638
PRODUCT_BUNDLE_IDENTIFIER = com.oct4pie.archify;
627639
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -660,7 +672,7 @@
660672
"@executable_path/../Frameworks",
661673
);
662674
MACOSX_DEPLOYMENT_TARGET = 11.0;
663-
MARKETING_VERSION = 1.0;
675+
MARKETING_VERSION = 1.1.0;
664676
ONLY_ACTIVE_ARCH = YES;
665677
PRODUCT_BUNDLE_IDENTIFIER = com.oct4pie.archify;
666678
PRODUCT_NAME = "$(TARGET_NAME)";
Binary file not shown.

archify/AppProcessingView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import SwiftUI
99

1010
struct AppProcessingView: View {
11-
@StateObject var appState = AppState()
11+
@EnvironmentObject var appState: AppState
1212
@State private var showAlert = false
1313

1414
var body: some View {

archify/BatchProcessing.swift

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import Combine
2+
import Foundation
3+
import AppKit
4+
5+
class BatchProcessing: ObservableObject {
6+
@Published var appSizes: [(String, UInt64)] = []
7+
@Published var progress: Double = 0.0
8+
@Published var currentApp: String = ""
9+
@Published var selectedApps: Set<String> = []
10+
@Published var isProcessing: Bool = false
11+
@Published var totalSavedSpace: UInt64 = 0
12+
@Published var logMessages: String = ""
13+
14+
private let appState = AppState()
15+
16+
func startCalculatingSizes() {
17+
isProcessing = true
18+
appSizes = []
19+
progress = 0.0
20+
currentApp = ""
21+
22+
DispatchQueue.global(qos: .background).async {
23+
let universalApps = UniversalApps()
24+
let systemArch = self.systemArchitecture()
25+
universalApps.produceSortedList(systemArch: systemArch, progressHandler: { app, processed, total in
26+
DispatchQueue.main.async {
27+
self.currentApp = URL(fileURLWithPath: app).lastPathComponent
28+
self.progress = Double(processed) / Double(total)
29+
}
30+
}) { sortedAppSizes in
31+
DispatchQueue.main.async {
32+
self.appSizes = sortedAppSizes
33+
self.isProcessing = false
34+
}
35+
}
36+
}
37+
}
38+
39+
func startProcessingSelectedApps() {
40+
isProcessing = true
41+
appState.isProcessing = true
42+
appState.logMessages = ""
43+
totalSavedSpace = 0
44+
45+
guard HelperToolManager.shared.blessHelperTool() else {
46+
print("Failed to install helper tool.")
47+
return
48+
}
49+
50+
HelperToolManager.shared.interactWithHelperTool(command: .checkFullDiskAccess) { [weak self] hasAccess, error in
51+
guard let self = self else { return }
52+
if hasAccess {
53+
self.processSelectedApps()
54+
} else {
55+
self.promptForFullDiskAccess()
56+
self.isProcessing = false
57+
self.appState.isProcessing = false
58+
}
59+
}
60+
}
61+
62+
private func processSelectedApps() {
63+
DispatchQueue.global(qos: .background).async {
64+
let appStateDict = self.appState.toDictionary()
65+
let group = DispatchGroup()
66+
67+
for app in self.selectedApps {
68+
group.enter()
69+
HelperToolManager.shared.interactWithHelperTool(command: .extractAndSignBinaries(dir: app, targetArch: self.systemArchitecture(), noSign: true, noEntitlements: true, appStateDict: appStateDict)) { success, errorString in
70+
if success {
71+
DispatchQueue.main.async {
72+
if let index = self.appSizes.firstIndex(where: { $0.0 == app }) {
73+
self.totalSavedSpace += self.appSizes[index].1
74+
self.appSizes.remove(at: index)
75+
self.selectedApps.remove(app)
76+
}
77+
}
78+
print("Processed \(app) successfully")
79+
} else {
80+
print("Failed to process \(app): \(errorString ?? "Unknown error")")
81+
}
82+
group.leave()
83+
}
84+
}
85+
86+
group.notify(queue: .main) {
87+
self.isProcessing = false
88+
self.appState.isProcessing = false
89+
}
90+
}
91+
}
92+
93+
func selectAllApps() {
94+
selectedApps = Set(appSizes.map { $0.0 })
95+
}
96+
97+
func deselectAllApps() {
98+
selectedApps.removeAll()
99+
}
100+
101+
private func systemArchitecture() -> String {
102+
let process = Process()
103+
process.launchPath = "/usr/bin/uname"
104+
process.arguments = ["-m"]
105+
106+
let pipe = Pipe()
107+
process.standardOutput = pipe
108+
109+
do {
110+
try process.run()
111+
process.waitUntilExit()
112+
113+
let data = pipe.fileHandleForReading.readDataToEndOfFile()
114+
if let output = String(data: data, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines) {
115+
return output
116+
}
117+
} catch {
118+
return "Unknown"
119+
}
120+
121+
return "Unknown"
122+
}
123+
124+
private func promptForFullDiskAccess() {
125+
DispatchQueue.main.async {
126+
let alert = NSAlert()
127+
alert.messageText = "Full Disk Access Required"
128+
alert.informativeText = """
129+
This application requires Full Disk Access to function properly.
130+
Please go to System Preferences > Security & Privacy > Privacy > Full Disk Access
131+
and check "com.oct4pie" in the list.
132+
"""
133+
alert.alertStyle = .warning
134+
alert.addButton(withTitle: "OK")
135+
alert.runModal()
136+
}
137+
}
138+
}

0 commit comments

Comments
 (0)