Skip to content

Commit 081f287

Browse files
committed
Not updating yet.
Add JIT enabler, add popup asking to be redirected (and also added update checker for first setup), add when logs will clear, associate .geode files with launcher, fix automatic launch soft locking when tapping settings, attempt to fix deactivate sidestore issue, Add error if GD fails to launch.
1 parent 97c676f commit 081f287

13 files changed

+498
-156
lines changed

Resources/Info.plist

+37
Original file line numberDiff line numberDiff line change
@@ -206,5 +206,42 @@
206206
<string>A mod you are using is requesting this permission.</string>
207207
<key>NSLocalNetworkUsageDescription</key>
208208
<string>This permission is needed for accessing the JIT server.</string>
209+
210+
<!-- Handling .geode files -->
211+
<key>CFBundleDocumentTypes</key>
212+
<array>
213+
<dict>
214+
<key>CFBundleTypeName</key>
215+
<string>Geode Mod</string>
216+
<key>LSHandlerRank</key>
217+
<string>Owner</string>
218+
<key>CFBundleTypeRole</key>
219+
<string>Editor</string>
220+
<key>LSItemContentTypes</key>
221+
<array>
222+
<string>com.geode.launcher.mod</string>
223+
</array>
224+
</dict>
225+
</array>
226+
<key>UTExportedTypeDeclarations</key>
227+
<array>
228+
<dict>
229+
<key>UTTypeDescription</key>
230+
<string>Geode Mod</string>
231+
<key>UTTypeIdentifier</key>
232+
<string>com.geode.launcher.mod</string>
233+
<key>UTTypeConformsTo</key>
234+
<array>
235+
<string>public.data</string>
236+
</array>
237+
<key>UTTypeTagSpecification</key>
238+
<dict>
239+
<key>public.filename-extension</key>
240+
<string>geode</string>
241+
<key>public.mime-type</key>
242+
<string>application/x-geode</string>
243+
</dict>
244+
</dict>
245+
</array>
209246
</dict>
210247
</plist>

Resources/en.lproj/Localizable.strings

+25-7
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
"intro.s1.title" = "Welcome to Geode!";
1111
"intro.s1.subtitle" = "Let's get you started.";
1212

13+
"intro.update.title" = "Update available!";
14+
"intro.update.subtitle" = "There is an update available for the launcher. It is recommended to download the latest version of the launcher. Would you like to be redirected to the latest release?";
15+
1316
"intro.s2.title" = "Choose your Accent Color";
1417
"intro.s2.color.preview" = "Preview";
1518
"intro.s2.color.button" = "Change Color";
@@ -65,9 +68,10 @@
6568

6669
"launcher.notice.gd-outdated" = "Your Geometry Dash is outdated!";
6770
"launcher.notice.gd-update" = "Geode requires an update! Relaunch the app to update it!";
68-
"launcher.notice.launcher-update" = "A launcher update is available! Redownload the IPA to update it!";
71+
"launcher.notice.launcher-update" = "A launcher update is available!\nRedownload the launcher by tapping OK to be redirected to the latest release!";
6972
"launcher.notice.ts.install" = "You are using the TrollStore version of Geode! If you want to install Geometry Dash in a container, consider installing the IPA version instead.";
70-
73+
"launcher.notice.mod-import" = "The mod '%@' has been imported!";
74+
"launcher.notice.mod-import.fail" = "The mod '%@' couldn't be imported";
7175

7276
"launcher.status.not-verified" = "Geometry Dash is not verified.\nYou need to verify that you installed the app.";
7377
"launcher.status.not-installed" = "Geode is not installed.";
@@ -81,6 +85,7 @@
8185

8286
"launcher.error.non" = "Please use the release from the original github page to download Geometry Dash.";
8387
"launcher.error.gd" = "Geode couldn't load Geometry Dash: %@";
88+
"launcher.error.app-uri" = "Couldn't open any app urls. Please ensure you have selected the right JIT Enabler, then restart the launcher.";
8489
"launcher.error.download-fail-restart" = "Download failed, please restart the app";
8590
"launcher.error.download-fail" = "Download failed";
8691
"launcher.error.download-not-found" = "Download failed, couldn't find ZIP archive. Please try again or enable nightly.";
@@ -112,11 +117,24 @@
112117
"gameplay.footer" = "Only enable the screen rotation fix or black screen fix if you are having problems.";
113118

