mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-19 19:53:25 +01:00
[AltServer] Adds method to fetch installed apps on devices
This commit is contained in:
@@ -13,6 +13,8 @@
|
|||||||
@class ALTNotificationConnection;
|
@class ALTNotificationConnection;
|
||||||
@class ALTDebugConnection;
|
@class ALTDebugConnection;
|
||||||
|
|
||||||
|
@class ALTInstalledApp;
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
extern NSNotificationName const ALTDeviceManagerDeviceDidConnectNotification NS_SWIFT_NAME(deviceManagerDeviceDidConnect);
|
extern NSNotificationName const ALTDeviceManagerDeviceDidConnectNotification NS_SWIFT_NAME(deviceManagerDeviceDidConnect);
|
||||||
@@ -41,6 +43,9 @@ extern NSNotificationName const ALTDeviceManagerDeviceDidDisconnectNotification
|
|||||||
- (void)installDeveloperDiskImageAtURL:(NSURL *)diskURL signatureURL:(NSURL *)signatureURL toDevice:(ALTDevice *)device
|
- (void)installDeveloperDiskImageAtURL:(NSURL *)diskURL signatureURL:(NSURL *)signatureURL toDevice:(ALTDevice *)device
|
||||||
completionHandler:(void (^)(BOOL success, NSError *_Nullable error))completionHandler;
|
completionHandler:(void (^)(BOOL success, NSError *_Nullable error))completionHandler;
|
||||||
|
|
||||||
|
/* Apps */
|
||||||
|
- (void)fetchInstalledAppsOnDevice:(ALTDevice *)altDevice completionHandler:(void (^)(NSSet<ALTInstalledApp *> *_Nullable installedApps, NSError *_Nullable error))completionHandler;
|
||||||
|
|
||||||
/* Connections */
|
/* Connections */
|
||||||
- (void)startWiredConnectionToDevice:(ALTDevice *)device completionHandler:(void (^)(ALTWiredConnection *_Nullable connection, NSError *_Nullable error))completionHandler;
|
- (void)startWiredConnectionToDevice:(ALTDevice *)device completionHandler:(void (^)(ALTWiredConnection *_Nullable connection, NSError *_Nullable error))completionHandler;
|
||||||
- (void)startNotificationConnectionToDevice:(ALTDevice *)device completionHandler:(void (^)(ALTNotificationConnection *_Nullable connection, NSError *_Nullable error))completionHandler;
|
- (void)startNotificationConnectionToDevice:(ALTDevice *)device completionHandler:(void (^)(ALTNotificationConnection *_Nullable connection, NSError *_Nullable error))completionHandler;
|
||||||
|
|||||||
@@ -16,6 +16,10 @@
|
|||||||
#import "NSError+ALTServerError.h"
|
#import "NSError+ALTServerError.h"
|
||||||
#import "NSError+libimobiledevice.h"
|
#import "NSError+libimobiledevice.h"
|
||||||
|
|
||||||
|
#import <AppKit/AppKit.h>
|
||||||
|
#import <UserNotifications/UserNotifications.h>
|
||||||
|
#import "AltServer-Swift.h"
|
||||||
|
|
||||||
#include <libimobiledevice/libimobiledevice.h>
|
#include <libimobiledevice/libimobiledevice.h>
|
||||||
#include <libimobiledevice/lockdown.h>
|
#include <libimobiledevice/lockdown.h>
|
||||||
#include <libimobiledevice/installation_proxy.h>
|
#include <libimobiledevice/installation_proxy.h>
|
||||||
@@ -38,7 +42,9 @@ NSNotificationName const ALTDeviceManagerDeviceDidDisconnectNotification = @"ALT
|
|||||||
@property (nonatomic, readonly) NSMutableDictionary<NSUUID *, void (^)(NSError *)> *deletionCompletionHandlers;
|
@property (nonatomic, readonly) NSMutableDictionary<NSUUID *, void (^)(NSError *)> *deletionCompletionHandlers;
|
||||||
|
|
||||||
@property (nonatomic, readonly) NSMutableDictionary<NSUUID *, NSProgress *> *installationProgress;
|
@property (nonatomic, readonly) NSMutableDictionary<NSUUID *, NSProgress *> *installationProgress;
|
||||||
|
|
||||||
@property (nonatomic, readonly) dispatch_queue_t installationQueue;
|
@property (nonatomic, readonly) dispatch_queue_t installationQueue;
|
||||||
|
@property (nonatomic, readonly) dispatch_queue_t devicesQueue;
|
||||||
|
|
||||||
@property (nonatomic, readonly) NSMutableSet<ALTDevice *> *cachedDevices;
|
@property (nonatomic, readonly) NSMutableSet<ALTDevice *> *cachedDevices;
|
||||||
|
|
||||||
@@ -66,7 +72,9 @@ NSNotificationName const ALTDeviceManagerDeviceDidDisconnectNotification = @"ALT
|
|||||||
_deletionCompletionHandlers = [NSMutableDictionary dictionary];
|
_deletionCompletionHandlers = [NSMutableDictionary dictionary];
|
||||||
|
|
||||||
_installationProgress = [NSMutableDictionary dictionary];
|
_installationProgress = [NSMutableDictionary dictionary];
|
||||||
_installationQueue = dispatch_queue_create("com.rileytestut.AltServer.InstallationQueue", DISPATCH_QUEUE_SERIAL);
|
|
||||||
|
_installationQueue = dispatch_queue_create("com.rileytestut.AltServer.Installation", DISPATCH_QUEUE_SERIAL);
|
||||||
|
_devicesQueue = dispatch_queue_create("com.rileytestut.AltServer.Devices", DISPATCH_QUEUE_CONCURRENT_WITH_AUTORELEASE_POOL);
|
||||||
|
|
||||||
_cachedDevices = [NSMutableSet set];
|
_cachedDevices = [NSMutableSet set];
|
||||||
}
|
}
|
||||||
@@ -1195,6 +1203,113 @@ NSNotificationName const ALTDeviceManagerDeviceDidDisconnectNotification = @"ALT
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - Apps -
|
||||||
|
|
||||||
|
- (void)fetchInstalledAppsOnDevice:(ALTDevice *)altDevice completionHandler:(void (^)(NSSet<ALTInstalledApp *> *_Nullable installedApps, NSError *_Nullable error))completionHandler
|
||||||
|
{
|
||||||
|
__block idevice_t device = NULL;
|
||||||
|
__block instproxy_client_t ipc = NULL;
|
||||||
|
__block lockdownd_client_t client = NULL;
|
||||||
|
__block lockdownd_service_descriptor_t service = NULL;
|
||||||
|
__block plist_t options = NULL;
|
||||||
|
|
||||||
|
void (^finish)(NSSet<ALTInstalledApp *> *, NSError *) = ^(NSSet<ALTInstalledApp *> *installedApps, NSError *error) {
|
||||||
|
if (error != nil) {
|
||||||
|
NSLog(@"Notification Connection Error: %@", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options) {
|
||||||
|
instproxy_client_options_free(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (service) {
|
||||||
|
lockdownd_service_descriptor_free(service);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client) {
|
||||||
|
lockdownd_client_free(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ipc) {
|
||||||
|
instproxy_client_free(ipc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (device) {
|
||||||
|
idevice_free(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
completionHandler(installedApps, error);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Don't use installationQueue since this operation can potentially take a very long time and will block other operations.
|
||||||
|
// dispatch_async(self.installationQueue, ^{
|
||||||
|
dispatch_async(self.devicesQueue, ^{
|
||||||
|
/* Find Device */
|
||||||
|
if (idevice_new_with_options(&device, altDevice.identifier.UTF8String, (enum idevice_options)((int)IDEVICE_LOOKUP_NETWORK | (int)IDEVICE_LOOKUP_USBMUX)) != IDEVICE_E_SUCCESS)
|
||||||
|
{
|
||||||
|
return finish(nil, [NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorDeviceNotFound userInfo:nil]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(device, &client, "AltServer"))
|
||||||
|
{
|
||||||
|
return finish(nil, [NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorConnectionFailed userInfo:nil]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((lockdownd_start_service(client, "com.apple.mobile.installation_proxy", &service) != LOCKDOWN_E_SUCCESS) || !service)
|
||||||
|
{
|
||||||
|
return finish(nil, [NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorConnectionFailed userInfo:nil]);
|
||||||
|
}
|
||||||
|
|
||||||
|
instproxy_error_t err = instproxy_client_new(device, service, &ipc);
|
||||||
|
if (err != INSTPROXY_E_SUCCESS)
|
||||||
|
{
|
||||||
|
return finish(nil, [NSError errorWithInstallationProxyError:err device:altDevice]);
|
||||||
|
}
|
||||||
|
|
||||||
|
options = instproxy_client_options_new();
|
||||||
|
instproxy_client_options_add(options, "ApplicationType", "User", NULL);
|
||||||
|
|
||||||
|
plist_t plist = NULL;
|
||||||
|
err = instproxy_browse(ipc, options, &plist);
|
||||||
|
if (err != INSTPROXY_E_SUCCESS)
|
||||||
|
{
|
||||||
|
return finish(nil, [NSError errorWithInstallationProxyError:err device:altDevice]);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *plistXML = NULL;
|
||||||
|
uint32_t length = 0;
|
||||||
|
plist_to_xml(plist, &plistXML, &length);
|
||||||
|
|
||||||
|
NSData *plistData = [@(plistXML) dataUsingEncoding:NSUTF8StringEncoding];
|
||||||
|
free(plistXML);
|
||||||
|
plist_free(plist);
|
||||||
|
|
||||||
|
NSError *error = nil;
|
||||||
|
NSArray *appDictionaries = [NSPropertyListSerialization propertyListWithData:plistData options:0 format:nil error:&error];
|
||||||
|
if (appDictionaries == nil)
|
||||||
|
{
|
||||||
|
return finish(nil, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
NSMutableSet *installedApps = [NSMutableSet set];
|
||||||
|
for (NSDictionary *appInfo in appDictionaries)
|
||||||
|
{
|
||||||
|
if (appInfo[@"ALTBundleIdentifier"] != nil)
|
||||||
|
{
|
||||||
|
// Only return apps installed with AltStore.
|
||||||
|
|
||||||
|
ALTInstalledApp *installedApp = [[ALTInstalledApp alloc] initWithDictionary:appInfo];
|
||||||
|
if (installedApp)
|
||||||
|
{
|
||||||
|
[installedApps addObject:installedApp];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
finish(installedApps, nil);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - Connections -
|
#pragma mark - Connections -
|
||||||
|
|
||||||
- (void)startWiredConnectionToDevice:(ALTDevice *)altDevice completionHandler:(void (^)(ALTWiredConnection * _Nullable, NSError * _Nullable))completionHandler
|
- (void)startWiredConnectionToDevice:(ALTDevice *)altDevice completionHandler:(void (^)(ALTWiredConnection * _Nullable, NSError * _Nullable))completionHandler
|
||||||
|
|||||||
29
AltServer/InstalledApp.swift
Normal file
29
AltServer/InstalledApp.swift
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
//
|
||||||
|
// InstalledApp.swift
|
||||||
|
// AltServer
|
||||||
|
//
|
||||||
|
// Created by Riley Testut on 5/25/21.
|
||||||
|
// Copyright © 2021 Riley Testut. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
@objc(ALTInstalledApp) @objcMembers
|
||||||
|
class InstalledApp: NSObject, MenuDisplayable
|
||||||
|
{
|
||||||
|
let name: String
|
||||||
|
let bundleIdentifier: String
|
||||||
|
let executableName: String
|
||||||
|
|
||||||
|
init?(dictionary: [String: Any])
|
||||||
|
{
|
||||||
|
guard let name = dictionary[kCFBundleNameKey as String] as? String,
|
||||||
|
let bundleIdentifier = dictionary[kCFBundleIdentifierKey as String] as? String,
|
||||||
|
let executableName = dictionary[kCFBundleExecutableKey as String] as? String
|
||||||
|
else { return nil }
|
||||||
|
|
||||||
|
self.name = name
|
||||||
|
self.bundleIdentifier = bundleIdentifier
|
||||||
|
self.executableName = executableName
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -199,6 +199,7 @@
|
|||||||
BF8CAE4E248AEABA004D6CCE /* UIDevice+Jailbreak.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8CAE4D248AEABA004D6CCE /* UIDevice+Jailbreak.swift */; };
|
BF8CAE4E248AEABA004D6CCE /* UIDevice+Jailbreak.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8CAE4D248AEABA004D6CCE /* UIDevice+Jailbreak.swift */; };
|
||||||
BF8F69C222E659F700049BA1 /* AppContentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8F69C122E659F700049BA1 /* AppContentViewController.swift */; };
|
BF8F69C222E659F700049BA1 /* AppContentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8F69C122E659F700049BA1 /* AppContentViewController.swift */; };
|
||||||
BF8F69C422E662D300049BA1 /* AppViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8F69C322E662D300049BA1 /* AppViewController.swift */; };
|
BF8F69C422E662D300049BA1 /* AppViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8F69C322E662D300049BA1 /* AppViewController.swift */; };
|
||||||
|
BF904DEA265DAE9A00E86C2A /* InstalledApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF904DE9265DAE9A00E86C2A /* InstalledApp.swift */; };
|
||||||
BF989171250AABF4002ACF50 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BF989170250AABF4002ACF50 /* Assets.xcassets */; };
|
BF989171250AABF4002ACF50 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BF989170250AABF4002ACF50 /* Assets.xcassets */; };
|
||||||
BF989177250AABF4002ACF50 /* AltWidgetExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = BF989167250AABF3002ACF50 /* AltWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
BF989177250AABF4002ACF50 /* AltWidgetExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = BF989167250AABF3002ACF50 /* AltWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
BF98917E250AAC4F002ACF50 /* Countdown.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF98917C250AAC4F002ACF50 /* Countdown.swift */; };
|
BF98917E250AAC4F002ACF50 /* Countdown.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF98917C250AAC4F002ACF50 /* Countdown.swift */; };
|
||||||
@@ -667,6 +668,7 @@
|
|||||||
BF8CAE4D248AEABA004D6CCE /* UIDevice+Jailbreak.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDevice+Jailbreak.swift"; sourceTree = "<group>"; };
|
BF8CAE4D248AEABA004D6CCE /* UIDevice+Jailbreak.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDevice+Jailbreak.swift"; sourceTree = "<group>"; };
|
||||||
BF8F69C122E659F700049BA1 /* AppContentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppContentViewController.swift; sourceTree = "<group>"; };
|
BF8F69C122E659F700049BA1 /* AppContentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppContentViewController.swift; sourceTree = "<group>"; };
|
||||||
BF8F69C322E662D300049BA1 /* AppViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppViewController.swift; sourceTree = "<group>"; };
|
BF8F69C322E662D300049BA1 /* AppViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppViewController.swift; sourceTree = "<group>"; };
|
||||||
|
BF904DE9265DAE9A00E86C2A /* InstalledApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstalledApp.swift; sourceTree = "<group>"; };
|
||||||
BF989167250AABF3002ACF50 /* AltWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = AltWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
BF989167250AABF3002ACF50 /* AltWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = AltWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
BF989170250AABF4002ACF50 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
BF989170250AABF4002ACF50 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
BF989172250AABF4002ACF50 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
BF989172250AABF4002ACF50 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
@@ -978,6 +980,7 @@
|
|||||||
BFC712BA2512B9CF00AB5EBE /* PluginManager.swift */,
|
BFC712BA2512B9CF00AB5EBE /* PluginManager.swift */,
|
||||||
BFAD67A225E0854500D4C4D1 /* DeveloperDiskManager.swift */,
|
BFAD67A225E0854500D4C4D1 /* DeveloperDiskManager.swift */,
|
||||||
BFF0394A25F0551600BE607D /* MenuController.swift */,
|
BFF0394A25F0551600BE607D /* MenuController.swift */,
|
||||||
|
BF904DE9265DAE9A00E86C2A /* InstalledApp.swift */,
|
||||||
BF703195229F36FF006E110F /* Devices */,
|
BF703195229F36FF006E110F /* Devices */,
|
||||||
BFD52BDC22A0A659000B7ED1 /* Connections */,
|
BFD52BDC22A0A659000B7ED1 /* Connections */,
|
||||||
BF055B4A233B528B0086DEA9 /* Extensions */,
|
BF055B4A233B528B0086DEA9 /* Extensions */,
|
||||||
@@ -2295,6 +2298,7 @@
|
|||||||
BFECAC8124FD950B0077C41F /* ALTServerError+Conveniences.swift in Sources */,
|
BFECAC8124FD950B0077C41F /* ALTServerError+Conveniences.swift in Sources */,
|
||||||
BFECAC7F24FD950B0077C41F /* CodableServerError.swift in Sources */,
|
BFECAC7F24FD950B0077C41F /* CodableServerError.swift in Sources */,
|
||||||
BFECAC8624FD950B0077C41F /* Result+Conveniences.swift in Sources */,
|
BFECAC8624FD950B0077C41F /* Result+Conveniences.swift in Sources */,
|
||||||
|
BF904DEA265DAE9A00E86C2A /* InstalledApp.swift in Sources */,
|
||||||
BFF435D9255CBDAB00DD724F /* ALTApplication+AltStoreApp.swift in Sources */,
|
BFF435D9255CBDAB00DD724F /* ALTApplication+AltStoreApp.swift in Sources */,
|
||||||
BF718BD523C928A300A89F2D /* ALTNotificationConnection.mm in Sources */,
|
BF718BD523C928A300A89F2D /* ALTNotificationConnection.mm in Sources */,
|
||||||
BF1E312B229F474900370A3C /* RequestHandler.swift in Sources */,
|
BF1E312B229F474900370A3C /* RequestHandler.swift in Sources */,
|
||||||
|
|||||||
Reference in New Issue
Block a user