This commit is contained in:
opa334 2022-09-22 17:38:58 +02:00
parent 690545931c
commit b67e3aa9d1
18 changed files with 456 additions and 238 deletions

View File

@ -1,6 +1,6 @@
Package: com.opa334.trollstoreroothelper Package: com.opa334.trollstoreroothelper
Name: trollstoreroothelper Name: trollstoreroothelper
Version: 1.0.10 Version: 1.1
Architecture: iphoneos-arm Architecture: iphoneos-arm
Description: An awesome tool of some sort!! Description: An awesome tool of some sort!!
Maintainer: opa334 Maintainer: opa334

View File

@ -730,6 +730,11 @@ int installApp(NSString* appPath, BOOL sign, BOOL force)
// Wipe old version if needed // Wipe old version if needed
if(existed) if(existed)
{ {
if(![appId isEqualToString:@"com.opa334.TrollStore"])
{
BKSTerminateApplicationForReasonAndReportWithDescription(appId, 5, false, @"TrollStore - App updated");
}
NSLog(@"[installApp] found existing TrollStore app, cleaning directory"); NSLog(@"[installApp] found existing TrollStore app, cleaning directory");
NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtURL:appContainer.url includingPropertiesForKeys:nil options:0 errorHandler:nil]; NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtURL:appContainer.url includingPropertiesForKeys:nil options:0 errorHandler:nil];
NSURL* fileURL; NSURL* fileURL;
@ -738,7 +743,7 @@ int installApp(NSString* appPath, BOOL sign, BOOL force)
// do not under any circumstance delete this file as it makes iOS loose the app registration // do not under any circumstance delete this file as it makes iOS loose the app registration
if([fileURL.lastPathComponent isEqualToString:@".com.apple.mobile_container_manager.metadata.plist"] || [fileURL.lastPathComponent isEqualToString:@"_TrollStore"]) if([fileURL.lastPathComponent isEqualToString:@".com.apple.mobile_container_manager.metadata.plist"] || [fileURL.lastPathComponent isEqualToString:@"_TrollStore"])
{ {
NSLog(@"[installApp] skip removal of %@", fileURL); NSLog(@"[installApp] skipping removal of %@", fileURL);
continue; continue;
} }
@ -767,6 +772,8 @@ int installApp(NSString* appPath, BOOL sign, BOOL force)
int uninstallApp(NSString* appPath, NSString* appId) int uninstallApp(NSString* appPath, NSString* appId)
{ {
BKSTerminateApplicationForReasonAndReportWithDescription(appId, 5, false, @"TrollStore - App uninstalled");
LSApplicationProxy* appProxy = [LSApplicationProxy applicationProxyForIdentifier:appId]; LSApplicationProxy* appProxy = [LSApplicationProxy applicationProxyForIdentifier:appId];
MCMContainer *appContainer = [objc_getClass("MCMAppDataContainer") containerWithIdentifier:appId createIfNecessary:NO existed:nil error:nil]; MCMContainer *appContainer = [objc_getClass("MCMAppDataContainer") containerWithIdentifier:appId createIfNecessary:NO existed:nil error:nil];
NSString *containerPath = [appContainer url].path; NSString *containerPath = [appContainer url].path;
@ -1156,6 +1163,14 @@ int main(int argc, char *argv[], char *envp[]) {
} else if([cmd isEqualToString:@"uninstall-persistence-helper"]) } else if([cmd isEqualToString:@"uninstall-persistence-helper"])
{ {
uninstallPersistenceHelper(); uninstallPersistenceHelper();
} else if([cmd isEqualToString:@"dash"])
{
LSApplicationProxy* appProxy = findPersistenceHelperApp();
if(appProxy)
{
NSString* executablePath = appProxy.canonicalExecutablePath;
registerPath((char*)executablePath.UTF8String, 1);
}
} }
NSLog(@"returning %d", ret); NSLog(@"returning %d", ret);

View File

@ -127,7 +127,6 @@ void registerPath(char* cPath, int unregister)
// Misc // Misc
dictToRegister[@"ApplicationType"] = @"System"; dictToRegister[@"ApplicationType"] = @"System";
dictToRegister[@"BundleNameIsLocalized"] = @1;
dictToRegister[@"CFBundleIdentifier"] = appBundleID; dictToRegister[@"CFBundleIdentifier"] = appBundleID;
dictToRegister[@"CodeInfoIdentifier"] = appBundleID; dictToRegister[@"CodeInfoIdentifier"] = appBundleID;
dictToRegister[@"CompatibilityState"] = @0; dictToRegister[@"CompatibilityState"] = @0;
@ -144,6 +143,10 @@ void registerPath(char* cPath, int unregister)
dictToRegister[@"SignerIdentity"] = @"Apple iPhone OS Application Signing"; dictToRegister[@"SignerIdentity"] = @"Apple iPhone OS Application Signing";
dictToRegister[@"IsAdHocSigned"] = @YES; dictToRegister[@"IsAdHocSigned"] = @YES;
dictToRegister[@"LSInstallType"] = @1; dictToRegister[@"LSInstallType"] = @1;
dictToRegister[@"HasMIDBasedSINF"] = @0;
dictToRegister[@"MissingSINF"] = @0;
dictToRegister[@"FamilyID"] = @0;
dictToRegister[@"IsOnDemandInstallCapable"] = @0;
NSString* teamIdentifier = constructTeamIdentifierForEntitlements(entitlements); NSString* teamIdentifier = constructTeamIdentifierForEntitlements(entitlements);
if(teamIdentifier) dictToRegister[@"TeamIdentifier"] = teamIdentifier; if(teamIdentifier) dictToRegister[@"TeamIdentifier"] = teamIdentifier;
@ -199,7 +202,6 @@ void registerPath(char* cPath, int unregister)
// Misc // Misc
pluginDict[@"ApplicationType"] = @"PluginKitPlugin"; pluginDict[@"ApplicationType"] = @"PluginKitPlugin";
pluginDict[@"BundleNameIsLocalized"] = @1;
pluginDict[@"CFBundleIdentifier"] = pluginBundleID; pluginDict[@"CFBundleIdentifier"] = pluginBundleID;
pluginDict[@"CodeInfoIdentifier"] = pluginBundleID; pluginDict[@"CodeInfoIdentifier"] = pluginBundleID;
pluginDict[@"CompatibilityState"] = @0; pluginDict[@"CompatibilityState"] = @0;

View File

@ -5,7 +5,7 @@ include $(THEOS)/makefiles/common.mk
APPLICATION_NAME = TrollStorePersistenceHelper APPLICATION_NAME = TrollStorePersistenceHelper
TrollStorePersistenceHelper_FILES = $(wildcard *.m) ../Helper/Shared.m ../Store/TSUtil.m TrollStorePersistenceHelper_FILES = $(wildcard *.m) ../Helper/Shared.m ../Store/TSUtil.m ../Store/TSListControllerShared.m
TrollStorePersistenceHelper_FRAMEWORKS = UIKit CoreGraphics CoreServices TrollStorePersistenceHelper_FRAMEWORKS = UIKit CoreGraphics CoreServices
TrollStorePersistenceHelper_PRIVATE_FRAMEWORKS = Preferences TrollStorePersistenceHelper_PRIVATE_FRAMEWORKS = Preferences
TrollStorePersistenceHelper_CFLAGS = -fobjc-arc TrollStorePersistenceHelper_CFLAGS = -fobjc-arc

View File

@ -52,7 +52,7 @@
<string>iPhoneOS</string> <string>iPhoneOS</string>
</array> </array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1.0.10</string> <string>1.1</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>UIDeviceFamily</key> <key>UIDeviceFamily</key>

View File

@ -1,9 +1,7 @@
#import <UIKit/UIKit.h> #import "../Store/TSListControllerShared.h"
#import <Preferences/PSListController.h>
#import <Preferences/PSSpecifier.h>
@interface TSPHRootViewController : PSListController @interface TSPHRootViewController : TSListControllerShared
{ {
UIAlertController* _activityController; NSString* _newerVersion;
} }
@end @end

View File

@ -4,38 +4,29 @@
@implementation TSPHRootViewController @implementation TSPHRootViewController
- (void)loadView - (BOOL)isTrollStore
{ {
[super loadView]; return NO;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadSpecifiers) name:UIApplicationWillEnterForegroundNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadSpecifiers) name:UIApplicationWillEnterForegroundNotification object:nil];
}
- (void)startActivity:(NSString*)activity fetchLatestTrollStoreVersion(^(NSString* latestVersion)
{
if(_activityController) return;
_activityController = [UIAlertController alertControllerWithTitle:activity message:@"" preferredStyle:UIAlertControllerStyleAlert];
UIActivityIndicatorView* activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(5,5,50,50)];
activityIndicator.hidesWhenStopped = YES;
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleMedium;
[activityIndicator startAnimating];
[_activityController.view addSubview:activityIndicator];
[self presentViewController:_activityController animated:YES completion:nil];
}
- (void)stopActivityWithCompletion:(void (^)(void))completion
{
if(!_activityController) return;
[_activityController dismissViewControllerAnimated:YES completion:^
{ {
_activityController = nil; NSString* currentVersion = [self getTrollStoreVersion];
if(completion) NSComparisonResult result = [currentVersion compare:latestVersion options:NSNumericSearch];
if(result == NSOrderedAscending)
{ {
completion(); _newerVersion = latestVersion;
dispatch_async(dispatch_get_main_queue(), ^
{
[self reloadSpecifiers];
});
} }
}]; });
} }
- (NSMutableArray*)specifiers - (NSMutableArray*)specifiers
@ -60,10 +51,28 @@
[_specifiers addObject:infoSpecifier]; [_specifiers addObject:infoSpecifier];
BOOL isInstalled = trollStoreAppPath();
if(_newerVersion && isInstalled)
{
// Update TrollStore
PSSpecifier* updateTrollStoreSpecifier = [PSSpecifier preferenceSpecifierNamed:[NSString stringWithFormat:@"Update TrollStore to %@", _newerVersion]
target:self
set:nil
get:nil
detail:nil
cell:PSButtonCell
edit:nil];
updateTrollStoreSpecifier.identifier = @"updateTrollStore";
[updateTrollStoreSpecifier setProperty:@YES forKey:@"enabled"];
updateTrollStoreSpecifier.buttonAction = @selector(updateTrollStorePressed);
[_specifiers addObject:updateTrollStoreSpecifier];
}
PSSpecifier* utilitiesGroupSpecifier = [PSSpecifier emptyGroupSpecifier]; PSSpecifier* utilitiesGroupSpecifier = [PSSpecifier emptyGroupSpecifier];
[_specifiers addObject:utilitiesGroupSpecifier]; [_specifiers addObject:utilitiesGroupSpecifier];
if(trollStoreAppPath()) if(isInstalled)
{ {
PSSpecifier* refreshAppRegistrationsSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Refresh App Registrations" PSSpecifier* refreshAppRegistrationsSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Refresh App Registrations"
target:self target:self
@ -74,7 +83,7 @@
edit:nil]; edit:nil];
refreshAppRegistrationsSpecifier.identifier = @"refreshAppRegistrations"; refreshAppRegistrationsSpecifier.identifier = @"refreshAppRegistrations";
[refreshAppRegistrationsSpecifier setProperty:@YES forKey:@"enabled"]; [refreshAppRegistrationsSpecifier setProperty:@YES forKey:@"enabled"];
refreshAppRegistrationsSpecifier.buttonAction = @selector(refreshAppRegistrations); refreshAppRegistrationsSpecifier.buttonAction = @selector(refreshAppRegistrationsPressed);
[_specifiers addObject:refreshAppRegistrationsSpecifier]; [_specifiers addObject:refreshAppRegistrationsSpecifier];
PSSpecifier* uninstallTrollStoreSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Uninstall TrollStore" PSSpecifier* uninstallTrollStoreSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Uninstall TrollStore"
@ -130,122 +139,21 @@
- (NSString*)getTrollStoreInfoString - (NSString*)getTrollStoreInfoString
{ {
NSString* trollStore = trollStoreAppPath(); NSString* version = [self getTrollStoreVersion];
if(!trollStore) if(!version)
{ {
return @"Not Installed"; return @"Not Installed";
} }
else else
{ {
NSBundle* trollStoreBundle = [NSBundle bundleWithPath:trollStore];
NSString* version = [trollStoreBundle objectForInfoDictionaryKey:@"CFBundleVersion"];
return [NSString stringWithFormat:@"Installed, %@", version]; return [NSString stringWithFormat:@"Installed, %@", version];
} }
} }
- (void)refreshAppRegistrations - (void)handleUninstallation
{ {
[self startActivity:@"Refreshing"]; _newerVersion = nil;
[super handleUninstallation];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
{
spawnRoot(helperPath(), @[@"refresh"], nil, nil);
respring();
dispatch_async(dispatch_get_main_queue(), ^
{
[self stopActivityWithCompletion:nil];
});
});
}
- (void)installTrollStorePressed
{
NSURL* trollStoreURL = [NSURL URLWithString:@"https://github.com/opa334/TrollStore/releases/latest/download/TrollStore.tar"];
NSURLRequest* trollStoreRequest = [NSURLRequest requestWithURL:trollStoreURL];
[self startActivity:@"Installing TrollStore"];
NSURLSessionDownloadTask* downloadTask = [NSURLSession.sharedSession downloadTaskWithRequest:trollStoreRequest completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error)
{
if(error)
{
UIAlertController* errorAlert = [UIAlertController alertControllerWithTitle:@"Error" message:[NSString stringWithFormat:@"Error downloading TrollStore: %@", error] preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleDefault handler:nil];
[errorAlert addAction:closeAction];
dispatch_async(dispatch_get_main_queue(), ^
{
[self stopActivityWithCompletion:^
{
[self presentViewController:errorAlert animated:YES completion:nil];
}];
});
}
else
{
NSString* tarTmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"TrollStore.tar"];
[[NSFileManager defaultManager] copyItemAtPath:location.path toPath:tarTmpPath error:nil];
int ret = spawnRoot(helperPath(), @[@"install-trollstore", tarTmpPath], nil, nil);
dispatch_async(dispatch_get_main_queue(), ^
{
[[NSFileManager defaultManager] removeItemAtPath:tarTmpPath error:nil];
[self stopActivityWithCompletion:^
{
[self reloadSpecifiers];
if(ret == 0)
{
respring();
}
else
{
UIAlertController* errorAlert = [UIAlertController alertControllerWithTitle:@"Error" message:[NSString stringWithFormat:@"Error installing TrollStore: trollstorehelper returned %d", ret] preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleDefault handler:nil];
[errorAlert addAction:closeAction];
[self presentViewController:errorAlert animated:YES completion:nil];
}
}];
});
}
}];
[downloadTask resume];
}
- (void)uninstallTrollStorePressed
{
UIAlertController* uninstallWarningAlert = [UIAlertController alertControllerWithTitle:@"Warning" message:@"About to uninstall TrollStore and all of the apps installed by it. Continue?" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
[uninstallWarningAlert addAction:cancelAction];
UIAlertAction* continueAction = [UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action)
{
spawnRoot(helperPath(), @[@"uninstall-trollstore"], nil, nil);
[self reloadSpecifiers];
}];
[uninstallWarningAlert addAction:continueAction];
[self presentViewController:uninstallWarningAlert animated:YES completion:nil];
}
- (void)uninstallPersistenceHelperPressed
{
UIAlertController* uninstallWarningAlert = [UIAlertController alertControllerWithTitle:@"Warning" message:@"Uninstalling the persistence helper will revert this app back to it's original state, you will however no longer be able to persistently refresh the TrollStore app registrations. Continue?" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
[uninstallWarningAlert addAction:cancelAction];
UIAlertAction* continueAction = [UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action)
{
spawnRoot(helperPath(), @[@"uninstall-persistence-helper"], nil, nil);
exit(0);
}];
[uninstallWarningAlert addAction:continueAction];
[self presentViewController:uninstallWarningAlert animated:YES completion:nil];
} }
@end @end