114119
"jit" = "JIT";
115-
"jit.enable-auto-jit" = "Enable Auto JIT";
116-
"jit.enable-auto-jit.warning.title" = "Are you sure you want to enable Auto JIT?";
117-
"jit.enable-auto-jit.warning" = "Auto JIT is meant to be used with JITStreamer-EB. If you do not have JITStreamer-EB or use other alternatives like StikJIT or Sidestore JIT, do not enable this option.";
118-
"jit.auto-jit-server" = "Address";
119-
"jit.footer" = "Set up your JITStreamer server. Local Network permission is required. This is not necessary to set up if you use TrollStore, or if you're jailbroken.";
120+
"jit.jit-server" = "Address";
121+
"jit.jit-udid" = "Device UDID";
122+
"jit.jit-enabler" = "JIT Enabler";
123+
"jit.jit-enabler.default" = "Auto";
124+
"jit.jit-enabler.jitstreamereb" = "JITStreamer-EB";
125+
"jit.jit-enabler.sidejit" = "SideJITServer/JITStreamer 2.0";
126+
"jit.jit-enabler.stikjit" = "StikJIT";
127+
"jit.jit-enabler.trollstore" = "TrollStore";
128+
"jit.jit-enabler.sidestore" = "SideStore JIT";
129+
"jit.jit-enabler.livecontainer" = "LiveContainer";
130+
131+
"jit.footer.default" = "Geode will figure out what method of JIT to use based on certain conditions. This default option is recommended.";
132+
"jit.footer.jitstreamereb" = "Set up your JITStreamer-EB server. Local Network permission is required.";
133+
"jit.footer.sidejit" = "Set up your SideJITServer/JITStreamer server. Local Network permission is required. Use this only if you cannot use JITStreamer-EB.";
134+
"jit.footer.stikjit" = "Geode will open StikJIT when launched to enable JIT.";
135+
"jit.footer.trollstore" = "Geode will utilize TrollStore to enable JIT. Make sure you enable the \"URL Scheme Enabled\" setting in TrollStore, otherwise Geode will open the Apple Magnifier app.";
136+
"jit.footer.sidestore" = "Geode will open SideStore when launched to enable JIT.";
137+
"jit.footer.livecontainer" = "Ensure that you enabled \"Launch with JIT\" for the Geode app in LiveContainer.";
120138

121139
"jitless" = "JIT-Less";
122140
"jitless.footer" = "JIT-less allows you to use Geode without enabling JIT! You will need to patch AltStore or SideStore to enable, or use ZSign. If you signed Geode with a Developer / Enterprise Certificate, you may need to import the certificate.";

src/AppDelegate.m

+40-1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,43 @@ + (void)launchApp:(NSString*)bundleId container:(NSString*)container {
8686
}
8787

