From b795b6a0aa82d8c281d4c2b0dc73db229ce85a72 Mon Sep 17 00:00:00 2001 From: Riley Testut Date: Mon, 1 Jul 2019 15:19:22 -0700 Subject: [PATCH] [AltServer] Turns AltServer into menu bar app --- AltServer/AppDelegate.swift | 195 +++++- .../MenuBarIcon.imageset/Contents.json | 25 + .../MenuBarIcon.imageset/MenuBarIcon.png | Bin 0 -> 4219 bytes .../MenuBarIcon.imageset/MenuBarIcon@2x.png | Bin 0 -> 4842 bytes AltServer/Base.lproj/Main.storyboard | 629 ++---------------- AltServer/Connections/ConnectionManager.swift | 2 +- .../ALTDeviceManager+Installation.swift} | 113 +--- AltServer/Devices/ALTDeviceManager.h | 1 + AltServer/Devices/ALTDeviceManager.mm | 25 +- AltServer/Info.plist | 2 + AltStore.xcodeproj/project.pbxproj | 8 +- Dependencies/libimobiledevice | 2 +- 12 files changed, 327 insertions(+), 675 deletions(-) create mode 100644 AltServer/Assets.xcassets/MenuBarIcon.imageset/Contents.json create mode 100644 AltServer/Assets.xcassets/MenuBarIcon.imageset/MenuBarIcon.png create mode 100644 AltServer/Assets.xcassets/MenuBarIcon.imageset/MenuBarIcon@2x.png rename AltServer/{ViewController.swift => Devices/ALTDeviceManager+Installation.swift} (83%) diff --git a/AltServer/AppDelegate.swift b/AltServer/AppDelegate.swift index 03e0c9ed..aeab490b 100644 --- a/AltServer/AppDelegate.swift +++ b/AltServer/AppDelegate.swift @@ -7,20 +7,203 @@ // import Cocoa +import UserNotifications + +import AltSign @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { + private var statusItem: NSStatusItem? + + private var connectedDevices = [ALTDevice]() + + private weak var authenticationAlert: NSAlert? + + @IBOutlet private var appMenu: NSMenu! + @IBOutlet private var connectedDevicesMenu: NSMenu! + + private weak var authenticationAppleIDTextField: NSTextField? + private weak var authenticationPasswordTextField: NSSecureTextField? - - func applicationDidFinishLaunching(_ aNotification: Notification) { - // Insert code here to initialize your application + func applicationDidFinishLaunching(_ aNotification: Notification) + { + UNUserNotificationCenter.current().delegate = self + ConnectionManager.shared.start() + + let item = NSStatusBar.system.statusItem(withLength: -1) + guard let button = item.button else { return } + + button.image = NSImage(named: "MenuBarIcon") + button.target = self + button.action = #selector(AppDelegate.presentMenu) + + self.statusItem = item + + self.connectedDevicesMenu.delegate = self } - func applicationWillTerminate(_ aNotification: Notification) { + func applicationWillTerminate(_ aNotification: Notification) + { // Insert code here to tear down your application } - - } +private extension AppDelegate +{ + @objc func presentMenu() + { + guard let button = self.statusItem?.button, let superview = button.superview, let window = button.window else { return } + + self.connectedDevices = ALTDeviceManager.shared.connectedDevices + + let x = button.frame.origin.x + let y = button.frame.origin.y - 5 + + let location = superview.convert(NSMakePoint(x, y), to: nil) + + guard let event = NSEvent.mouseEvent(with: .leftMouseUp, location: location, + modifierFlags: [], timestamp: 0, windowNumber: window.windowNumber, context: nil, + eventNumber: 0, clickCount: 1, pressure: 0) + else { return } + + NSMenu.popUpContextMenu(self.appMenu, with: event, for: button) + } + + @objc func installAltStore(_ item: NSMenuItem) + { + guard case let index = self.connectedDevicesMenu.index(of: item), index != -1 else { return } + + let alert = NSAlert() + alert.messageText = NSLocalizedString("Please enter your Apple ID and password.", comment: "") + alert.informativeText = NSLocalizedString("Your Apple ID and password are not saved and are only sent to Apple for authentication.", comment: "") + + let textFieldSize = NSSize(width: 300, height: 22) + + let appleIDTextField = NSTextField(frame: NSRect(x: 0, y: 0, width: textFieldSize.width, height: textFieldSize.height)) + appleIDTextField.delegate = self + appleIDTextField.translatesAutoresizingMaskIntoConstraints = false + appleIDTextField.placeholderString = NSLocalizedString("Apple ID", comment: "") + alert.window.initialFirstResponder = appleIDTextField + self.authenticationAppleIDTextField = appleIDTextField + + let passwordTextField = NSSecureTextField(frame: NSRect(x: 0, y: 0, width: textFieldSize.width, height: textFieldSize.height)) + passwordTextField.delegate = self + passwordTextField.translatesAutoresizingMaskIntoConstraints = false + passwordTextField.placeholderString = NSLocalizedString("Password", comment: "") + self.authenticationPasswordTextField = passwordTextField + + appleIDTextField.nextKeyView = passwordTextField + + let stackView = NSStackView(frame: NSRect(x: 0, y: 0, width: textFieldSize.width, height: textFieldSize.height * 2)) + stackView.orientation = .vertical + stackView.distribution = .equalSpacing + stackView.spacing = 0 + stackView.addArrangedSubview(appleIDTextField) + stackView.addArrangedSubview(passwordTextField) + alert.accessoryView = stackView + + alert.addButton(withTitle: NSLocalizedString("Install", comment: "")) + alert.addButton(withTitle: NSLocalizedString("Cancel", comment: "")) + + self.authenticationAlert = alert + self.validate() + + NSRunningApplication.current.activate(options: .activateIgnoringOtherApps) + + let response = alert.runModal() + guard response == .alertFirstButtonReturn else { return } + + let username = appleIDTextField.stringValue + let password = passwordTextField.stringValue + + let device = self.connectedDevices[index] + ALTDeviceManager.shared.installAltStore(to: device, appleID: username, password: password) { (result) in + let content = UNMutableNotificationContent() + + switch result + { + case .success: + content.title = NSLocalizedString("Installation Succeeded", comment: "") + content.body = String(format: NSLocalizedString("AltStore was successfully installed on %@.", comment: ""), device.name) + + case .failure(let error): + content.title = NSLocalizedString("Installation Failed", comment: "") + content.body = error.localizedDescription + } + + let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: nil) + UNUserNotificationCenter.current().add(request) + } + } +} + +extension AppDelegate: NSMenuDelegate +{ + func numberOfItems(in menu: NSMenu) -> Int + { + return self.connectedDevices.isEmpty ? 1 : self.connectedDevices.count + } + + func menu(_ menu: NSMenu, update item: NSMenuItem, at index: Int, shouldCancel: Bool) -> Bool + { + if self.connectedDevices.isEmpty + { + item.title = NSLocalizedString("No Connected Devices", comment: "") + item.isEnabled = false + item.target = nil + item.action = nil + } + else + { + let device = self.connectedDevices[index] + item.title = device.name + item.isEnabled = true + item.target = self + item.action = #selector(AppDelegate.installAltStore) + item.tag = index + } + + return true + } +} + +extension AppDelegate: NSTextFieldDelegate +{ + func controlTextDidChange(_ obj: Notification) + { + self.validate() + } + + func controlTextDidEndEditing(_ obj: Notification) + { + self.validate() + } + + private func validate() + { + guard + let appleID = self.authenticationAppleIDTextField?.stringValue.trimmingCharacters(in: .whitespacesAndNewlines), + let password = self.authenticationPasswordTextField?.stringValue.trimmingCharacters(in: .whitespacesAndNewlines) + else { return } + + if appleID.isEmpty || password.isEmpty + { + self.authenticationAlert?.buttons.first?.isEnabled = false + } + else + { + self.authenticationAlert?.buttons.first?.isEnabled = true + } + + self.authenticationAlert?.layout() + } +} + +extension AppDelegate: UNUserNotificationCenterDelegate +{ + func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) + { + completionHandler([.alert, .sound, .badge]) + } +} diff --git a/AltServer/Assets.xcassets/MenuBarIcon.imageset/Contents.json b/AltServer/Assets.xcassets/MenuBarIcon.imageset/Contents.json new file mode 100644 index 00000000..69ff52d9 --- /dev/null +++ b/AltServer/Assets.xcassets/MenuBarIcon.imageset/Contents.json @@ -0,0 +1,25 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "MenuBarIcon.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "MenuBarIcon@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" + } +} \ No newline at end of file diff --git a/AltServer/Assets.xcassets/MenuBarIcon.imageset/MenuBarIcon.png b/AltServer/Assets.xcassets/MenuBarIcon.imageset/MenuBarIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..e13b1f0d96660bd2653abd6eb47990706ebb3b9c GIT binary patch literal 4219 zcmdT|3v3f*9Pbto*nqg8i4ho=@{j@7>s?=WM^_&09(8oiF%lk<`1S5trP0H=nBKn!R$CCr!*&0t_;5!47GWbz0g2}VGLp_$+Hd272cHK;VX-u1ix z|M!3Y|KHc-r4c~9pV42Ch@a!)n7kJGM^kD+h5%Kinq$5%;!t84p1^7E*#Fvsi-CO$aC>XWaU(9nj(;>hKf`tbFicy zX)-yRqZG9o4&teV5(A+Sc`B|bY|dmbSg+e%B})Mz1YKIzV%`$Bon-8GoHCKlRM7Nv zso3jq+)_xAeG(5{7Cl>PS;wV?lYLGWkbOYQEEkfLv8JO(PG@~6^Ld~G4^W|tGLsB$ zcHm~RhP1I}hP9z*2WvJvi458_9JdS+LUt6=u1C>PrePp6g+Nnwj5JMBlxY}IbV;s} zq>yW#)&Q`oMEziHH-;>vvFSd*38Ge1MKQzlOgcQCV*`>L2C7R4gCHa#V$eyX7Il=- z^wnG+6hsj6NL-zk?p}`zy)f|t&jKrDAvu!99TW|4s})c<14$kSkcJ#*Wk@^2M0N4` zvcY7CDi;)0lAEH9DcLWg9cm$5IdE0WORdF(glMOU09k=rK@=Mk6_IRBNhFOYT3DF!EdSs7Ys#yPa^c?npjk8fW zY2zu}N;^p0&p|&<+bQ14Gn|d|Qwc5qO7s*^5C4nUC6Y%H>!GYZP=%C(QMm%NJAty| z3dm9z1CdBb;G*rFs2BP8Mj$zNFjc~I%_`=89Y%U2A4ZeO*1|TGX!>*CfiO#W2UeCN5x?ug5Q`Mi%9bHoJ>84|4SBC#y z*wj(pePrjtpGI{~eSNrPi`U-S>1#iC^x~@6ArDJ+IFYqtF<>KeRO%#g!QL(9`_vT+EaLTYx~N#idQ{bHsW&6 z)*n6JZQoldV^`kqk5t__we9;3Lr?4WDVKt|w|?7pZRVQgch`#Jj?>>Rf1zb>ThY~u zcW$ohm|XGm^DSRjY#96Giu2PNuU=a8rARM{Y%W=F_gdS@X6Jh?-1YX2rz={qSx;>$ zy)foOqQcO>@jQq2zW~>JqPE%xb9DukrZ_R literal 0 HcmV?d00001 diff --git a/AltServer/Assets.xcassets/MenuBarIcon.imageset/MenuBarIcon@2x.png b/AltServer/Assets.xcassets/MenuBarIcon.imageset/MenuBarIcon@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..ca13e7fcfc15cdaf9e6382727afdbb61531c0c40 GIT binary patch literal 4842 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 by - + @@ -8,6 +8,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + NSAllRomanInputSourcesLocaleIdentifier + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -21,98 +76,27 @@ - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -337,325 +321,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -674,170 +339,8 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - NSAllRomanInputSourcesLocaleIdentifier - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/AltServer/Connections/ConnectionManager.swift b/AltServer/Connections/ConnectionManager.swift index 31675c5f..d3e74ad1 100644 --- a/AltServer/Connections/ConnectionManager.swift +++ b/AltServer/Connections/ConnectionManager.swift @@ -277,7 +277,7 @@ private extension ConnectionManager print("Processed app data!") - guard ALTDeviceManager.shared.connectedDevices.contains(where: { $0.identifier == request.udid }) else { throw ALTServerError(.deviceNotFound) } + guard ALTDeviceManager.shared.availableDevices.contains(where: { $0.identifier == request.udid }) else { throw ALTServerError(.deviceNotFound) } print("Writing app data...") diff --git a/AltServer/ViewController.swift b/AltServer/Devices/ALTDeviceManager+Installation.swift similarity index 83% rename from AltServer/ViewController.swift rename to AltServer/Devices/ALTDeviceManager+Installation.swift index 815e06a7..320567e8 100644 --- a/AltServer/ViewController.swift +++ b/AltServer/Devices/ALTDeviceManager+Installation.swift @@ -1,12 +1,13 @@ // -// ViewController.swift +// ALTDeviceManager+Installation.swift // AltServer // -// Created by Riley Testut on 5/24/19. +// Created by Riley Testut on 7/1/19. // Copyright © 2019 Riley Testut. All rights reserved. // import Cocoa +import UserNotifications enum InstallError: Error { @@ -26,119 +27,39 @@ enum InstallError: Error } } -class ViewController: NSViewController +extension ALTDeviceManager { - @IBOutlet private var emailAddressTextField: NSTextField! - @IBOutlet private var passwordTextField: NSSecureTextField! - - @IBOutlet private var devicesButton: NSPopUpButton! - - private var currentDevice: ALTDevice? - - override func viewDidLoad() - { - super.viewDidLoad() - - ConnectionManager.shared.stateUpdateHandler = { (state) in - DispatchQueue.main.async { - switch state - { - case .notRunning: self.view.window?.title = "" - case .connecting: self.view.window?.title = "Connecting...." - case .running(let service): self.view.window?.title = service.name ?? "" - case .failed(let error): self.view.window?.title = error.localizedDescription - } - } - } - - ConnectionManager.shared.start() - - self.update() - } - - func update() - { - self.devicesButton.removeAllItems() - - let devices = ALTDeviceManager.shared.connectedDevices - - if devices.isEmpty - { - self.devicesButton.addItem(withTitle: "No Connected Device") - } - else - { - for device in devices - { - self.devicesButton.addItem(withTitle: device.name) - } - } - - if let currentDevice = self.currentDevice, let index = devices.firstIndex(of: currentDevice) - { - self.devicesButton.selectItem(at: index) - } - else - { - self.currentDevice = devices.first - self.devicesButton.selectItem(at: 0) - } - } -} - -private extension ViewController -{ - @IBAction func installAltStore(_ sender: NSButton) - { - guard let device = self.currentDevice else { return } - guard !self.emailAddressTextField.stringValue.isEmpty, !self.passwordTextField.stringValue.isEmpty else { return } - - self.installAltStore(to: device) - } - - @IBAction func chooseDevice(_ sender: NSPopUpButton) - { - let devices = ALTDeviceManager.shared.connectedDevices - guard !devices.isEmpty else { return } - - let index = sender.indexOfSelectedItem - - let device = devices[index] - self.currentDevice = device - } -} - -private extension ViewController -{ - func installAltStore(to device: ALTDevice) + func installAltStore(to device: ALTDevice, appleID: String, password: String, completion: @escaping (Result) -> Void) { let destinationDirectoryURL = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) func finish(_ error: Error?, title: String = "") { DispatchQueue.main.async { - let alert = NSAlert() - if let error = error { - alert.messageText = title - alert.informativeText = error.localizedDescription + completion(.failure(error)) } else { - alert.messageText = NSLocalizedString("Successfully installed AltStore!", comment: "") + completion(.success(())) } - - alert.runModal() } try? FileManager.default.removeItem(at: destinationDirectoryURL) } - self.authenticate() { (result) in + self.authenticate(appleID: appleID, password: password) { (result) in do { let account = try result.get() + + let content = UNMutableNotificationContent() + content.title = String(format: NSLocalizedString("Installing AltStore to %@...", comment: ""), device.name) + + let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: nil) + UNUserNotificationCenter.current().add(request) + self.fetchTeam(for: account) { (result) in do { @@ -253,9 +174,9 @@ private extension ViewController downloadTask.resume() } - func authenticate(completionHandler: @escaping (Result) -> Void) + func authenticate(appleID: String, password: String, completionHandler: @escaping (Result) -> Void) { - ALTAppleAPI.shared.authenticate(appleID: self.emailAddressTextField.stringValue, password: self.passwordTextField.stringValue) { (account, error) in + ALTAppleAPI.shared.authenticate(appleID: appleID, password: password) { (account, error) in let result = Result(account, error) completionHandler(result) } diff --git a/AltServer/Devices/ALTDeviceManager.h b/AltServer/Devices/ALTDeviceManager.h index d3997432..8447b57d 100644 --- a/AltServer/Devices/ALTDeviceManager.h +++ b/AltServer/Devices/ALTDeviceManager.h @@ -16,6 +16,7 @@ NS_ASSUME_NONNULL_BEGIN @property (class, nonatomic, readonly) ALTDeviceManager *sharedManager; @property (nonatomic, readonly) NSArray *connectedDevices; +@property (nonatomic, readonly) NSArray *availableDevices; - (NSProgress *)installAppAtURL:(NSURL *)fileURL toDeviceWithUDID:(NSString *)udid completionHandler:(void (^)(BOOL success, NSError *_Nullable error))completionHandler; diff --git a/AltServer/Devices/ALTDeviceManager.mm b/AltServer/Devices/ALTDeviceManager.mm index 7d5bf67c..2d0dffa5 100644 --- a/AltServer/Devices/ALTDeviceManager.mm +++ b/AltServer/Devices/ALTDeviceManager.mm @@ -518,7 +518,17 @@ NSErrorDomain const ALTDeviceErrorDomain = @"com.rileytestut.ALTDeviceError"; - (NSArray *)connectedDevices { - NSMutableArray *connectedDevices = [NSMutableArray array]; + return [self availableDevicesIncludingNetworkDevices:NO]; +} + +- (NSArray *)availableDevices +{ + return [self availableDevicesIncludingNetworkDevices:YES]; +} + +- (NSArray *)availableDevicesIncludingNetworkDevices:(BOOL)includingNetworkDevices +{ + NSMutableSet *connectedDevices = [NSMutableSet set]; int count = 0; char **udids = NULL; @@ -533,11 +543,18 @@ NSErrorDomain const ALTDeviceErrorDomain = @"com.rileytestut.ALTDeviceError"; char *udid = udids[i]; idevice_t device = NULL; - idevice_new(&device, udid); + + if (includingNetworkDevices) + { + idevice_new(&device, udid); + } + else + { + idevice_new_ignore_network(&device, udid); + } if (!device) { - fprintf(stderr, "ERROR: No device with UDID %s attached.\n", udid); continue; } @@ -580,7 +597,7 @@ NSErrorDomain const ALTDeviceErrorDomain = @"com.rileytestut.ALTDeviceError"; idevice_device_list_free(udids); - return connectedDevices; + return connectedDevices.allObjects; } @end diff --git a/AltServer/Info.plist b/AltServer/Info.plist index 80297304..dc24eecc 100644 --- a/AltServer/Info.plist +++ b/AltServer/Info.plist @@ -26,6 +26,8 @@ Copyright © 2019 Riley Testut. All rights reserved. NSMainStoryboardFile Main + LSUIElement + NSPrincipalClass NSApplication diff --git a/AltStore.xcodeproj/project.pbxproj b/AltStore.xcodeproj/project.pbxproj index c53517f9..cf2b24e6 100644 --- a/AltStore.xcodeproj/project.pbxproj +++ b/AltStore.xcodeproj/project.pbxproj @@ -19,10 +19,10 @@ BF1E315A22A0620000370A3C /* NSError+ALTServerError.m in Sources */ = {isa = PBXBuildFile; fileRef = BF1E314922A060F400370A3C /* NSError+ALTServerError.m */; }; BF1E315F22A0635900370A3C /* libAltKit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BF1E315022A0616100370A3C /* libAltKit.a */; }; BF1E316022A0636400370A3C /* libAltKit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BF1E315022A0616100370A3C /* libAltKit.a */; }; + BF3F786422CAA41E008FBD20 /* ALTDeviceManager+Installation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3F786322CAA41E008FBD20 /* ALTDeviceManager+Installation.swift */; }; BF43002E22A714AF0051E2BC /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF43002D22A714AF0051E2BC /* Keychain.swift */; }; BF43003022A71C960051E2BC /* UserDefaults+AltStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF43002F22A71C960051E2BC /* UserDefaults+AltStore.swift */; }; BF458690229872EA00BD7491 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF45868F229872EA00BD7491 /* AppDelegate.swift */; }; - BF458692229872EA00BD7491 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF458691229872EA00BD7491 /* ViewController.swift */; }; BF458694229872EA00BD7491 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BF458693229872EA00BD7491 /* Assets.xcassets */; }; BF458697229872EA00BD7491 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BF458695229872EA00BD7491 /* Main.storyboard */; }; BF4586C52298CDB800BD7491 /* ALTDeviceManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = BF4586C42298CDB800BD7491 /* ALTDeviceManager.mm */; }; @@ -241,11 +241,11 @@ BF1E314822A060F400370A3C /* NSError+ALTServerError.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSError+ALTServerError.h"; sourceTree = ""; }; BF1E314922A060F400370A3C /* NSError+ALTServerError.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSError+ALTServerError.m"; sourceTree = ""; }; BF1E315022A0616100370A3C /* libAltKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libAltKit.a; sourceTree = BUILT_PRODUCTS_DIR; }; + BF3F786322CAA41E008FBD20 /* ALTDeviceManager+Installation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ALTDeviceManager+Installation.swift"; sourceTree = ""; }; BF43002D22A714AF0051E2BC /* Keychain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Keychain.swift; sourceTree = ""; }; BF43002F22A71C960051E2BC /* UserDefaults+AltStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+AltStore.swift"; sourceTree = ""; }; BF45868D229872EA00BD7491 /* AltServer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AltServer.app; sourceTree = BUILT_PRODUCTS_DIR; }; BF45868F229872EA00BD7491 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - BF458691229872EA00BD7491 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; BF458693229872EA00BD7491 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; BF458696229872EA00BD7491 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; BF458698229872EA00BD7491 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -469,7 +469,6 @@ children = ( BF45868F229872EA00BD7491 /* AppDelegate.swift */, BF458695229872EA00BD7491 /* Main.storyboard */, - BF458691229872EA00BD7491 /* ViewController.swift */, BF703195229F36FF006E110F /* Devices */, BFD52BDC22A0A659000B7ED1 /* Connections */, BF703194229F36F6006E110F /* Resources */, @@ -630,6 +629,7 @@ children = ( BF4586C32298CDB800BD7491 /* ALTDeviceManager.h */, BF4586C42298CDB800BD7491 /* ALTDeviceManager.mm */, + BF3F786322CAA41E008FBD20 /* ALTDeviceManager+Installation.swift */, ); path = Devices; sourceTree = ""; @@ -1121,7 +1121,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - BF458692229872EA00BD7491 /* ViewController.swift in Sources */, + BF3F786422CAA41E008FBD20 /* ALTDeviceManager+Installation.swift in Sources */, BF1E312B229F474900370A3C /* ConnectionManager.swift in Sources */, BF458690229872EA00BD7491 /* AppDelegate.swift in Sources */, BF4586C52298CDB800BD7491 /* ALTDeviceManager.mm in Sources */, diff --git a/Dependencies/libimobiledevice b/Dependencies/libimobiledevice index 7dc84af1..df4f2b0a 160000 --- a/Dependencies/libimobiledevice +++ b/Dependencies/libimobiledevice @@ -1 +1 @@ -Subproject commit 7dc84af1fbb54e5a591d60ed5fc4b8279d2bf39d +Subproject commit df4f2b0ac56479f8952e8159c9c64ab68a935301