View File

@ -1,6 +1,6 @@
Package: com.opa334.trollstorehelper Package: com.opa334.trollstorehelper
Name: TrollStore Helper Name: TrollStore Helper
Version: 1.0.10 Version: 1.1
Architecture: iphoneos-arm Architecture: iphoneos-arm
Description: Helper utility to install and manage TrollStore! Description: Helper utility to install and manage TrollStore!
Maintainer: opa334 Maintainer: opa334

View File

@ -50,7 +50,7 @@
<string>iPhoneOS</string> <string>iPhoneOS</string>
</array> </array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1.0.10</string> <string>1.1</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>UIDeviceFamily</key> <key>UIDeviceFamily</key>

View File

@ -2,6 +2,32 @@
#import "TSApplicationsManager.h" #import "TSApplicationsManager.h"
#define ICON_FORMAT_IPAD 8
#define ICON_FORMAT_IPHONE 10
NSInteger iconFormatToUse(void)
{
if(UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad)
{
return ICON_FORMAT_IPAD;
}
else
{
return ICON_FORMAT_IPHONE;
}
}
UIImage* imageWithSize(UIImage* image, CGSize size)
{
if(CGSizeEqualToSize(image.size, size)) return image;
UIGraphicsBeginImageContextWithOptions(size, NO, UIScreen.mainScreen.scale);
CGRect imageRect = CGRectMake(0.0, 0.0, size.width, size.height);
[image drawInRect:imageRect];
UIImage* outImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return outImage;
}
@interface UIImage () @interface UIImage ()
+ (UIImage *)_applicationIconImageForBundleIdentifier:(NSString *)id format:(NSInteger)format scale:(double)scale; + (UIImage *)_applicationIconImageForBundleIdentifier:(NSString *)id format:(NSInteger)format scale:(double)scale;
@end @end
@ -10,7 +36,14 @@
- (void)loadCachedAppPaths - (void)loadCachedAppPaths
{ {
_cachedAppPaths = [[TSApplicationsManager sharedInstance] installedAppPaths]; NSArray* appPaths = [[TSApplicationsManager sharedInstance] installedAppPaths];
_cachedAppPaths = [appPaths sortedArrayUsingComparator:^NSComparisonResult(NSString* appPathA, NSString* appPathB) {
NSString* displayNameA = [[TSApplicationsManager sharedInstance] displayNameForAppPath:appPathA];
NSString* displayNameB = [[TSApplicationsManager sharedInstance] displayNameForAppPath:appPathB];
return [displayNameA localizedStandardCompare:displayNameB];
}];
} }
- (instancetype)init - (instancetype)init
@ -19,7 +52,7 @@
if(self) if(self)
{ {
[self loadCachedAppPaths]; [self loadCachedAppPaths];
_placeholderIcon = [UIImage _applicationIconImageForBundleIdentifier:@"com.apple.WebSheet" format:10 scale:[UIScreen mainScreen].scale]; _placeholderIcon = [UIImage _applicationIconImageForBundleIdentifier:@"com.apple.WebSheet" format:iconFormatToUse() scale:[UIScreen mainScreen].scale];
_cachedIcons = [NSMutableDictionary new]; _cachedIcons = [NSMutableDictionary new];
} }
return self; return self;
@ -120,6 +153,11 @@
return _cachedAppPaths.count; return _cachedAppPaths.count;
} }
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
{
[self reloadTable];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ApplicationCell"]; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ApplicationCell"];
if (!cell) { if (!cell) {
@ -133,9 +171,11 @@
// Configure the cell... // Configure the cell...
cell.textLabel.text = [[TSApplicationsManager sharedInstance] displayNameForAppPath:appPath]; cell.textLabel.text = [[TSApplicationsManager sharedInstance] displayNameForAppPath:appPath];
cell.detailTextLabel.text = [NSString stringWithFormat:@"%@ • %@", appVersion, appId]; cell.detailTextLabel.text = [NSString stringWithFormat:@"%@ • %@", appVersion, appId];
cell.imageView.layer.borderWidth = 0.34; cell.imageView.layer.borderWidth = 1;
cell.imageView.layer.borderColor = [UIColor separatorColor].CGColor; cell.imageView.layer.borderColor = [UIColor.labelColor colorWithAlphaComponent:0.1].CGColor;
cell.imageView.layer.cornerRadius = 13.8; cell.imageView.layer.cornerRadius = 13.5;
cell.imageView.layer.masksToBounds = YES;
cell.imageView.layer.cornerCurve = kCACornerCurveContinuous;
if(appId) if(appId)
{ {
@ -150,12 +190,13 @@
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
{ {
//usleep(1000 * 5000); // (test delay for debugging) //usleep(1000 * 5000); // (test delay for debugging)
UIImage* iconImage = [UIImage _applicationIconImageForBundleIdentifier:appId format:10 scale:[UIScreen mainScreen].scale]; UIImage* iconImage = imageWithSize([UIImage _applicationIconImageForBundleIdentifier:appId format:iconFormatToUse() scale:[UIScreen mainScreen].scale], _placeholderIcon.size);
_cachedIcons[appId] = iconImage; _cachedIcons[appId] = iconImage;
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
if([tableView.indexPathsForVisibleRows containsObject:indexPath]) if([tableView.indexPathsForVisibleRows containsObject:indexPath])
{ {
cell.imageView.image = iconImage; cell.imageView.image = iconImage;
[cell setNeedsLayout];
} }
}); });
}); });
@ -207,7 +248,7 @@
[appSelectAlert addAction:detachAction];*/ [appSelectAlert addAction:detachAction];*/
UIAlertAction* openAction = [UIAlertAction actionWithTitle: @"Open" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action) UIAlertAction* openAction = [UIAlertAction actionWithTitle:@"Open" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action)
{ {
[self openAppPressedForRowAtIndexPath:indexPath]; [self openAppPressedForRowAtIndexPath:indexPath];
[self deselectRow]; [self deselectRow];

View File

@ -0,0 +1,23 @@
#import <UIKit/UIKit.h>
#import <Preferences/PSListController.h>
#import <Preferences/PSSpecifier.h>
@interface TSListControllerShared : PSListController
{
UIAlertController* _activityController;
}
- (BOOL)isTrollStore;
- (NSString*)getTrollStoreVersion;
- (void)startActivity:(NSString*)activity;
- (void)stopActivityWithCompletion:(void (^)(void))completion;
- (void)installTrollStorePressed;
- (void)updateTrollStorePressed;
- (void)rebuildIconCachePressed;
- (void)refreshAppRegistrationsPressed;
- (void)uninstallPersistenceHelperPressed;
- (void)handleUninstallation;
- (void)uninstallTrollStorePressed;
@end

View File

@ -0,0 +1,227 @@
#import "TSListControllerShared.h"
#import "TSUtil.h"
#import "../Helper/Shared.h"
@implementation TSListControllerShared
- (BOOL)isTrollStore
{
return YES;
}
- (NSString*)getTrollStoreVersion
{
if([self isTrollStore])
{
return [NSBundle.mainBundle objectForInfoDictionaryKey:@"CFBundleVersion"];
}
else
{
NSString* trollStorePath = trollStoreAppPath();
if(!trollStorePath) return nil;
NSBundle* trollStoreBundle = [NSBundle bundleWithPath:trollStorePath];
return [trollStoreBundle objectForInfoDictionaryKey:@"CFBundleVersion"];
}
}
- (void)startActivity:(NSString*)activity
{
if(_activityController) return;
_activityController = [UIAlertController alertControllerWithTitle:activity message:@"" preferredStyle:UIAlertControllerStyleAlert];
UIActivityIndicatorView* activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(5,5,50,50)];
activityIndicator.hidesWhenStopped = YES;
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleMedium;
[activityIndicator startAnimating];
[_activityController.view addSubview:activityIndicator];
[self presentViewController:_activityController animated:YES completion:nil];
}
- (void)stopActivityWithCompletion:(void (^)(void))completion
{
if(!_activityController) return;
[_activityController dismissViewControllerAnimated:YES completion:^
{
_activityController = nil;
if(completion)
{
completion();
}
}];
}
- (void)_updateOrInstallTrollStore:(BOOL)update
{
NSURL* trollStoreURL = [NSURL URLWithString:@"https://github.com/opa334/TrollStore/releases/latest/download/TrollStore.tar"];
NSURLRequest* trollStoreRequest = [NSURLRequest requestWithURL:trollStoreURL];
if(update)
{
[self startActivity:@"Updating TrollStore"];
}
else
{
[self startActivity:@"Installing TrollStore"];
}
NSURLSessionDownloadTask* downloadTask = [NSURLSession.sharedSession downloadTaskWithRequest:trollStoreRequest completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error)
{
if(error)
{
UIAlertController* errorAlert = [UIAlertController alertControllerWithTitle:@"Error" message:[NSString stringWithFormat:@"Error downloading TrollStore: %@", error] preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleDefault handler:nil];
[errorAlert addAction:closeAction];
dispatch_async(dispatch_get_main_queue(), ^
{
[self stopActivityWithCompletion:^
{
[self presentViewController:errorAlert animated:YES completion:nil];
}];
});
}
else
{
NSString* tarTmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"TrollStore.tar"];
[[NSFileManager defaultManager] copyItemAtPath:location.path toPath:tarTmpPath error:nil];
int ret = spawnRoot(helperPath(), @[@"install-trollstore", tarTmpPath], nil, nil);
[[NSFileManager defaultManager] removeItemAtPath:tarTmpPath error:nil];
if(ret == 0)
{
respring();
if([self isTrollStore])
{
exit(0);
}
else
{
dispatch_async(dispatch_get_main_queue(), ^
{
[self stopActivityWithCompletion:^
{
[self reloadSpecifiers];
}];
});
}
}
else
{
dispatch_async(dispatch_get_main_queue(), ^
{
[self stopActivityWithCompletion:^
{
UIAlertController* errorAlert = [UIAlertController alertControllerWithTitle:@"Error" message:[NSString stringWithFormat:@"Error installing TrollStore: trollstorehelper returned %d", ret] preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleDefault handler:nil];
[errorAlert addAction:closeAction];
[self presentViewController:errorAlert animated:YES completion:nil];
}];
});
}
}
}];
[downloadTask resume];
}
- (void)installTrollStorePressed
{
[self _updateOrInstallTrollStore:NO];
}
- (void)updateTrollStorePressed
{
[self _updateOrInstallTrollStore:YES];
}
- (void)rebuildIconCachePressed
{
[self startActivity:@"Rebuilding Icon Cache"];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
{
spawnRoot(helperPath(), @[@"refresh-all"], nil, nil);
dispatch_async(dispatch_get_main_queue(), ^
{
[self stopActivityWithCompletion:nil];
});
});
}
- (void)refreshAppRegistrationsPressed
{
[self startActivity:@"Refreshing"];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
{
spawnRoot(helperPath(), @[@"refresh"], nil, nil);
respring();
dispatch_async(dispatch_get_main_queue(), ^
{
[self stopActivityWithCompletion:nil];
});
});
}
- (void)uninstallPersistenceHelperPressed
{
if([self isTrollStore])
{
spawnRoot(helperPath(), @[@"uninstall-persistence-helper"], nil, nil);
[self reloadSpecifiers];
}
else
{
UIAlertController* uninstallWarningAlert = [UIAlertController alertControllerWithTitle:@"Warning" message:@"Uninstalling the persistence helper will revert this app back to it's original state, you will however no longer be able to persistently refresh the TrollStore app registrations. Continue?" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
[uninstallWarningAlert addAction:cancelAction];
UIAlertAction* continueAction = [UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action)
{
spawnRoot(helperPath(), @[@"uninstall-persistence-helper"], nil, nil);
exit(0);
}];
[uninstallWarningAlert addAction:continueAction];
[self presentViewController:uninstallWarningAlert animated:YES completion:nil];
}
}
- (void)handleUninstallation
{
if([self isTrollStore])
{
exit(0);
}
else
{
[self reloadSpecifiers];
}
}
- (void)uninstallTrollStorePressed
{
UIAlertController* uninstallWarningAlert = [UIAlertController alertControllerWithTitle:@"Warning" message:@"About to uninstall TrollStore and all of the apps installed by it. Continue?" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
[uninstallWarningAlert addAction:cancelAction];
UIAlertAction* continueAction = [UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action)
{
spawnRoot(helperPath(), @[@"uninstall-trollstore"], nil, nil);
[self handleUninstallation];
}];
[uninstallWarningAlert addAction:continueAction];
[self presentViewController:uninstallWarningAlert animated:YES completion:nil];
}
@end