8888
- (BOOL)application:(UIApplication*)application openURL:(nonnull NSURL*)url options:(nonnull NSDictionary<UIApplicationOpenURLOptionsKey, id>*)options {
89+
90+
if (url && [url isFileURL]) {
91+
NSFileManager* fm = NSFileManager.defaultManager;
92+
NSString* fileName = [url lastPathComponent];
93+
94+
NSURL* path;
95+
NSError* error = nil;
96+
if ([Utils isContainerized]) {
97+
path = [NSURL fileURLWithPath:[[LCPath docPath].path stringByAppendingString:@"/game/geode/mods/"]];
98+
} else {
99+
path = [NSURL fileURLWithPath:[[Utils docPath] stringByAppendingString:@"game/geode/mods/"]];
100+
}
101+
NSURL* destinationURL = [path URLByAppendingPathComponent:fileName];
102+
if ([fm fileExistsAtPath:destinationURL.path]) {
103+
[fm removeItemAtURL:destinationURL error:&error];
104+
if (error) {
105+
AppLog(@"Couldn't replace file: %@", error);
106+
return NO;
107+
}
108+
}
109+
BOOL access = [url startAccessingSecurityScopedResource]; // to prevent ios from going "OH YOU HAVE NO PERMISSION!!!"
110+
if ([fm copyItemAtURL:url toURL:destinationURL error:&error]) {
111+
AppLog(@"Added new mod %@!", fileName);
112+
if (access)
113+
[url stopAccessingSecurityScopedResource];
114+
dispatch_async(dispatch_get_main_queue(), ^{ [Utils showNoticeGlobal:[NSString stringWithFormat:@"launcher.notice.mod-import".loc, fileName]]; });
115+
return YES;
116+
} else {
117+
AppLog(@"Couldn't copy file: %@", error);
118+
if (access)
119+
[url stopAccessingSecurityScopedResource];
120+
dispatch_async(dispatch_get_main_queue(), ^{ [Utils showErrorGlobal:[NSString stringWithFormat:@"launcher.notice.mod-import.fail".loc, fileName] error:error]; });
121+
return NO;
122+
}
123+
return YES;
124+
}
125+
89126
if ([url.host isEqualToString:@"open-web-page"]) {
90127
NSURLComponents* components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
91128
for (NSURLQueryItem* item in components.queryItems) {
@@ -131,7 +168,9 @@ - (BOOL)application:(UIApplication*)application openURL:(nonnull NSURL*)url opti
131168
}];
132169
} else {
133170
AppLog(@"Launching Geometry Dash");
134-
[LCUtils launchToGuestApp];
171+
if (![LCUtils launchToGuestApp]) {
172+
[Utils showErrorGlobal:[NSString stringWithFormat:@"launcher.error.gd".loc, @"launcher.error.app-uri".loc] error:nil];
173+
}
135174
}
136175
} else if ([url.host isEqualToString:@"safe-mode"]) {
137176
AppLog(@"Launching in Safe Mode");

src/GeodeInstaller.m

+18-35
Original file line numberDiff line numberDiff line change
@@ -7,40 +7,6 @@
77

88
typedef void (^DecompressCompletion)(NSError* _Nullable error);
99

10-
@interface CompareSemVer : NSObject
11-
+ (BOOL)isVersion:(NSString*)versionA greaterThanVersion:(NSString*)versionB;
12-
@end
13-
14-
@implementation CompareSemVer
15-
16-
+ (NSString*)normalizedVersionString:(NSString*)versionString {
17-
if ([versionString hasPrefix:@"v"]) {
18-
return [versionString substringFromIndex:1];
19-
}
20-
return versionString;
21-
}
22-
+ (BOOL)isVersion:(NSString*)versionA greaterThanVersion:(NSString*)versionB {
23-
if (versionA == nil || [versionA isEqual:@""])
24-
return YES;
25-
if (versionB == nil || [versionB isEqual:@""])
26-
return YES;
27-
NSString* normalizedA = [self normalizedVersionString:versionA];
28-
NSString* normalizedB = [self normalizedVersionString:versionB];
29-
NSArray<NSString*>* componentsA = [normalizedA componentsSeparatedByString:@"."];
30-
NSArray<NSString*>* componentsB = [normalizedB componentsSeparatedByString:@"."];
31-
NSUInteger maxCount = MAX(componentsA.count, componentsB.count);
32-
for (NSUInteger i = 0; i < maxCount; i++) {
33-
NSInteger valueA = (i < componentsA.count) ? [componentsA[i] integerValue] : 0;
34-
NSInteger valueB = (i < componentsB.count) ? [componentsB[i] integerValue] : 0;
35-
if (valueA > valueB) {
36-
return NO;
37-
}
38-
}
39-
return YES;
40-
}
41-
42-
@end
43-
4410
@implementation GeodeInstaller {
4511
NSURLSessionDownloadTask* downloadTask;
4612
}
@@ -235,7 +201,24 @@ - (void)checkLauncherUpdates:(RootViewController*)root {
235201
if (!greaterThanVer) {
236202
// assume out of date
237203
dispatch_async(dispatch_get_main_queue(), ^{
238-
[Utils showNotice:_root title:@"launcher.notice.launcher-update".loc];
204+
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"common.notice".loc message:@"launcher.notice.launcher-update".loc
205+
preferredStyle:UIAlertControllerStyleAlert];
206+
UIAlertAction* okAction = [UIAlertAction actionWithTitle:@"common.ok".loc style:UIAlertActionStyleDefault
207+
handler:^(UIAlertAction* _Nonnull action) {
208+
NSURL* url = [NSURL URLWithString:[Utils getGeodeLauncherRedirect]];
209+
if ([[UIApplication sharedApplication] canOpenURL:url]) {
210+
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
211+
}
212+
}];
213+
UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"common.cancel".loc style:UIAlertActionStyleCancel handler:nil];
214+
[alert addAction:okAction];
215+
[alert addAction:cancelAction];
216+
217+
UIWindowScene* scene = (id)[UIApplication.sharedApplication.connectedScenes allObjects].firstObject;
218+
UIWindow* window = scene.windows.firstObject;
219+
if (window != nil) {
220+
[window.rootViewController presentViewController:alert animated:YES completion:nil];
221+
}
239222
[self.root updateState];
240223
});
241224
} else {

src/IntroVC.m

+52
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,56 @@ - (void)transitionToView:(UIView*)newView {
9494
}];
9595
}
9696

