diff --git a/Makefile b/Makefile index 6e39fc0..5679496 100644 --- a/Makefile +++ b/Makefile @@ -244,7 +244,7 @@ CORE_FILTER += Core/debugger.c Core/sm83_disassembler.c Core/symbol_hash.c LDFLAGS += -arch arm64 OCFLAGS += -x objective-c -fobjc-arc -Wno-deprecated-declarations -isysroot $(SYSROOT) LDFLAGS += -miphoneos-version-min=11.0 -isysroot $(SYSROOT) -REREGISTER_LDFLAGS := $(LDFLAGS) -lobjc -framework CoreServices -framework Foundation +IOS_INSTALLER_LDFLAGS := $(LDFLAGS) -lobjc -framework CoreServices -framework Foundation LDFLAGS += -lobjc -framework UIKit -framework Foundation -framework CoreGraphics -framework Metal -framework MetalKit -framework AudioToolbox -framework AVFoundation -framework QuartzCore -framework CoreMotion -framework CoreVideo -framework CoreMedia -framework CoreImage -framework UserNotifications -weak_framework CoreHaptics CODESIGN := codesign -fs - else @@ -325,7 +325,7 @@ quicklook: $(BIN)/SameBoy.qlgenerator sdl: $(SDL_TARGET) $(BIN)/SDL/dmg_boot.bin $(BIN)/SDL/mgb_boot.bin $(BIN)/SDL/cgb0_boot.bin $(BIN)/SDL/cgb_boot.bin $(BIN)/SDL/agb_boot.bin $(BIN)/SDL/sgb_boot.bin $(BIN)/SDL/sgb2_boot.bin $(BIN)/SDL/LICENSE $(BIN)/SDL/registers.sym $(BIN)/SDL/background.bmp $(BIN)/SDL/Shaders $(BIN)/SDL/Palettes bootroms: $(BIN)/BootROMs/agb_boot.bin $(BIN)/BootROMs/cgb_boot.bin $(BIN)/BootROMs/cgb0_boot.bin $(BIN)/BootROMs/dmg_boot.bin $(BIN)/BootROMs/mgb_boot.bin $(BIN)/BootROMs/sgb_boot.bin $(BIN)/BootROMs/sgb2_boot.bin tester: $(TESTER_TARGET) $(BIN)/tester/dmg_boot.bin $(BIN)/tester/cgb_boot.bin $(BIN)/tester/agb_boot.bin $(BIN)/tester/sgb_boot.bin $(BIN)/tester/sgb2_boot.bin -_ios: $(BIN)/SameBoy-iOS.app $(OBJ)/reregister +_ios: $(BIN)/SameBoy-iOS.app $(OBJ)/installer ios-ipa: $(BIN)/SameBoy-iOS.ipa ios-deb: $(BIN)/SameBoy-iOS.deb ifeq ($(PLATFORM),windows32) @@ -344,7 +344,7 @@ CORE_SOURCES := $(filter-out $(CORE_FILTER),$(shell ls Core/*.c)) CORE_HEADERS := $(shell ls Core/*.h) SDL_SOURCES := $(shell ls SDL/*.c) $(OPEN_DIALOG) $(patsubst %,SDL/audio/%.c,$(SDL_AUDIO_DRIVERS)) TESTER_SOURCES := $(shell ls Tester/*.c) -IOS_SOURCES := $(filter-out iOS/reregister.m, $(shell ls iOS/*.m)) $(shell ls AppleCommon/*.m) +IOS_SOURCES := $(filter-out iOS/installer.m, $(shell ls iOS/*.m)) $(shell ls AppleCommon/*.m) COCOA_SOURCES := $(shell ls Cocoa/*.m) $(shell ls HexFiend/*.m) $(shell ls JoyKit/*.m) $(shell ls AppleCommon/*.m) QUICKLOOK_SOURCES := $(shell ls QuickLook/*.m) $(shell ls QuickLook/*.c) @@ -449,9 +449,8 @@ ifeq ($(CONF), release) $(STRIP) $@ endif -$(OBJ)/reregister: iOS/reregister.m iOS/reregister.entitlements - $(CC) $< -o $@ $(REREGISTER_LDFLAGS) $(CFLAGS) - codesign -fs - --entitlements iOS/reregister.entitlements $@ +$(OBJ)/installer: iOS/installer.m + $(CC) $< -o $@ $(IOS_INSTALLER_LDFLAGS) $(CFLAGS) # Cocoa Port @@ -697,20 +696,22 @@ $(BIN)/SameBoy-iOS.deb: $(OBJ)/debian-binary $(OBJ)/control.tar.gz $(OBJ)/data.t -@$(MKDIR) -p $(dir $@) (cd $(OBJ) && ar cr $(abspath $@) $(notdir $^)) -$(OBJ)/data.tar.gz: ios iOS/jailbreak.entitlements - $(MKDIR) -p $(OBJ)/Applications - cp -rf $(BIN)/SameBoy-iOS.app $(OBJ)/Applications/SameBoy-iOS.app - cp build/obj-ios/reregister $(OBJ)/Applications/SameBoy-iOS.app - codesign -fs - --entitlements iOS/jailbreak.entitlements $(OBJ)/Applications/SameBoy-iOS.app - (cd $(OBJ) && tar -czf $(abspath $@) --format ustar --uid 501 --gid 501 --numeric-owner ./Applications) - rm -rf $(OBJ)/Applications +$(OBJ)/data.tar.gz: ios iOS/jailbreak.entitlements iOS/installer.entitlements + $(MKDIR) -p $(OBJ)/private/var/containers/ + cp -rf $(BIN)/SameBoy-iOS.app $(OBJ)/private/var/containers/SameBoy-iOS.app + cp build/obj-ios/installer $(OBJ)/private/var/containers/SameBoy-iOS.app + codesign -fs - --entitlements iOS/installer.entitlements $(OBJ)/private/var/containers/SameBoy-iOS.app/installer + codesign -fs - --entitlements iOS/jailbreak.entitlements $(OBJ)/private/var/containers/SameBoy-iOS.app + (cd $(OBJ) && tar -czf $(abspath $@) --format ustar --uid 501 --gid 501 --numeric-owner ./private) + rm -rf $(OBJ)/private/ -$(OBJ)/control.tar.gz: iOS/deb-postinst iOS/deb-control +$(OBJ)/control.tar.gz: iOS/deb-postinst iOS/deb-prerm iOS/deb-control -@$(MKDIR) -p $(dir $@) sed "s/@VERSION/$(VERSION)/" < iOS/deb-control > $(OBJ)/control ln iOS/deb-postinst $(OBJ)/postinst - (cd $(OBJ) && tar -czf $(abspath $@) --format ustar --uid 501 --gid 501 --numeric-owner ./control ./postinst) - rm $(OBJ)/control $(OBJ)/postinst + ln iOS/deb-prerm $(OBJ)/prerm + (cd $(OBJ) && tar -czf $(abspath $@) --format ustar --uid 501 --gid 501 --numeric-owner ./control ./postinst ./prerm) + rm $(OBJ)/control $(OBJ)/postinst $(OBJ)/prerm $(OBJ)/debian-binary: -@$(MKDIR) -p $(dir $@) diff --git a/iOS/deb-control b/iOS/deb-control index 7f3002e..4c92a80 100644 --- a/iOS/deb-control +++ b/iOS/deb-control @@ -1,7 +1,7 @@ Package: com.github.liji32.sameboy.ios Name: SameBoy Depends: firmware (>= 11.0) -Architecture: iphoneos-arm +Architecture: all Description: A Game Boy emulator for iOS Maintainer: Lior Halphon Author: Lior Halphon diff --git a/iOS/deb-postinst b/iOS/deb-postinst index ed91d43..13dc0e2 100755 --- a/iOS/deb-postinst +++ b/iOS/deb-postinst @@ -1,2 +1,2 @@ #!/bin/bash -/Applications/SameBoy-iOS.app/reregister +/private/var/containers/SameBoy-iOS.app/installer install diff --git a/iOS/deb-prerm b/iOS/deb-prerm new file mode 100755 index 0000000..849f266 --- /dev/null +++ b/iOS/deb-prerm @@ -0,0 +1,2 @@ +#!/bin/bash +/Applications/SameBoy-iOS.app/installer uninstall || /var/jb/Applications/SameBoy-iOS.app/installer uninstall diff --git a/iOS/reregister.entitlements b/iOS/installer.entitlements similarity index 89% rename from iOS/reregister.entitlements rename to iOS/installer.entitlements index c1ed56b..5dd0f8a 100644 --- a/iOS/reregister.entitlements +++ b/iOS/installer.entitlements @@ -15,5 +15,7 @@ platform-application +com.apple.private.security.no-container + \ No newline at end of file diff --git a/iOS/installer.m b/iOS/installer.m new file mode 100644 index 0000000..2fa2ff6 --- /dev/null +++ b/iOS/installer.m @@ -0,0 +1,105 @@ +#import +#import +#import + +@interface LSApplicationProxy : NSObject +@property (readonly, getter=isContainerized) bool containerized; +@property (readonly) NSString *bundleIdentifier; +@property (readonly) NSURL * bundleURL; +@end + +@interface LSApplicationWorkspace : NSObject ++ (instancetype)defaultWorkspace; +- (NSArray *)allInstalledApplications; +- (bool)unregisterApplication:(NSURL *)url; +- (bool)registerApplicationDictionary:(NSDictionary *)dict; +@end + +@interface MCMAppDataContainer : NSObject ++ (MCMAppDataContainer *)containerWithIdentifier:(NSString *)identifier + createIfNecessary:(bool)create + existed:(bool *)existed + error:(NSError **)error; +@property(readonly) NSURL *url; +@end + + +int main(int argc, char **argv) +{ + if (argc != 2) return 1; + // Make sure MobileContainerManager is loaded + if (!dlopen("/System/Library/PrivateFrameworks/MobileContainerManager.framework/MobileContainerManager", RTLD_NOW)) return 1; + + bool uninstall = false; + if (strcmp(argv[1], "uninstall") == 0) { + uninstall = true; + } + else if (strcmp(argv[1], "install") != 0) { + return 1; + } + + NSString *installPath = @"/var/jb/Applications/SameBoy-iOS.app"; + if (access("/Applications/", W_OK) == 0) { + installPath = @"/Applications/SameBoy-iOS.app"; + } + NSLog(@"Install path is %@", installPath); + + for (LSApplicationProxy *app in [[LSApplicationWorkspace defaultWorkspace] allInstalledApplications]) { + if (![app.bundleIdentifier isEqualToString:[NSBundle mainBundle].bundleIdentifier]) continue; + if (![app.bundleURL.path.stringByResolvingSymlinksInPath isEqual:installPath.stringByResolvingSymlinksInPath]) { + // Already installed elsewhere + NSLog(@"Already installed at %@", app.bundleURL.path); + return 1; + } + + NSLog(@"Unregistering previous installation"); + // We're registered but not containerized (or just uninstalling), unregister ourselves first + if (![[LSApplicationWorkspace defaultWorkspace] unregisterApplication:app.bundleURL]) return 1; + + break; + } + + // Don't modify files if we're at the correct path already + if (uninstall || ![[NSBundle mainBundle].bundlePath.stringByResolvingSymlinksInPath isEqual:installPath.stringByResolvingSymlinksInPath]) { + // Remove any previous copy + NSError *error = nil; + if (!access(installPath.UTF8String, F_OK)) { + NSLog(@"Removing previous installation"); + [[NSFileManager defaultManager] removeItemAtPath:installPath error:&error]; + if (error) { + NSLog(@"Error: %@", error); + return 1; + } + } + + // If we're uninstalling, we're done + if (uninstall) return 0; + + NSLog(@"Installing..."); + + [[NSFileManager defaultManager] moveItemAtPath:[NSBundle mainBundle].bundlePath toPath:installPath error:&error]; + if (error) { + NSLog(@"Error: %@", error); + return 1; + } + } + + + NSLog(@"Registering..."); + + NSString *container = [objc_getClass("MCMAppDataContainer") containerWithIdentifier:[NSBundle mainBundle].bundleIdentifier + createIfNecessary:true + existed:nil + error:nil].url.path; + + return ![[LSApplicationWorkspace defaultWorkspace] registerApplicationDictionary:@{ + @"ApplicationType": @"System", + @"CFBundleIdentifier": [NSBundle mainBundle].bundleIdentifier, + @"CompatibilityState": @NO, + @"Container": container, + @"IsDeletable": @NO, + @"Path": installPath, + @"_LSBundlePlugins": @{}, + @"IsContainerized": @YES, + }]; +} diff --git a/iOS/reregister.m b/iOS/reregister.m deleted file mode 100644 index 49885ba..0000000 --- a/iOS/reregister.m +++ /dev/null @@ -1,54 +0,0 @@ -#import -#import -#import - -@interface LSApplicationProxy : NSObject -@property (nonatomic, readonly, getter=isContainerized) bool containerized; -@property (nonatomic, readonly) NSString *bundleIdentifier; -@end - -@interface LSApplicationWorkspace : NSObject -+ (instancetype)defaultWorkspace; -- (NSArray *)allInstalledApplications; -- (bool)unregisterApplication:(NSURL *)url; -- (bool)registerApplicationDictionary:(NSDictionary *)dict; -@end - -@interface MCMAppDataContainer : NSObject -+ (MCMAppDataContainer *)containerWithIdentifier:(NSString *)identifier - createIfNecessary:(bool)create - existed:(bool *)existed - error:(NSError **)error; -@property(readonly, nonatomic) NSURL *url; -@end - - -int main(void) -{ - // Make sure MobileContainerManager is loaded - if (!dlopen("/System/Library/PrivateFrameworks/MobileContainerManager.framework/MobileContainerManager", RTLD_NOW)) return 1; - for (LSApplicationProxy *app in [[LSApplicationWorkspace defaultWorkspace] allInstalledApplications]) { - if (![app.bundleIdentifier isEqualToString:[NSBundle mainBundle].bundleIdentifier]) continue; - if (app.containerized) return 0; // Everything's fine, no need to reregister - // We're registered but not containerized, unregister ourselves first - if (![[LSApplicationWorkspace defaultWorkspace] unregisterApplication:[NSBundle mainBundle].bundleURL]) return 1; - - break; - } - - NSString *container = [objc_getClass("MCMAppDataContainer") containerWithIdentifier:[NSBundle mainBundle].bundleIdentifier - createIfNecessary:true - existed:nil - error:nil].url.path; - - return ![[LSApplicationWorkspace defaultWorkspace] registerApplicationDictionary:@{ - @"ApplicationType": @"System", - @"CFBundleIdentifier": [NSBundle mainBundle].bundleIdentifier, - @"CompatibilityState": @NO, - @"Container": container, - @"IsDeletable": @NO, - @"Path": [NSBundle mainBundle].bundlePath, - @"_LSBundlePlugins": @{}, - @"IsContainerized": @YES, - }]; -}