View File

@ -1,9 +1,8 @@
#import <Preferences/PSListController.h> #import "TSListControllerShared.h"
#import <Preferences/PSSpecifier.h>
@interface TSSettingsListController : PSListController @interface TSSettingsListController : TSListControllerShared
{ {
UIAlertController* _activityController;
PSSpecifier* _installPersistenceHelperSpecifier; PSSpecifier* _installPersistenceHelperSpecifier;
NSString* _newerVersion;
} }
@end @end

View File

@ -6,38 +6,24 @@
@implementation TSSettingsListController @implementation TSSettingsListController
- (void)loadView - (void)viewDidLoad
{ {
[super loadView]; [super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadSpecifiers) name:UIApplicationWillEnterForegroundNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadSpecifiers) name:UIApplicationWillEnterForegroundNotification object:nil];
}
- (void)startActivity:(NSString*)activity fetchLatestTrollStoreVersion(^(NSString* latestVersion)
{
if(_activityController) return;
_activityController = [UIAlertController alertControllerWithTitle:activity message:@"" preferredStyle:UIAlertControllerStyleAlert];
UIActivityIndicatorView* activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(5,5,50,50)];
activityIndicator.hidesWhenStopped = YES;
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleMedium;
[activityIndicator startAnimating];
[_activityController.view addSubview:activityIndicator];
[self presentViewController:_activityController animated:YES completion:nil];
}
- (void)stopActivityWithCompletion:(void (^)(void))completion
{
if(!_activityController) return;
[_activityController dismissViewControllerAnimated:YES completion:^
{ {
_activityController = nil; NSString* currentVersion = [self getTrollStoreVersion];
if(completion) NSComparisonResult result = [currentVersion compare:latestVersion options:NSNumericSearch];
if(result == NSOrderedAscending)
{ {
completion(); _newerVersion = latestVersion;
dispatch_async(dispatch_get_main_queue(), ^
{
[self reloadSpecifiers];
});
} }
}]; });
} }
- (NSMutableArray*)specifiers - (NSMutableArray*)specifiers
@ -46,6 +32,25 @@
{ {
_specifiers = [NSMutableArray new]; _specifiers = [NSMutableArray new];
if(_newerVersion)
{
PSSpecifier* updateTrollStoreGroupSpecifier = [PSSpecifier emptyGroupSpecifier];
updateTrollStoreGroupSpecifier.name = @"Update Available";
[_specifiers addObject:updateTrollStoreGroupSpecifier];
PSSpecifier* updateTrollStoreSpecifier = [PSSpecifier preferenceSpecifierNamed:[NSString stringWithFormat:@"Update TrollStore to %@", _newerVersion]
target:self
set:nil
get:nil
detail:nil
cell:PSButtonCell
edit:nil];
updateTrollStoreSpecifier.identifier = @"updateTrollStore";
[updateTrollStoreSpecifier setProperty:@YES forKey:@"enabled"];
updateTrollStoreSpecifier.buttonAction = @selector(updateTrollStorePressed);
[_specifiers addObject:updateTrollStoreSpecifier];
}
PSSpecifier* utilitiesGroupSpecifier = [PSSpecifier emptyGroupSpecifier]; PSSpecifier* utilitiesGroupSpecifier = [PSSpecifier emptyGroupSpecifier];
utilitiesGroupSpecifier.name = @"Utilities"; utilitiesGroupSpecifier.name = @"Utilities";
[utilitiesGroupSpecifier setProperty:@"If an app does not immediately appear after installation, respring here and it should appear afterwards." forKey:@"footerText"]; [utilitiesGroupSpecifier setProperty:@"If an app does not immediately appear after installation, respring here and it should appear afterwards." forKey:@"footerText"];
@ -192,7 +197,7 @@
} }
PSSpecifier* otherGroupSpecifier = [PSSpecifier emptyGroupSpecifier]; PSSpecifier* otherGroupSpecifier = [PSSpecifier emptyGroupSpecifier];
[otherGroupSpecifier setProperty:[NSString stringWithFormat:@"TrollStore %@\n\n© 2022 Lars Fröder (opa334)\n\nCredits:\n@LinusHenze: CoreTrust bug\n@zhuowei: CoreTrust bug writeup and cert\n@lunotech11, @SerenaKit, @tylinux: Various contributions\n@ProcursusTeam: uicache and ldid build\n@cstar_ow: uicache\n@saurik: ldid", getTrollStoreVersion()] forKey:@"footerText"]; [otherGroupSpecifier setProperty:[NSString stringWithFormat:@"TrollStore %@\n\n© 2022 Lars Fröder (opa334)\n\nCredits:\n@LinusHenze: CoreTrust bug\n@zhuowei: CoreTrust bug writeup and cert\n@lunotech11, @SerenaKit, @tylinux: Various contributions\n@ProcursusTeam: uicache and ldid build\n@cstar_ow: uicache\n@saurik: ldid", [self getTrollStoreVersion]] forKey:@"footerText"];
[_specifiers addObject:otherGroupSpecifier]; [_specifiers addObject:otherGroupSpecifier];
// Uninstall TrollStore // Uninstall TrollStore
@ -208,6 +213,18 @@
[uninstallTrollStoreSpecifier setProperty:NSClassFromString(@"PSDeleteButtonCell") forKey:@"cellClass"]; [uninstallTrollStoreSpecifier setProperty:NSClassFromString(@"PSDeleteButtonCell") forKey:@"cellClass"];
uninstallTrollStoreSpecifier.buttonAction = @selector(uninstallTrollStorePressed); uninstallTrollStoreSpecifier.buttonAction = @selector(uninstallTrollStorePressed);
[_specifiers addObject:uninstallTrollStoreSpecifier]; [_specifiers addObject:uninstallTrollStoreSpecifier];
/*PSSpecifier* doTheDashSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Do the Dash"
target:self
set:nil
get:nil
detail:nil
cell:PSButtonCell
edit:nil];
doTheDashSpecifier.identifier = @"doTheDash";
[doTheDashSpecifier setProperty:@YES forKey:@"enabled"];
uninstallTrollStoreSpecifier.buttonAction = @selector(doTheDashPressed);
[_specifiers addObject:doTheDashSpecifier];*/
} }
[(UINavigationItem *)self.navigationItem setTitle:@"Settings"]; [(UINavigationItem *)self.navigationItem setTitle:@"Settings"];
@ -219,21 +236,6 @@
respring(); respring();
} }
- (void)rebuildIconCachePressed
{
[self startActivity:@"Rebuilding Icon Cache"];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
{
spawnRoot(helperPath(), @[@"refresh-all"], nil, nil);
dispatch_async(dispatch_get_main_queue(), ^
{
[self stopActivityWithCompletion:nil];
});
});
}
- (void)installLdidPressed - (void)installLdidPressed
{ {
NSURL* ldidURL = [NSURL URLWithString:@"https://github.com/opa334/ldid/releases/download/v2.1.5-procursus5/ldid"]; NSURL* ldidURL = [NSURL URLWithString:@"https://github.com/opa334/ldid/releases/download/v2.1.5-procursus5/ldid"];
@ -312,27 +314,9 @@
[self presentViewController:selectAppAlert animated:YES completion:nil]; [self presentViewController:selectAppAlert animated:YES completion:nil];
} }
- (void)uninstallPersistenceHelperPressed - (void)doTheDashPressed
{ {
spawnRoot(helperPath(), @[@"uninstall-persistence-helper"], nil, nil); spawnRoot(helperPath(), @[@"dash"], nil, nil);
[self reloadSpecifiers];
}
- (void)uninstallTrollStorePressed
{
UIAlertController* uninstallWarningAlert = [UIAlertController alertControllerWithTitle:@"Warning" message:@"About to uninstall TrollStore and all of the apps installed by it. Continue?" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
[uninstallWarningAlert addAction:cancelAction];
UIAlertAction* continueAction = [UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action)
{
spawnRoot(helperPath(), @[@"uninstall-trollstore"], nil, nil);
exit(0);
}];
[uninstallWarningAlert addAction:continueAction];
[self presentViewController:uninstallWarningAlert animated:YES completion:nil];
} }
@end @end