97+
#pragma mark - Update checker
98+
- (void)checkLauncherUpdates {
99+
NSLog(@"[Geode/IntroVC] Checking for Launcher updates...");
100+
NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:[Utils getGeodeLauncherURL]]];
101+
NSURLSession* session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
102+
NSURLSessionDataTask* dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData* data, NSURLResponse* response, NSError* error) {
103+
if (error)
104+
return;
105+
if (data) {
106+
NSError* jsonError;
107+
NSArray* jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
108+
if (!jsonError) {
109+
if ([jsonObject isKindOfClass:[NSArray class]]) {
110+
NSDictionary* jsonDict = jsonObject[0];
111+
NSString* tagName = jsonDict[@"tag_name"];
112+
if (tagName && [tagName isKindOfClass:[NSString class]]) {
113+
NSString* launcherVer = [NSString stringWithFormat:@"v%@", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]];
114+
BOOL greaterThanVer = [CompareSemVer isVersion:tagName greaterThanVersion:launcherVer];
115+
NSLog(@"[Geode/IntroVC] Latest Launcher version is %@ (Currently on %@)", tagName, launcherVer);
116+
if (!greaterThanVer) {
117+
// assume out of date
118+
dispatch_async(dispatch_get_main_queue(), ^{
119+
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"intro.update.title".loc message:@"intro.update.subtitle".loc
120+
preferredStyle:UIAlertControllerStyleAlert];
121+
UIAlertAction* okAction = [UIAlertAction actionWithTitle:@"common.yes".loc style:UIAlertActionStyleDefault
122+
handler:^(UIAlertAction* _Nonnull action) {
123+
NSURL* url = [NSURL URLWithString:[Utils getGeodeLauncherRedirect]];
124+
if ([[UIApplication sharedApplication] canOpenURL:url]) {
125+
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
126+
}
127+
}];
128+
UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"common.no".loc style:UIAlertActionStyleCancel handler:nil];
129+
[alert addAction:okAction];
130+
[alert addAction:cancelAction];
131+
132+
UIWindowScene* scene = (id)[UIApplication.sharedApplication.connectedScenes allObjects].firstObject;
133+
UIWindow* window = scene.windows.firstObject;
134+
if (window != nil) {
135+
[window.rootViewController presentViewController:alert animated:YES completion:nil];
136+
}
137+
});
138+
}
139+
}
140+
}
141+
}
142+
}
143+
}];
144+
[dataTask resume];
145+
}
146+
97147
#pragma mark - Step Views
98148

