diff --git a/Helper/control b/Helper/control
index cc03a1a..4c4200b 100644
--- a/Helper/control
+++ b/Helper/control
@@ -1,6 +1,6 @@
Package: com.opa334.trollstoreroothelper
Name: trollstoreroothelper
-Version: 1.0.10
+Version: 1.1
Architecture: iphoneos-arm
Description: An awesome tool of some sort!!
Maintainer: opa334
diff --git a/Helper/main.m b/Helper/main.m
index 411c640..6e10e6a 100644
--- a/Helper/main.m
+++ b/Helper/main.m
@@ -730,6 +730,11 @@ int installApp(NSString* appPath, BOOL sign, BOOL force)
// Wipe old version if needed
if(existed)
{
+ if(![appId isEqualToString:@"com.opa334.TrollStore"])
+ {
+ BKSTerminateApplicationForReasonAndReportWithDescription(appId, 5, false, @"TrollStore - App updated");
+ }
+
NSLog(@"[installApp] found existing TrollStore app, cleaning directory");
NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtURL:appContainer.url includingPropertiesForKeys:nil options:0 errorHandler:nil];
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
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;
}
@@ -767,6 +772,8 @@ int installApp(NSString* appPath, BOOL sign, BOOL force)
int uninstallApp(NSString* appPath, NSString* appId)
{
+ BKSTerminateApplicationForReasonAndReportWithDescription(appId, 5, false, @"TrollStore - App uninstalled");
+
LSApplicationProxy* appProxy = [LSApplicationProxy applicationProxyForIdentifier:appId];
MCMContainer *appContainer = [objc_getClass("MCMAppDataContainer") containerWithIdentifier:appId createIfNecessary:NO existed:nil error:nil];
NSString *containerPath = [appContainer url].path;
@@ -1156,6 +1163,14 @@ int main(int argc, char *argv[], char *envp[]) {
} else if([cmd isEqualToString:@"uninstall-persistence-helper"])
{
uninstallPersistenceHelper();
+ } else if([cmd isEqualToString:@"dash"])
+ {
+ LSApplicationProxy* appProxy = findPersistenceHelperApp();
+ if(appProxy)
+ {
+ NSString* executablePath = appProxy.canonicalExecutablePath;
+ registerPath((char*)executablePath.UTF8String, 1);
+ }
}
NSLog(@"returning %d", ret);
diff --git a/Helper/uicache.m b/Helper/uicache.m
index 73eb782..f50e214 100644
--- a/Helper/uicache.m
+++ b/Helper/uicache.m
@@ -127,7 +127,6 @@ void registerPath(char* cPath, int unregister)
// Misc
dictToRegister[@"ApplicationType"] = @"System";
- dictToRegister[@"BundleNameIsLocalized"] = @1;
dictToRegister[@"CFBundleIdentifier"] = appBundleID;
dictToRegister[@"CodeInfoIdentifier"] = appBundleID;
dictToRegister[@"CompatibilityState"] = @0;
@@ -144,6 +143,10 @@ void registerPath(char* cPath, int unregister)
dictToRegister[@"SignerIdentity"] = @"Apple iPhone OS Application Signing";
dictToRegister[@"IsAdHocSigned"] = @YES;
dictToRegister[@"LSInstallType"] = @1;
+ dictToRegister[@"HasMIDBasedSINF"] = @0;
+ dictToRegister[@"MissingSINF"] = @0;
+ dictToRegister[@"FamilyID"] = @0;
+ dictToRegister[@"IsOnDemandInstallCapable"] = @0;
NSString* teamIdentifier = constructTeamIdentifierForEntitlements(entitlements);
if(teamIdentifier) dictToRegister[@"TeamIdentifier"] = teamIdentifier;
@@ -199,7 +202,6 @@ void registerPath(char* cPath, int unregister)
// Misc
pluginDict[@"ApplicationType"] = @"PluginKitPlugin";
- pluginDict[@"BundleNameIsLocalized"] = @1;
pluginDict[@"CFBundleIdentifier"] = pluginBundleID;
pluginDict[@"CodeInfoIdentifier"] = pluginBundleID;
pluginDict[@"CompatibilityState"] = @0;
diff --git a/PersistenceHelper/Makefile b/PersistenceHelper/Makefile
index baa9eb2..6d5bdad 100644
--- a/PersistenceHelper/Makefile
+++ b/PersistenceHelper/Makefile
@@ -5,7 +5,7 @@ include $(THEOS)/makefiles/common.mk
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_PRIVATE_FRAMEWORKS = Preferences
TrollStorePersistenceHelper_CFLAGS = -fobjc-arc
diff --git a/PersistenceHelper/Resources/Info.plist b/PersistenceHelper/Resources/Info.plist
index 17c7756..8830808 100644
--- a/PersistenceHelper/Resources/Info.plist
+++ b/PersistenceHelper/Resources/Info.plist
@@ -52,7 +52,7 @@
iPhoneOS
CFBundleVersion
- 1.0.10
+ 1.1
LSRequiresIPhoneOS
UIDeviceFamily
diff --git a/PersistenceHelper/TSPHRootViewController.h b/PersistenceHelper/TSPHRootViewController.h
index f7cdc13..d2921c8 100644
--- a/PersistenceHelper/TSPHRootViewController.h
+++ b/PersistenceHelper/TSPHRootViewController.h
@@ -1,9 +1,7 @@
-#import
-#import
-#import
+#import "../Store/TSListControllerShared.h"
-@interface TSPHRootViewController : PSListController
+@interface TSPHRootViewController : TSListControllerShared
{
- UIAlertController* _activityController;
+ NSString* _newerVersion;
}
@end
diff --git a/PersistenceHelper/TSPHRootViewController.m b/PersistenceHelper/TSPHRootViewController.m
index 503e8f5..6dc1c80 100644
--- a/PersistenceHelper/TSPHRootViewController.m
+++ b/PersistenceHelper/TSPHRootViewController.m
@@ -4,38 +4,29 @@
@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];
-}
-- (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:^
+ fetchLatestTrollStoreVersion(^(NSString* latestVersion)
{
- _activityController = nil;
- if(completion)
+ NSString* currentVersion = [self getTrollStoreVersion];
+ NSComparisonResult result = [currentVersion compare:latestVersion options:NSNumericSearch];
+ if(result == NSOrderedAscending)
{
- completion();
+ _newerVersion = latestVersion;
+ dispatch_async(dispatch_get_main_queue(), ^
+ {
+ [self reloadSpecifiers];
+ });
}
- }];
+ });
}
- (NSMutableArray*)specifiers
@@ -60,10 +51,28 @@
[_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];
[_specifiers addObject:utilitiesGroupSpecifier];
- if(trollStoreAppPath())
+ if(isInstalled)
{
PSSpecifier* refreshAppRegistrationsSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Refresh App Registrations"
target:self
@@ -74,7 +83,7 @@
edit:nil];
refreshAppRegistrationsSpecifier.identifier = @"refreshAppRegistrations";
[refreshAppRegistrationsSpecifier setProperty:@YES forKey:@"enabled"];
- refreshAppRegistrationsSpecifier.buttonAction = @selector(refreshAppRegistrations);
+ refreshAppRegistrationsSpecifier.buttonAction = @selector(refreshAppRegistrationsPressed);
[_specifiers addObject:refreshAppRegistrationsSpecifier];
PSSpecifier* uninstallTrollStoreSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Uninstall TrollStore"
@@ -130,122 +139,21 @@
- (NSString*)getTrollStoreInfoString
{
- NSString* trollStore = trollStoreAppPath();
- if(!trollStore)
+ NSString* version = [self getTrollStoreVersion];
+ if(!version)
{
return @"Not Installed";
}
else
{
- NSBundle* trollStoreBundle = [NSBundle bundleWithPath:trollStore];
- NSString* version = [trollStoreBundle objectForInfoDictionaryKey:@"CFBundleVersion"];
return [NSString stringWithFormat:@"Installed, %@", version];
}
}
-- (void)refreshAppRegistrations
+- (void)handleUninstallation
{
- [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)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];
+ _newerVersion = nil;
+ [super handleUninstallation];
}
@end
diff --git a/PersistenceHelper/control b/PersistenceHelper/control
index 065abf8..ce555b4 100644
--- a/PersistenceHelper/control
+++ b/PersistenceHelper/control
@@ -1,6 +1,6 @@
Package: com.opa334.trollstorehelper
Name: TrollStore Helper
-Version: 1.0.10
+Version: 1.1
Architecture: iphoneos-arm
Description: Helper utility to install and manage TrollStore!
Maintainer: opa334
diff --git a/Store/Resources/Info.plist b/Store/Resources/Info.plist
index e332bd4..2b31b54 100644
--- a/Store/Resources/Info.plist
+++ b/Store/Resources/Info.plist
@@ -50,7 +50,7 @@
iPhoneOS
CFBundleVersion
- 1.0.10
+ 1.1
LSRequiresIPhoneOS
UIDeviceFamily
diff --git a/Store/TSAppTableViewController.m b/Store/TSAppTableViewController.m
index a58c26d..6268a61 100644
--- a/Store/TSAppTableViewController.m
+++ b/Store/TSAppTableViewController.m
@@ -2,6 +2,32 @@
#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 ()
+ (UIImage *)_applicationIconImageForBundleIdentifier:(NSString *)id format:(NSInteger)format scale:(double)scale;
@end
@@ -10,7 +36,14 @@
- (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
@@ -19,7 +52,7 @@
if(self)
{
[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];
}
return self;
@@ -120,6 +153,11 @@
return _cachedAppPaths.count;
}
+- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
+{
+ [self reloadTable];
+}
+
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ApplicationCell"];
if (!cell) {
@@ -133,9 +171,11 @@
// Configure the cell...
cell.textLabel.text = [[TSApplicationsManager sharedInstance] displayNameForAppPath:appPath];
cell.detailTextLabel.text = [NSString stringWithFormat:@"%@ • %@", appVersion, appId];
- cell.imageView.layer.borderWidth = 0.34;
- cell.imageView.layer.borderColor = [UIColor separatorColor].CGColor;
- cell.imageView.layer.cornerRadius = 13.8;
+ cell.imageView.layer.borderWidth = 1;
+ cell.imageView.layer.borderColor = [UIColor.labelColor colorWithAlphaComponent:0.1].CGColor;
+ cell.imageView.layer.cornerRadius = 13.5;
+ cell.imageView.layer.masksToBounds = YES;
+ cell.imageView.layer.cornerCurve = kCACornerCurveContinuous;
if(appId)
{
@@ -150,12 +190,13 @@
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
{
//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;
dispatch_async(dispatch_get_main_queue(), ^{
if([tableView.indexPathsForVisibleRows containsObject:indexPath])
{
cell.imageView.image = iconImage;
+ [cell setNeedsLayout];
}
});
});
@@ -207,7 +248,7 @@
[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 deselectRow];
diff --git a/Store/TSListControllerShared.h b/Store/TSListControllerShared.h
new file mode 100644
index 0000000..59b65e3
--- /dev/null
+++ b/Store/TSListControllerShared.h
@@ -0,0 +1,23 @@
+#import
+#import
+#import
+
+@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
\ No newline at end of file
diff --git a/Store/TSListControllerShared.m b/Store/TSListControllerShared.m
new file mode 100644
index 0000000..9bea3b0
--- /dev/null
+++ b/Store/TSListControllerShared.m
@@ -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
\ No newline at end of file
diff --git a/Store/TSSettingsListController.h b/Store/TSSettingsListController.h
index 39fdd47..959d405 100644
--- a/Store/TSSettingsListController.h
+++ b/Store/TSSettingsListController.h
@@ -1,9 +1,8 @@
-#import
-#import
+#import "TSListControllerShared.h"
-@interface TSSettingsListController : PSListController
+@interface TSSettingsListController : TSListControllerShared
{
- UIAlertController* _activityController;
PSSpecifier* _installPersistenceHelperSpecifier;
+ NSString* _newerVersion;
}
@end
\ No newline at end of file
diff --git a/Store/TSSettingsListController.m b/Store/TSSettingsListController.m
index 9782ecb..9b2d2b0 100644
--- a/Store/TSSettingsListController.m
+++ b/Store/TSSettingsListController.m
@@ -6,38 +6,24 @@
@implementation TSSettingsListController
-- (void)loadView
+- (void)viewDidLoad
{
- [super loadView];
+ [super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadSpecifiers) name:UIApplicationWillEnterForegroundNotification object:nil];
-}
-- (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:^
+ fetchLatestTrollStoreVersion(^(NSString* latestVersion)
{
- _activityController = nil;
- if(completion)
+ NSString* currentVersion = [self getTrollStoreVersion];
+ NSComparisonResult result = [currentVersion compare:latestVersion options:NSNumericSearch];
+ if(result == NSOrderedAscending)
{
- completion();
+ _newerVersion = latestVersion;
+ dispatch_async(dispatch_get_main_queue(), ^
+ {
+ [self reloadSpecifiers];
+ });
}
- }];
+ });
}
- (NSMutableArray*)specifiers
@@ -46,6 +32,25 @@
{
_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];
utilitiesGroupSpecifier.name = @"Utilities";
[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];
- [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];
// Uninstall TrollStore
@@ -208,6 +213,18 @@
[uninstallTrollStoreSpecifier setProperty:NSClassFromString(@"PSDeleteButtonCell") forKey:@"cellClass"];
uninstallTrollStoreSpecifier.buttonAction = @selector(uninstallTrollStorePressed);
[_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"];
@@ -219,21 +236,6 @@
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
{
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];
}
-- (void)uninstallPersistenceHelperPressed
+- (void)doTheDashPressed
{
- spawnRoot(helperPath(), @[@"uninstall-persistence-helper"], 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];
+ spawnRoot(helperPath(), @[@"dash"], nil, nil);
}
@end
\ No newline at end of file
diff --git a/Store/TSUtil.h b/Store/TSUtil.h
index 55afe23..af54257 100644
--- a/Store/TSUtil.h
+++ b/Store/TSUtil.h
@@ -4,4 +4,4 @@ extern NSString* helperPath(void);
extern void printMultilineNSString(NSString* stringToPrint);
extern int spawnRoot(NSString* path, NSArray* args, NSString** stdOut, NSString** stdErr);
extern void respring(void);
-extern NSString* getTrollStoreVersion(void);
\ No newline at end of file
+extern void fetchLatestTrollStoreVersion(void (^completionHandler)(NSString* latestVersion));
\ No newline at end of file
diff --git a/Store/TSUtil.m b/Store/TSUtil.m
index aee6b86..1a26cf6 100644
--- a/Store/TSUtil.m
+++ b/Store/TSUtil.m
@@ -186,7 +186,26 @@ void respring(void)
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];
+}
\ No newline at end of file
diff --git a/Store/control b/Store/control
index 6747b25..1013550 100644
--- a/Store/control
+++ b/Store/control
@@ -1,6 +1,6 @@
Package: com.opa334.trollstore
Name: TrollStore
-Version: 1.0.10
+Version: 1.1
Architecture: iphoneos-arm
Description: An awesome application!
Maintainer: opa334
diff --git a/_compile/build_full.sh b/_compile/build_full.sh
index 67ac02d..b22b22f 100755
--- a/_compile/build_full.sh
+++ b/_compile/build_full.sh
@@ -48,18 +48,20 @@ COPYFILE_DISABLE=1 tar -czvf TrollStore.tar ./TrollStore.app
rm -rf ./TrollStore.app
cd -
-# Step five: compile installer
-xcodebuild -project ../Installer/TrollInstaller/TrollInstaller.xcodeproj -scheme TrollInstaller -destination generic/platform=iOS -archivePath ./out/Installer.xcarchive archive
+if [[ $1 == "installer" ]]; then
+ # 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
- rm ./out/Installer.xcarchive/Products/Applications/TrollInstaller.app/embedded.mobileprovision
-fi
+ if [[ -f "./out/Installer.xcarchive/Products/Applications/TrollInstaller.app/embedded.mobileprovision" ]]; then
+ rm ./out/Installer.xcarchive/Products/Applications/TrollInstaller.app/embedded.mobileprovision
+ fi
-ldid -s ./out/Installer.xcarchive/Products/Applications/TrollInstaller.app
-mkdir ./out/Payload
-mv ./out/Installer.xcarchive/Products/Applications/TrollInstaller.app ./out/Payload/TrollInstaller.app
-cd out
-zip -vr TrollInstaller.ipa Payload
-cd -
-rm -rf ./out/Payload
-rm -rf ./out/Installer.xcarchive
\ No newline at end of file
+ ldid -s ./out/Installer.xcarchive/Products/Applications/TrollInstaller.app
+ mkdir ./out/Payload
+ mv ./out/Installer.xcarchive/Products/Applications/TrollInstaller.app ./out/Payload/TrollInstaller.app
+ cd out
+ zip -vr TrollInstaller.ipa Payload
+ cd -
+ rm -rf ./out/Payload
+ rm -rf ./out/Installer.xcarchive
+fi
\ No newline at end of file