View File

@ -4,4 +4,4 @@ extern NSString* helperPath(void);
extern void printMultilineNSString(NSString* stringToPrint); extern void printMultilineNSString(NSString* stringToPrint);
extern int spawnRoot(NSString* path, NSArray* args, NSString** stdOut, NSString** stdErr); extern int spawnRoot(NSString* path, NSArray* args, NSString** stdOut, NSString** stdErr);
extern void respring(void); extern void respring(void);
extern NSString* getTrollStoreVersion(void); extern void fetchLatestTrollStoreVersion(void (^completionHandler)(NSString* latestVersion));

View File

@ -186,7 +186,26 @@ void respring(void)
exit(0); exit(0);
} }
NSString* getTrollStoreVersion(void) void fetchLatestTrollStoreVersion(void (^completionHandler)(NSString* latestVersion))
{ {
return [NSBundle.mainBundle objectForInfoDictionaryKey:@"CFBundleVersion"]; NSURL* githubLatestAPIURL = [NSURL URLWithString:@"https://api.github.com/repos/opa334/TrollStore/releases/latest"];
}
NSURLSessionDataTask* task = [NSURLSession.sharedSession dataTaskWithURL:githubLatestAPIURL completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
if(!error)
{
if ([response isKindOfClass:[NSHTTPURLResponse class]])
{
NSError *jsonError;
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
if (!jsonError)
{
completionHandler(jsonResponse[@"tag_name"]);
}
}
}
}];
[task resume];
}