99149
- (void)showWarningStep {
@@ -175,6 +225,8 @@ - (void)showWelcomeStep {
175225
nextButton.frame = CGRectMake(view.center.x - 70, CGRectGetMaxY(subtitleLabel.frame) + 20, 140, 45);
176226
[view addSubview:nextButton];
177227

228+
[self checkLauncherUpdates];
229+
178230
[self transitionToView:view];
179231
}
180232

src/LCUtils/GCSharedUtils.m

+22-13
Original file line numberDiff line numberDiff line change
@@ -145,12 +145,15 @@ + (BOOL)launchToGuestApp {
145145
if (NSClassFromString(@"LCSharedUtils")) {
146146
// urlScheme = @"livecontainer://livecontainer-launch?bundle-name=%@.app";
147147
} else {
148+
NSInteger jitEnabler = [gcUserDefaults integerForKey:@"JIT_ENABLER"];
149+
if (!jitEnabler)
150+
jitEnabler = 0;
148151
NSString* tsPath = [NSString stringWithFormat:@"%@/../_TrollStore", gcMainBundle.bundlePath];
149-
if (!access(tsPath.UTF8String, F_OK)) {
152+
if ((jitEnabler == 0 && !access(tsPath.UTF8String, F_OK)) || jitEnabler == 1) {
150153
urlScheme = @"apple-magnifier://enable-jit?bundle-id=%@";
151-
} else if ([application canOpenURL:[NSURL URLWithString:@"stikjit://"]]) {
154+
} else if ((jitEnabler == 0 && [application canOpenURL:[NSURL URLWithString:@"stikjit://"]]) || jitEnabler == 2) {
152155
urlScheme = @"stikjit://enable-jit?bundle-id=%@";
153-
} else if ([application canOpenURL:[NSURL URLWithString:@"sidestore://"]]) {
156+
} else if ((jitEnabler == 0 && [application canOpenURL:[NSURL URLWithString:@"sidestore://"]]) || jitEnabler == 5) {
154157
urlScheme = @"sidestore://sidejit-enable?bid=%@";
155158
} else if (self.certificatePassword) {
156159
tries = 2;
@@ -173,25 +176,31 @@ + (BOOL)launchToGuestApp {
173176
}
174177

175178
+ (BOOL)askForJIT {
176-
NSString* sideJITServerAddress = [gcUserDefaults objectForKey:@"SideJITServerAddr"];
177-
if (!sideJITServerAddress || ![gcUserDefaults boolForKey:@"AUTO_JIT"]) {
178-
if ([gcUserDefaults boolForKey:@"AUTO_JIT"]) {
179-
[Utils showErrorGlobal:@"JITStreamer Server Address not set." error:nil];
180-
return NO;
181-
}
179+
NSInteger jitEnabler = [gcUserDefaults integerForKey:@"JIT_ENABLER"];
180+
if (!jitEnabler)
181+
jitEnabler = 0;
182+
if (jitEnabler != 3 && jitEnabler != 4)
182183
return YES;
184+
NSString* sideJITServerAddress = [gcUserDefaults objectForKey:@"SideJITServerAddr"];
185+
NSString* deviceUDID = [gcUserDefaults objectForKey:@"JITDeviceUDID"];
186+
if (!sideJITServerAddress || (!deviceUDID && jitEnabler == 4)) {
187+
[Utils showErrorGlobal:@"Server Address not set." error:nil];
188+
return NO;
183189
}
184-
AppLog(@"Launching the app with JITStreamer: %@/launch_app/%@", sideJITServerAddress, gcMainBundle.bundleIdentifier);
185190
NSString* launchJITUrlStr = [NSString stringWithFormat:@"%@/launch_app/%@", sideJITServerAddress, gcMainBundle.bundleIdentifier];
191+
if (jitEnabler == 4) {
192+
launchJITUrlStr = [NSString stringWithFormat:@"%@/%@/%@", sideJITServerAddress, deviceUDID, gcMainBundle.bundleIdentifier];
193+
}
194+
AppLog(@"Launching the app with URL: %@", launchJITUrlStr);
186195
NSURLSession* session = [NSURLSession sharedSession];
187196
NSURL* launchJITUrl = [NSURL URLWithString:launchJITUrlStr];
188197
NSURLRequest* req = [[NSURLRequest alloc] initWithURL:launchJITUrl];
189198
NSURLSessionDataTask* task = [session dataTaskWithRequest:req completionHandler:^(NSData* _Nullable data, NSURLResponse* _Nullable response, NSError* _Nullable error) {
190199
if (error) {
191200
return dispatch_async(dispatch_get_main_queue(), ^{
192-
[Utils showErrorGlobal:[NSString stringWithFormat:@"(%@/launch_app/%@) Failed to contact JITStreamer.\nIf you don't have JITStreamer-EB, disable Auto JIT and use "
193-
@"\"Manual reopen with JIT\" if launching doesn't work.",
194-
sideJITServerAddress, gcMainBundle.bundleIdentifier]
201+
[Utils showErrorGlobal:[NSString stringWithFormat:@"(%@) Failed to contact JITStreamer.\nIf you don't have JITStreamer-EB, disable Auto JIT and use \"Manual "
202+
@"reopen with JIT\" if launching doesn't work.",
203+
launchJITUrlStr]
195204
error:error];
196205
AppLog(@"Tried connecting with %@, failed to contact JITStreamer: %@", launchJITUrlStr, error);
197206
});

src/LogsView.m

+6-2
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,12 @@ - (void)viewDidLoad {
5353
NSError* error;
5454

5555
if ([self.fileURL checkResourceIsReachableAndReturnError:&error]) {
56-
self.textView.text = [NSString stringWithFormat:@"%@\n============================\n%@", self.fileURL.lastPathComponent,
57-
[NSString stringWithContentsOfURL:self.fileURL encoding:NSUTF8StringEncoding error:&error]];
56+
NSString* fileName = self.fileURL.lastPathComponent;
57+
if ([fileName isEqualToString:@"app.log"]) {
58+
fileName = [NSString stringWithFormat:@"app.log (Clearing in %lu launches)", (5 - [[Utils getPrefs] integerForKey:@"LAUNCH_COUNT"] % 5)];
59+
}
60+
self.textView.text = [NSString
61+
stringWithFormat:@"%@\n============================\n%@", fileName, [NSString stringWithContentsOfURL:self.fileURL encoding:NSUTF8StringEncoding error:&error]];
5862
}
5963
if (error) {
6064
AppLog(@"Error reading log file: %@", error);

0 commit comments

Comments
 (0)