Skip to content

Commit 1984717

Browse files
committed
feat: instant inject
Signed-off-by: 82Flex <82flex@gmail.com>
1 parent c2688c5 commit 1984717

File tree

9 files changed

+158
-39
lines changed

9 files changed

+158
-39
lines changed

.bartycrouch.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ tasks = ["interfaces", "code", "transform", "normalize"]
44
[update.interfaces]
55
paths = ["TrollFools"]
66
subpathsToIgnore = [".git", "carthage", "pods", "build", ".build", "docs"]
7-
defaultToBase = false
7+
defaultToBase = true
88
ignoreEmptyStrings = false
99
unstripped = false
1010
ignoreKeys = ["#bartycrouch-ignore!", "#bc-ignore!", "#i!"]

TrollFools.xcodeproj/project.pbxproj

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
CC3485182C71B219007E0E28 /* Version.Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = CC3485162C71B219007E0E28 /* Version.Debug.xcconfig */; };
3030
CC5E54BE2C4E12F900FDE4A8 /* install_name_tool in Resources */ = {isa = PBXBuildFile; fileRef = CC5E54BC2C4E12F900FDE4A8 /* install_name_tool */; };
3131
CC5E54BF2C4E131000FDE4A8 /* libxar.1.dylib in Resources */ = {isa = PBXBuildFile; fileRef = CC5E54BB2C4E12F900FDE4A8 /* libxar.1.dylib */; };
32+
CC60FBEC2CC50F5A00A6D21A /* BartyCrouch.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC60FBEB2CC50F5A00A6D21A /* BartyCrouch.swift */; };
3233
CC61A87C2C4A677B003BD9A0 /* CydiaSubstrate.framework.zip in Resources */ = {isa = PBXBuildFile; fileRef = CC61A87B2C4A677B003BD9A0 /* CydiaSubstrate.framework.zip */; };
3334
CCB6A1172C4A540F000D75B0 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CCB6A1162C4A540F000D75B0 /* CoreServices.framework */; };
3435
CCB6A1192C4A58C7000D75B0 /* OptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCB6A1182C4A58C7000D75B0 /* OptionView.swift */; };
@@ -70,6 +71,8 @@
7071
CC5E54BB2C4E12F900FDE4A8 /* libxar.1.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = libxar.1.dylib; sourceTree = "<group>"; };
7172
CC5E54BC2C4E12F900FDE4A8 /* install_name_tool */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = install_name_tool; sourceTree = "<group>"; };
7273
CC60FBE92CC4E6C400A6D21A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
74+
CC60FBEA2CC5024000A6D21A /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = "<group>"; };
75+
CC60FBEB2CC50F5A00A6D21A /* BartyCrouch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BartyCrouch.swift; sourceTree = "<group>"; };
7376
CC61A87B2C4A677B003BD9A0 /* CydiaSubstrate.framework.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = CydiaSubstrate.framework.zip; sourceTree = "<group>"; };
7477
CCB6A1162C4A540F000D75B0 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; };
7578
CCB6A1182C4A58C7000D75B0 /* OptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OptionView.swift; sourceTree = "<group>"; };
@@ -113,28 +116,29 @@
113116
isa = PBXGroup;
114117
children = (
115118
CCF4705D2C4A464B008D8197 /* Assets.xcassets */,
116-
CC61A87B2C4A677B003BD9A0 /* CydiaSubstrate.framework.zip */,
117119
CCF925432C4CE47800880D48 /* chown */,
118120
CC1548E02C4A963500A4173E /* cp */,
119121
CC1549012C4B62E300A4173E /* cp-15 */,
120122
CC1548CF2C4A6B8200A4173E /* ct_bypass */,
123+
CC61A87B2C4A677B003BD9A0 /* CydiaSubstrate.framework.zip */,
124+
CC60FBE92CC4E6C400A6D21A /* Info.plist */,
121125
CC1548DC2C4A8DC500A4173E /* insert_dylib */,
122126
CC5E54BC2C4E12F900FDE4A8 /* install_name_tool */,
123127
CCC564E82C4BE8320097C300 /* ldid */,
124-
CCFC78632C4E853D008EB25D /* mkdir */,
125-
CCECB7CD2C54DC660094C8E6 /* mv */,
126-
CC0E80FA2C54F84000B137B4 /* mv-15 */,
127-
CC15490B2C4B79D800A4173E /* optool */,
128-
CC1548FF2C4AB43600A4173E /* rm */,
129128
CCC564E62C4BE8320097C300 /* libcrypto.3.dylib */,
130129
CC1548E22C4A974400A4173E /* libintl.8.dylib */,
131130
CC1548E32C4A974400A4173E /* libiosexec.1.dylib */,
132131
CCC564E72C4BE8320097C300 /* libplist-2.0.3.dylib */,
133132
CC5E54BB2C4E12F900FDE4A8 /* libxar.1.dylib */,
134133
CCF4706B2C4A4919008D8197 /* Localizable.strings */,
134+
CCFC78632C4E853D008EB25D /* mkdir */,
135+
CCECB7CD2C54DC660094C8E6 /* mv */,
136+
CC0E80FA2C54F84000B137B4 /* mv-15 */,
137+
CC15490B2C4B79D800A4173E /* optool */,
138+
CC1548FF2C4AB43600A4173E /* rm */,
135139
CC3485142C71B219007E0E28 /* TrollFools.entitlements */,
136-
CC3485152C71B219007E0E28 /* Version.xcconfig */,
137140
CC3485162C71B219007E0E28 /* Version.Debug.xcconfig */,
141+
CC3485152C71B219007E0E28 /* Version.xcconfig */,
138142
);
139143
name = Resources;
140144
sourceTree = "<group>";
@@ -167,7 +171,7 @@
167171
CCF470582C4A4649008D8197 /* TrollFools */ = {
168172
isa = PBXGroup;
169173
children = (
170-
CC60FBE92CC4E6C400A6D21A /* Info.plist */,
174+
CC60FBEB2CC50F5A00A6D21A /* BartyCrouch.swift */,
171175
CCF470592C4A4649008D8197 /* TrollFoolsApp.swift */,
172176
CCF4706D2C4A4BAB008D8197 /* AppListView.swift */,
173177
CCB6A1182C4A58C7000D75B0 /* OptionView.swift */,
@@ -238,6 +242,7 @@
238242
en,
239243
Base,
240244
"zh-Hans",
245+
vi,
241246
);
242247
mainGroup = CCF4704D2C4A4649008D8197;
243248
packageReferences = (
@@ -294,6 +299,7 @@
294299
CCB6A11B2C4A6066000D75B0 /* InjectView.swift in Sources */,
295300
CCF470732C4A4E81008D8197 /* TrollFoolsStub.m in Sources */,
296301
CC15490E2C4B80AF00A4173E /* EjectListView.swift in Sources */,
302+
CC60FBEC2CC50F5A00A6D21A /* BartyCrouch.swift in Sources */,
297303
CC1548DB2C4A7C7000A4173E /* Execute.swift in Sources */,
298304
CCF5A0A42C4D45160097D48D /* AuxiliaryExecute.swift in Sources */,
299305
CCF4705A2C4A4649008D8197 /* TrollFoolsApp.swift in Sources */,
@@ -314,6 +320,7 @@
314320
children = (
315321
CCF4706A2C4A4919008D8197 /* en */,
316322
CCF4706C2C4A491B008D8197 /* zh-Hans */,
323+
CC60FBEA2CC5024000A6D21A /* vi */,
317324
);
318325
name = Localizable.strings;
319326
sourceTree = "<group>";

TrollFools/AppListView.swift

Lines changed: 66 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,14 @@ final class App: Identifiable, ObservableObject {
2929
lazy var isFromTroll: Bool = isSystem && !isFromApple
3030
lazy var isRemovable: Bool = url.path.contains("/var/containers/Bundle/Application/")
3131

32-
init(id: String,
33-
name: String,
34-
type: String,
35-
teamID: String,
36-
url: URL,
37-
version: String? = nil,
38-
alternateIcon: UIImage? = nil
32+
init(
33+
id: String,
34+
name: String,
35+
type: String,
36+
teamID: String,
37+
url: URL,
38+
version: String? = nil,
39+
alternateIcon: UIImage? = nil
3940
) {
4041
self.id = id
4142
self.name = name
@@ -68,6 +69,9 @@ final class AppListModel: ObservableObject {
6869
static let hasTrollStore: Bool = { LSApplicationProxy(forIdentifier: "com.opa334.TrollStore") != nil }()
6970
private var _allApplications: [App] = []
7071

72+
let selectorURL: URL?
73+
var isSelectorMode: Bool { selectorURL != nil }
74+
7175
@Published var filter = FilterOptions()
7276
@Published var userApplications: [App] = []
7377
@Published var trollApplications: [App] = []
@@ -85,7 +89,8 @@ final class AppListModel: ObservableObject {
8589
private let applicationChanged = PassthroughSubject<Void, Never>()
8690
private var cancellables = Set<AnyCancellable>()
8791

88-
init() {
92+
init(selectorURL: URL? = nil) {
93+
self.selectorURL = selectorURL
8994
reload()
9095

9196
filter.$searchKeyword
@@ -116,6 +121,11 @@ final class AppListModel: ObservableObject {
116121
}, "com.apple.LaunchServices.ApplicationsChanged" as CFString, nil, .coalesce)
117122
}
118123

124+
deinit {
125+
let darwinCenter = CFNotificationCenterGetDarwinNotifyCenter()
126+
CFNotificationCenterRemoveObserver(darwinCenter, Unmanaged.passUnretained(self).toOpaque(), nil, nil)
127+
}
128+
119129
func reload() {
120130
let allApplications = Self.fetchApplications(&hasTrollRecorder, &unsupportedCount)
121131
self._allApplications = allApplications
@@ -325,7 +335,11 @@ struct AppListCell: View {
325335
else {
326336
// iOS 15
327337
Color.clear
328-
.contextMenu { cellContextMenu }
338+
.contextMenu {
339+
if !vm.isSelectorMode {
340+
cellContextMenu
341+
}
342+
}
329343
.id(app.isDetached)
330344
}
331345
}
@@ -391,7 +405,11 @@ struct AppListCell: View {
391405
}
392406
}
393407
}
394-
.contextMenu { cellContextMenuWrapper }
408+
.contextMenu {
409+
if !vm.isSelectorMode {
410+
cellContextMenuWrapper
411+
}
412+
}
395413
.background(cellBackground)
396414
}
397415

@@ -412,6 +430,8 @@ struct AppListView: View {
412430
@State var isErrorOccurred: Bool = false
413431
@State var errorMessage: String = ""
414432

433+
@State var selectorOpenedURL: URL? = nil
434+
415435
var appNameString: String {
416436
Bundle.main.infoDictionary?["CFBundleName"] as? String ?? "TrollFools"
417437
}
@@ -426,15 +446,19 @@ struct AppListView: View {
426446
String(format: """
427447
%@ %@ %@ © 2024
428448
%@
429-
""", appNameString, appVersionString, NSLocalizedString("Copyright", comment: ""), NSLocalizedString("Lessica, Lakr233, mlgm and other contributors.", comment: ""))
449+
""", appNameString, appVersionString, NSLocalizedString("Copyright", comment: ""), NSLocalizedString("Made with ♥ by OwnGoal Studio", comment: ""))
430450
}
431451

432452
let repoURL = URL(string: "https://github.com/Lessica/TrollFools")
433453

434454
func filteredAppList(_ apps: [App]) -> some View {
435455
ForEach(apps, id: \.id) { app in
436456
NavigationLink {
437-
OptionView(app)
457+
if vm.isSelectorMode, let selectorURL = vm.selectorURL {
458+
InjectView(app, urlList: [selectorURL])
459+
} else {
460+
OptionView(app)
461+
}
438462
} label: {
439463
if #available(iOS 16.0, *) {
440464
AppListCell(app: app)
@@ -539,26 +563,37 @@ struct AppListView: View {
539563
.font(.footnote)
540564
}
541565

542-
if #available(iOS 16.0, *) {
543-
appListFooter
544-
.padding(.top, 8)
545-
} else {
546-
appListFooter
547-
.padding(.top, 2)
566+
if !vm.isSelectorMode {
567+
if #available(iOS 16.0, *) {
568+
appListFooter
569+
.padding(.top, 8)
570+
} else {
571+
appListFooter
572+
.padding(.top, 2)
573+
}
548574
}
549575
}
550576
}
551577
}
552578
}
553579
.listStyle(.insetGrouped)
554-
.navigationTitle(NSLocalizedString("TrollFools", comment: ""))
580+
.navigationTitle(vm.isSelectorMode ? NSLocalizedString("Select Application to Inject", comment: "") : NSLocalizedString("TrollFools", comment: ""))
581+
.navigationBarTitleDisplayMode(vm.isSelectorMode ? .inline : .automatic)
555582
.background(Group {
556583
NavigationLink(isActive: $isErrorOccurred) {
557584
FailureView(title: NSLocalizedString("Error", comment: ""),
558585
message: errorMessage)
559586
} label: { }
560587
})
561588
.toolbar {
589+
ToolbarItem(placement: .principal) {
590+
if vm.isSelectorMode, let selectorURL = vm.selectorURL {
591+
VStack {
592+
Text(selectorURL.lastPathComponent).font(.headline)
593+
Text(NSLocalizedString("Select Application to Inject", comment: "")).font(.caption)
594+
}
595+
}
596+
}
562597
ToolbarItem(placement: .navigationBarTrailing) {
563598
Button {
564599
vm.filter.showPatchedOnly.toggle()
@@ -601,8 +636,15 @@ struct AppListView: View {
601636
appList
602637
}
603638
}
639+
.sheet(item: $selectorOpenedURL) { url in
640+
AppListView()
641+
.environmentObject(AppListModel(selectorURL: url))
642+
}
604643
.onOpenURL { url in
605-
644+
guard url.isFileURL, url.pathExtension.lowercased() == "dylib" else {
645+
return
646+
}
647+
selectorOpenedURL = url
606648
}
607649
}
608650

@@ -639,3 +681,7 @@ struct AppListView: View {
639681
}
640682
}
641683
}
684+
685+
extension URL: Identifiable {
686+
public var id: String { absoluteString }
687+
}

TrollFools/BartyCrouch.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// This file is required in order for the `transform` task of the translation helper tool BartyCrouch to work.
2+
// See here for more details: https://github.com/FlineDev/BartyCrouch
3+
4+
import Foundation
5+
6+
enum BartyCrouch {
7+
enum SupportedLanguage: String {
8+
case english = "en"
9+
case chineseSimplified = "zh-Hans"
10+
case vietnamese = "vi"
11+
}
12+
13+
static func translate(key: String, translations: [SupportedLanguage: String], comment _: String? = nil) -> String {
14+
let typeName = String(describing: BartyCrouch.self)
15+
let methodName = #function
16+
17+
print(
18+
"Warning: [BartyCrouch]",
19+
"Untransformed \(typeName).\(methodName) method call found with key '\(key)' and base translations '\(translations)'.",
20+
"Please ensure that BartyCrouch is installed and configured correctly."
21+
)
22+
23+
// fall back in case something goes wrong with BartyCrouch transformation
24+
return "BC: TRANSFORMATION FAILED!"
25+
}
26+
}

TrollFools/InjectView.swift

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,19 @@ final class ViewControllerHost: ObservableObject {
5353
}
5454

5555
struct InjectView: View {
56+
@EnvironmentObject var vm: AppListModel
57+
5658
let app: App
5759
let urlList: [URL]
5860

5961
@State var injectResult: Result<Void, Error>?
60-
6162
@StateObject var viewControllerHost = ViewControllerHost()
6263

64+
init(_ app: App, urlList: [URL]) {
65+
self.app = app
66+
self.urlList = urlList
67+
}
68+
6369
func inject() -> Result<Void, Error> {
6470
do {
6571
let injector = try Injector(app.url, appID: app.id, teamID: app.teamID)
@@ -73,7 +79,7 @@ struct InjectView: View {
7379
}
7480
}
7581

76-
var body: some View {
82+
var bodyContent: some View {
7783
VStack {
7884
if let injectResult {
7985
switch injectResult {
@@ -125,4 +131,20 @@ struct InjectView: View {
125131
}
126132
}
127133
}
134+
135+
var body: some View {
136+
if vm.isSelectorMode {
137+
bodyContent
138+
.toolbar {
139+
ToolbarItem(placement: .navigationBarTrailing) {
140+
Button(NSLocalizedString("Done", comment: "")) {
141+
viewControllerHost.viewController?.navigationController?
142+
.dismiss(animated: true)
143+
}
144+
}
145+
}
146+
} else {
147+
bodyContent
148+
}
149+
}
128150
}

TrollFools/OptionView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ struct OptionView: View {
105105
if let result = importerResult {
106106
switch result {
107107
case .success(let urls):
108-
InjectView(app: app, urlList: urls
108+
InjectView(app, urlList: urls
109109
.sorted(by: { $0.lastPathComponent < $1.lastPathComponent }))
110110
case .failure(let message):
111111
FailureView(title: NSLocalizedString("Error", comment: ""),

TrollFools/en.lproj/Localizable.strings

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
/* No comment provided by engineer. */
2323
"Copyright" = "Copyright";
2424

25+
/* No comment provided by engineer. */
26+
"Done" = "Done";
27+
2528
/* No comment provided by engineer. */
2629
"Eject" = "Eject";
2730

@@ -65,10 +68,10 @@
6568
"Launch" = "Launch";
6669

6770
/* No comment provided by engineer. */
68-
"Lessica, Lakr233, mlgm and other contributors." = "Lessica, Lakr233, mlgm and other contributors.";
71+
"Lock Version" = "Lock Version";
6972

7073
/* No comment provided by engineer. */
71-
"Lock Version" = "Lock Version";
74+
"Made with ♥ by OwnGoal Studio" = "Made with ♥ by OwnGoal Studio";
7275

7376
/* No comment provided by engineer. */
7477
"No eligible framework found." = "No eligible framework found.";
@@ -106,6 +109,9 @@
106109
/* No comment provided by engineer. */
107110
"Search…" = "Search…";
108111

112+
/* No comment provided by engineer. */
113+
"Select Application to Inject" = "Select Application to Inject";
114+
109115
/* No comment provided by engineer. */
110116
"Show in Filza" = "Show in Filza";
111117

0 commit comments

Comments
 (0)