View File

@ -1,6 +1,6 @@
Package: com.opa334.trollstore Package: com.opa334.trollstore
Name: TrollStore Name: TrollStore
Version: 1.0.10 Version: 1.1
Architecture: iphoneos-arm Architecture: iphoneos-arm
Description: An awesome application! Description: An awesome application!
Maintainer: opa334 Maintainer: opa334

View File

@ -48,18 +48,20 @@ COPYFILE_DISABLE=1 tar -czvf TrollStore.tar ./TrollStore.app
rm -rf ./TrollStore.app rm -rf ./TrollStore.app
cd - cd -
# Step five: compile installer if [[ $1 == "installer" ]]; then
xcodebuild -project ../Installer/TrollInstaller/TrollInstaller.xcodeproj -scheme TrollInstaller -destination generic/platform=iOS -archivePath ./out/Installer.xcarchive archive # Step five: compile installer
xcodebuild -project ../Installer/TrollInstaller/TrollInstaller.xcodeproj -scheme TrollInstaller -destination generic/platform=iOS -archivePath ./out/Installer.xcarchive archive
if [[ -f "./out/Installer.xcarchive/Products/Applications/TrollInstaller.app/embedded.mobileprovision" ]]; then if [[ -f "./out/Installer.xcarchive/Products/Applications/TrollInstaller.app/embedded.mobileprovision" ]]; then
rm ./out/Installer.xcarchive/Products/Applications/TrollInstaller.app/embedded.mobileprovision rm ./out/Installer.xcarchive/Products/Applications/TrollInstaller.app/embedded.mobileprovision
fi fi
ldid -s ./out/Installer.xcarchive/Products/Applications/TrollInstaller.app ldid -s ./out/Installer.xcarchive/Products/Applications/TrollInstaller.app
mkdir ./out/Payload mkdir ./out/Payload
mv ./out/Installer.xcarchive/Products/Applications/TrollInstaller.app ./out/Payload/TrollInstaller.app mv ./out/Installer.xcarchive/Products/Applications/TrollInstaller.app ./out/Payload/TrollInstaller.app
cd out cd out
zip -vr TrollInstaller.ipa Payload zip -vr TrollInstaller.ipa Payload
cd - cd -
rm -rf ./out/Payload rm -rf ./out/Payload
rm -rf ./out/Installer.xcarchive rm -rf ./out/Installer.xcarchive
fi