diff --git a/Delta.xcodeproj/project.pbxproj b/Delta.xcodeproj/project.pbxproj index 07a2a0e..2e0c5fd 100644 --- a/Delta.xcodeproj/project.pbxproj +++ b/Delta.xcodeproj/project.pbxproj @@ -93,6 +93,7 @@ BF63A1B521A4B76E00EE8F61 /* RecordVersionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF63A1B421A4B76E00EE8F61 /* RecordVersionsViewController.swift */; }; BF6424831F5B8F3F00D6AB44 /* ListMenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6424821F5B8F3F00D6AB44 /* ListMenuViewController.swift */; }; BF6424851F5CBDC900D6AB44 /* UIView+ParentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6424841F5CBDC900D6AB44 /* UIView+ParentViewController.swift */; }; + BF647A6A22FB8FCE0061D76D /* Bundle+SwizzleBundleID.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF647A6922FB8FCE0061D76D /* Bundle+SwizzleBundleID.swift */; }; BF6866171DCAC8B900BF2D06 /* ControllerSkin+Configuring.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6866161DCAC8B900BF2D06 /* ControllerSkin+Configuring.swift */; }; BF696B801D9B2B02009639E0 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF696B7F1D9B2B02009639E0 /* Theme.swift */; }; BF6BF3131EB7E47F008E83CD /* ImportOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6BF3121EB7E47F008E83CD /* ImportOption.swift */; }; @@ -279,6 +280,7 @@ BF63BDE91D389EEB00FCB040 /* GameViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameViewController.swift; sourceTree = ""; }; BF6424821F5B8F3F00D6AB44 /* ListMenuViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListMenuViewController.swift; sourceTree = ""; }; BF6424841F5CBDC900D6AB44 /* UIView+ParentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+ParentViewController.swift"; sourceTree = ""; }; + BF647A6922FB8FCE0061D76D /* Bundle+SwizzleBundleID.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+SwizzleBundleID.swift"; sourceTree = ""; }; BF6866161DCAC8B900BF2D06 /* ControllerSkin+Configuring.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ControllerSkin+Configuring.swift"; sourceTree = ""; }; BF696B7F1D9B2B02009639E0 /* Theme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = ""; }; BF6B82A41F7CC2A300042BFB /* GameControllerInputMappingTransformer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameControllerInputMappingTransformer.swift; sourceTree = ""; }; @@ -395,6 +397,7 @@ BFC3627F21ADE2BA00EF2BE6 /* UIAlertController+Error.swift */, BF1F45AC21AF57BA00EF9895 /* HarmonyMetadataKey+Keys.swift */, BFFBD3D8224A0756002EFC79 /* URL+ExtendedAttributes.swift */, + BF647A6922FB8FCE0061D76D /* Bundle+SwizzleBundleID.swift */, ); path = Extensions; sourceTree = ""; @@ -1026,6 +1029,7 @@ BFC6F7B81F435BC500221B96 /* Input+Display.swift in Sources */, BF59426A1E09BBD00051894B /* GridCollectionViewCell.swift in Sources */, BF6BF3181EB82111008E83CD /* iTunesImportOption.swift in Sources */, + BF647A6A22FB8FCE0061D76D /* Bundle+SwizzleBundleID.swift in Sources */, BFF6452E1F7CC5060056533E /* GameControllerInputMappingTransformer.swift in Sources */, BF59427C1E09BC830051894B /* Cheat.swift in Sources */, BFBAB2E31EB685A2004E0B0E /* DeltaCoreProtocol+Delta.swift in Sources */, @@ -1311,6 +1315,7 @@ DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = "Delta/Supporting Files/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" -DDEBUG"; PROVISIONING_PROFILE = ""; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Delta/Supporting Files/Delta-Bridging-Header.h"; diff --git a/Delta/AppDelegate.swift b/Delta/AppDelegate.swift index e53bd0a..c6708eb 100644 --- a/Delta/AppDelegate.swift +++ b/Delta/AppDelegate.swift @@ -28,9 +28,24 @@ class AppDelegate: UIResponder, UIApplicationDelegate System.allCases.forEach { Delta.register($0.deltaCore) } + #if DEBUG + // Must go AFTER registering cores, or else NESDeltaCore may not work correctly when not connected to debugger 🤷‍♂️ Fabric.with([Crashlytics.self]) + #else + + // Fabric doesn't allow us to change what value it uses for the bundle identifier. + // Normally this wouldn't be an issue, except AltStore creates a unique bundle identifier per user. + // Rather than have every copy of Delta be listed separately in Fabric, we temporarily swizzle Bundle.infoDictionary + // to return a constant identifier while Fabric is starting up. This way, Fabric will now group + // all copies of Delta under the bundle identifier "com.rileytestut.Delta.AltStore". + Bundle.swizzleBundleID { + Fabric.with([Crashlytics.self]) + } + + #endif + self.configureAppearance() // Controllers diff --git a/Delta/Extensions/Bundle+SwizzleBundleID.swift b/Delta/Extensions/Bundle+SwizzleBundleID.swift new file mode 100644 index 0000000..e876bc7 --- /dev/null +++ b/Delta/Extensions/Bundle+SwizzleBundleID.swift @@ -0,0 +1,38 @@ +// +// Bundle+SwizzleBundleID.swift +// Delta +// +// Created by Riley Testut on 8/7/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +import Foundation +import ObjectiveC.runtime + +extension Bundle +{ + @objc private var swizzled_infoDictionary: [String : Any]? { + var infoDictionary = self.swizzled_infoDictionary + infoDictionary?[kCFBundleIdentifierKey as String] = "com.rileytestut.Delta.AltStore" + return infoDictionary + } + + public static func swizzleBundleID(handler: () -> Void) + { + let bundleClass: AnyClass = Bundle.self + + guard + let originalMethod = class_getInstanceMethod(bundleClass, #selector(getter: Bundle.infoDictionary)), + let swizzledMethod = class_getInstanceMethod(bundleClass, #selector(getter: Bundle.swizzled_infoDictionary)) + else { + print("Failed to swizzle Bundle.infoDictionary.") + return + } + + method_exchangeImplementations(originalMethod, swizzledMethod) + + handler() + + method_exchangeImplementations(swizzledMethod, originalMethod) + } +}