mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-09 06:43:25 +01:00
[AltServer] Supports “remove app” requests
Improves support for removing apps
This commit is contained in:
@@ -39,7 +39,9 @@ typedef NS_ERROR_ENUM(AltServerErrorDomain, ALTServerError)
|
||||
ALTServerErrorInvalidAnisetteData = 13,
|
||||
ALTServerErrorPluginNotFound = 14,
|
||||
|
||||
ALTServerErrorProfileNotFound = 15
|
||||
ALTServerErrorProfileNotFound = 15,
|
||||
|
||||
ALTServerErrorAppDeletionFailed = 16,
|
||||
};
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@@ -95,6 +95,9 @@ NSErrorUserInfoKey const ALTProvisioningProfileBundleIDErrorKey = @"bundleIdenti
|
||||
|
||||
case ALTServerErrorProfileNotFound:
|
||||
return [self profileErrorLocalizedDescriptionWithBaseDescription:NSLocalizedString(@"Could not find profile", "")];
|
||||
|
||||
case ALTServerErrorAppDeletionFailed:
|
||||
return NSLocalizedString(@"An error occured while removing the app.", @"");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ public enum ServerRequest: Decodable
|
||||
case beginInstallation(BeginInstallationRequest)
|
||||
case installProvisioningProfiles(InstallProvisioningProfilesRequest)
|
||||
case removeProvisioningProfiles(RemoveProvisioningProfilesRequest)
|
||||
case removeApp(RemoveAppRequest)
|
||||
case unknown(identifier: String, version: Int)
|
||||
|
||||
var identifier: String {
|
||||
@@ -34,6 +35,7 @@ public enum ServerRequest: Decodable
|
||||
case .beginInstallation(let request): return request.identifier
|
||||
case .installProvisioningProfiles(let request): return request.identifier
|
||||
case .removeProvisioningProfiles(let request): return request.identifier
|
||||
case .removeApp(let request): return request.identifier
|
||||
case .unknown(let identifier, _): return identifier
|
||||
}
|
||||
}
|
||||
@@ -46,6 +48,7 @@ public enum ServerRequest: Decodable
|
||||
case .beginInstallation(let request): return request.version
|
||||
case .installProvisioningProfiles(let request): return request.version
|
||||
case .removeProvisioningProfiles(let request): return request.version
|
||||
case .removeApp(let request): return request.version
|
||||
case .unknown(_, let version): return version
|
||||
}
|
||||
}
|
||||
@@ -85,6 +88,10 @@ public enum ServerRequest: Decodable
|
||||
let request = try RemoveProvisioningProfilesRequest(from: decoder)
|
||||
self = .removeProvisioningProfiles(request)
|
||||
|
||||
case "RemoveAppRequest":
|
||||
let request = try RemoveAppRequest(from: decoder)
|
||||
self = .removeApp(request)
|
||||
|
||||
default:
|
||||
self = .unknown(identifier: identifier, version: version)
|
||||
}
|
||||
@@ -97,6 +104,7 @@ public enum ServerResponse: Decodable
|
||||
case installationProgress(InstallationProgressResponse)
|
||||
case installProvisioningProfiles(InstallProvisioningProfilesResponse)
|
||||
case removeProvisioningProfiles(RemoveProvisioningProfilesResponse)
|
||||
case removeApp(RemoveAppResponse)
|
||||
case error(ErrorResponse)
|
||||
case unknown(identifier: String, version: Int)
|
||||
|
||||
@@ -107,6 +115,7 @@ public enum ServerResponse: Decodable
|
||||
case .installationProgress(let response): return response.identifier
|
||||
case .installProvisioningProfiles(let response): return response.identifier
|
||||
case .removeProvisioningProfiles(let response): return response.identifier
|
||||
case .removeApp(let response): return response.identifier
|
||||
case .error(let response): return response.identifier
|
||||
case .unknown(let identifier, _): return identifier
|
||||
}
|
||||
@@ -119,6 +128,7 @@ public enum ServerResponse: Decodable
|
||||
case .installationProgress(let response): return response.version
|
||||
case .installProvisioningProfiles(let response): return response.version
|
||||
case .removeProvisioningProfiles(let response): return response.version
|
||||
case .removeApp(let response): return response.version
|
||||
case .error(let response): return response.version
|
||||
case .unknown(_, let version): return version
|
||||
}
|
||||
@@ -155,6 +165,10 @@ public enum ServerResponse: Decodable
|
||||
let response = try RemoveProvisioningProfilesResponse(from: decoder)
|
||||
self = .removeProvisioningProfiles(response)
|
||||
|
||||
case "RemoveAppResponse":
|
||||
let response = try RemoveAppResponse(from: decoder)
|
||||
self = .removeApp(response)
|
||||
|
||||
case "ErrorResponse":
|
||||
let response = try ErrorResponse(from: decoder)
|
||||
self = .error(response)
|
||||
@@ -379,3 +393,28 @@ public struct RemoveProvisioningProfilesResponse: ServerMessageProtocol
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public struct RemoveAppRequest: ServerMessageProtocol
|
||||
{
|
||||
public var version = 1
|
||||
public var identifier = "RemoveAppRequest"
|
||||
|
||||
public var udid: String
|
||||
public var bundleIdentifier: String
|
||||
|
||||
public init(udid: String, bundleIdentifier: String)
|
||||
{
|
||||
self.udid = udid
|
||||
self.bundleIdentifier = bundleIdentifier
|
||||
}
|
||||
}
|
||||
|
||||
public struct RemoveAppResponse: ServerMessageProtocol
|
||||
{
|
||||
public var version = 1
|
||||
public var identifier = "RemoveAppResponse"
|
||||
|
||||
public init()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,6 +273,9 @@ private extension ConnectionManager
|
||||
case .success(.removeProvisioningProfiles(let request)):
|
||||
self.handleRemoveProvisioningProfilesRequest(request, for: connection)
|
||||
|
||||
case .success(.removeApp(let request)):
|
||||
self.handleRemoveAppRequest(request, for: connection)
|
||||
|
||||
case .success(.unknown):
|
||||
let response = ErrorResponse(error: ALTServerError(.unknownRequest))
|
||||
connection.send(response, shouldDisconnect: true) { (result) in
|
||||
@@ -485,7 +488,31 @@ private extension ConnectionManager
|
||||
|
||||
let response = RemoveProvisioningProfilesResponse()
|
||||
connection.send(response, shouldDisconnect: true) { (result) in
|
||||
print("Sent remove profiles error response to \(connection) with result:", result)
|
||||
print("Sent remove profiles success response to \(connection) with result:", result)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handleRemoveAppRequest(_ request: RemoveAppRequest, for connection: ClientConnection)
|
||||
{
|
||||
ALTDeviceManager.shared.removeApp(forBundleIdentifier: request.bundleIdentifier, fromDeviceWithUDID: request.udid) { (success, error) in
|
||||
if let error = error, !success
|
||||
{
|
||||
print("Failed to remove app \(request.bundleIdentifier):", error)
|
||||
|
||||
let errorResponse = ErrorResponse(error: ALTServerError(error))
|
||||
connection.send(errorResponse, shouldDisconnect: true) { (result) in
|
||||
print("Sent remove a[[ error response with result:", result)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
print("Removed app:", request.bundleIdentifier)
|
||||
|
||||
let response = RemoveAppResponse()
|
||||
connection.send(response, shouldDisconnect: true) { (result) in
|
||||
print("Sent remove app success response to \(connection) with result:", result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ extern NSNotificationName const ALTDeviceManagerDeviceDidDisconnectNotification
|
||||
|
||||
/* App Installation */
|
||||
- (NSProgress *)installAppAtURL:(NSURL *)fileURL toDeviceWithUDID:(NSString *)udid activeProvisioningProfiles:(nullable NSSet<NSString *> *)activeProvisioningProfiles completionHandler:(void (^)(BOOL success, NSError *_Nullable error))completionHandler;
|
||||
- (void)removeAppForBundleIdentifier:(NSString *)bundleIdentifier fromDeviceWithUDID:(NSString *)udid completionHandler:(void (^)(BOOL success, NSError *_Nullable error))completionHandler;
|
||||
|
||||
- (void)installProvisioningProfiles:(NSSet<ALTProvisioningProfile *> *)provisioningProfiles toDeviceWithUDID:(NSString *)udid activeProvisioningProfiles:(nullable NSSet<NSString *> *)activeProvisioningProfiles completionHandler:(void (^)(BOOL success, NSError *_Nullable error))completionHandler;
|
||||
- (void)removeProvisioningProfilesForBundleIdentifiers:(NSSet<NSString *> *)bundleIdentifiers fromDeviceWithUDID:(NSString *)udid completionHandler:(void (^)(BOOL success, NSError *_Nullable error))completionHandler;
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <libimobiledevice/misagent.h>
|
||||
|
||||
void ALTDeviceManagerUpdateStatus(plist_t command, plist_t status, void *udid);
|
||||
void ALTDeviceManagerUpdateAppDeletionStatus(plist_t command, plist_t status, void *uuid);
|
||||
void ALTDeviceDidChangeConnectionStatus(const idevice_event_t *event, void *user_data);
|
||||
|
||||
NSNotificationName const ALTDeviceManagerDeviceDidConnectNotification = @"ALTDeviceManagerDeviceDidConnectNotification";
|
||||
@@ -28,6 +29,8 @@ NSNotificationName const ALTDeviceManagerDeviceDidDisconnectNotification = @"ALT
|
||||
@interface ALTDeviceManager ()
|
||||
|
||||
@property (nonatomic, readonly) NSMutableDictionary<NSUUID *, void (^)(NSError *)> *installationCompletionHandlers;
|
||||
@property (nonatomic, readonly) NSMutableDictionary<NSUUID *, void (^)(NSError *)> *deletionCompletionHandlers;
|
||||
|
||||
@property (nonatomic, readonly) NSMutableDictionary<NSUUID *, NSProgress *> *installationProgress;
|
||||
@property (nonatomic, readonly) dispatch_queue_t installationQueue;
|
||||
|
||||
@@ -54,8 +57,9 @@ NSNotificationName const ALTDeviceManagerDeviceDidDisconnectNotification = @"ALT
|
||||
if (self)
|
||||
{
|
||||
_installationCompletionHandlers = [NSMutableDictionary dictionary];
|
||||
_installationProgress = [NSMutableDictionary dictionary];
|
||||
_deletionCompletionHandlers = [NSMutableDictionary dictionary];
|
||||
|
||||
_installationProgress = [NSMutableDictionary dictionary];
|
||||
_installationQueue = dispatch_queue_create("com.rileytestut.AltServer.InstallationQueue", DISPATCH_QUEUE_SERIAL);
|
||||
|
||||
_cachedDevices = [NSMutableSet set];
|
||||
@@ -498,6 +502,87 @@ NSNotificationName const ALTDeviceManagerDeviceDidDisconnectNotification = @"ALT
|
||||
return success;
|
||||
}
|
||||
|
||||
- (void)removeAppForBundleIdentifier:(NSString *)bundleIdentifier fromDeviceWithUDID:(NSString *)udid completionHandler:(void (^)(BOOL success, NSError *_Nullable error))completionHandler
|
||||
{
|
||||
__block idevice_t device = NULL;
|
||||
__block lockdownd_client_t client = NULL;
|
||||
__block instproxy_client_t ipc = NULL;
|
||||
__block lockdownd_service_descriptor_t service = NULL;
|
||||
|
||||
void (^finish)(NSError *error) = ^(NSError *e) {
|
||||
__block NSError *error = e;
|
||||
|
||||
lockdownd_service_descriptor_free(service);
|
||||
instproxy_client_free(ipc);
|
||||
lockdownd_client_free(client);
|
||||
idevice_free(device);
|
||||
|
||||
if (error != nil)
|
||||
{
|
||||
completionHandler(NO, error);
|
||||
}
|
||||
else
|
||||
{
|
||||
completionHandler(YES, nil);
|
||||
}
|
||||
};
|
||||
|
||||
/* Find Device */
|
||||
if (idevice_new(&device, udid.UTF8String) != IDEVICE_E_SUCCESS)
|
||||
{
|
||||
return finish([NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorDeviceNotFound userInfo:nil]);
|
||||
}
|
||||
|
||||
/* Connect to Device */
|
||||
if (lockdownd_client_new_with_handshake(device, &client, "altserver") != LOCKDOWN_E_SUCCESS)
|
||||
{
|
||||
return finish([NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorConnectionFailed userInfo:nil]);
|
||||
}
|
||||
|
||||
/* Connect to Installation Proxy */
|
||||
if ((lockdownd_start_service(client, "com.apple.mobile.installation_proxy", &service) != LOCKDOWN_E_SUCCESS) || service == NULL)
|
||||
{
|
||||
return finish([NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorConnectionFailed userInfo:nil]);
|
||||
}
|
||||
|
||||
if (instproxy_client_new(device, service, &ipc) != INSTPROXY_E_SUCCESS)
|
||||
{
|
||||
return finish([NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorConnectionFailed userInfo:nil]);
|
||||
}
|
||||
|
||||
if (service)
|
||||
{
|
||||
lockdownd_service_descriptor_free(service);
|
||||
service = NULL;
|
||||
}
|
||||
|
||||
NSUUID *UUID = [NSUUID UUID];
|
||||
__block char *uuidString = (char *)malloc(UUID.UUIDString.length + 1);
|
||||
strncpy(uuidString, (const char *)UUID.UUIDString.UTF8String, UUID.UUIDString.length);
|
||||
uuidString[UUID.UUIDString.length] = '\0';
|
||||
|
||||
self.deletionCompletionHandlers[UUID] = ^(NSError *error) {
|
||||
if (error != nil)
|
||||
{
|
||||
NSString *localizedFailure = [NSString stringWithFormat:NSLocalizedString(@"Could not remove “%@”.", @""), bundleIdentifier];
|
||||
|
||||
NSMutableDictionary *userInfo = [error.userInfo mutableCopy];
|
||||
userInfo[NSLocalizedFailureErrorKey] = localizedFailure;
|
||||
|
||||
NSError *localizedError = [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo];
|
||||
finish(localizedError);
|
||||
}
|
||||
else
|
||||
{
|
||||
finish(nil);
|
||||
}
|
||||
|
||||
free(uuidString);
|
||||
};
|
||||
|
||||
instproxy_uninstall(ipc, bundleIdentifier.UTF8String, NULL, ALTDeviceManagerUpdateAppDeletionStatus, uuidString);
|
||||
}
|
||||
|
||||
#pragma mark - Provisioning Profiles -
|
||||
|
||||
- (void)installProvisioningProfiles:(NSSet<ALTProvisioningProfile *> *)provisioningProfiles toDeviceWithUDID:(NSString *)udid activeProvisioningProfiles:(nullable NSSet<NSString *> *)activeProvisioningProfiles completionHandler:(void (^)(BOOL success, NSError *error))completionHandler
|
||||
@@ -1117,6 +1202,43 @@ void ALTDeviceManagerUpdateStatus(plist_t command, plist_t status, void *uuid)
|
||||
}
|
||||
}
|
||||
|
||||
void ALTDeviceManagerUpdateAppDeletionStatus(plist_t command, plist_t status, void *uuid)
|
||||
{
|
||||
NSUUID *UUID = [[NSUUID alloc] initWithUUIDString:[NSString stringWithUTF8String:(const char *)uuid]];
|
||||
|
||||
char *statusName = NULL;
|
||||
instproxy_status_get_name(status, &statusName);
|
||||
|
||||
char *errorName = NULL;
|
||||
char *errorDescription = NULL;
|
||||
uint64_t code = 0;
|
||||
instproxy_status_get_error(status, &errorName, &errorDescription, &code);
|
||||
|
||||
if ([@(statusName) isEqualToString:@"Complete"] || code != 0 || errorName != NULL)
|
||||
{
|
||||
void (^completionHandler)(NSError *) = ALTDeviceManager.sharedManager.deletionCompletionHandlers[UUID];
|
||||
if (completionHandler != nil)
|
||||
{
|
||||
if (code != 0 || errorName != NULL)
|
||||
{
|
||||
NSLog(@"Error removing app. %@ (%@). %@", @(code), @(errorName ?: ""), @(errorDescription ?: ""));
|
||||
|
||||
NSError *underlyingError = [NSError errorWithDomain:AltServerInstallationErrorDomain code:code userInfo:@{NSLocalizedDescriptionKey: @(errorDescription ?: "")}];
|
||||
NSError *error = [NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorAppDeletionFailed userInfo:@{NSUnderlyingErrorKey: underlyingError}];
|
||||
|
||||
completionHandler(error);
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"Finished removing app!");
|
||||
completionHandler(nil);
|
||||
}
|
||||
|
||||
ALTDeviceManager.sharedManager.deletionCompletionHandlers[UUID] = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ALTDeviceDidChangeConnectionStatus(const idevice_event_t *event, void *user_data)
|
||||
{
|
||||
ALTDevice * (^deviceForUDID)(NSString *, NSArray<ALTDevice *> *) = ^ALTDevice *(NSString *udid, NSArray<ALTDevice *> *devices) {
|
||||
|
||||
Reference in New Issue
Block a user