├── .gitattributes ├── .gitignore ├── ModMyIPA.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── swiftpm │ │ └── Package.resolved └── xcuserdata │ └── xiaobowen.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── ModMyIPA.xml ├── ModMyIPA ├── Assets.xcassets │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ ├── 1024.png │ │ └── Contents.json │ ├── Contents.json │ └── appicon.imageset │ │ ├── Contents.json │ │ └── icon.png ├── ContentView.swift ├── Launch Screen.storyboard ├── Managers │ ├── IPAFile.swift │ └── MyFileManager.swift ├── Misc │ ├── Extensions.swift │ ├── FilePaths.swift │ ├── MyUserDefaults.swift │ └── Version.swift ├── ModMyIPAApp.swift ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json ├── ShareSheet.swift └── Views │ ├── EditAppInfoView.swift │ ├── InfoView.swift │ ├── MainView.swift │ └── PackageListView.swift ├── README.md ├── Screenshots ├── 01.png ├── 02.png └── 03.png └── compile.command /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Payload 2 | .DS_Store 3 | build 4 | *.ipa 5 | *.xcuserstate 6 | -------------------------------------------------------------------------------- /ModMyIPA.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 56; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | B58A5FA129064F4100926816 /* ModMyIPAApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58A5FA029064F4100926816 /* ModMyIPAApp.swift */; }; 11 | B58A5FA329064F4100926816 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58A5FA229064F4100926816 /* ContentView.swift */; }; 12 | B58A5FA529064F4300926816 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B58A5FA429064F4300926816 /* Assets.xcassets */; }; 13 | B58A5FA829064F4300926816 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B58A5FA729064F4300926816 /* Preview Assets.xcassets */; }; 14 | B58A5FB22906500A00926816 /* InfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58A5FB12906500A00926816 /* InfoView.swift */; }; 15 | B58A5FB42906501F00926816 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58A5FB32906501F00926816 /* MainView.swift */; }; 16 | B58A5FB62906509200926816 /* Version.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58A5FB52906509200926816 /* Version.swift */; }; 17 | B58A5FB8290653AF00926816 /* MyUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58A5FB7290653AF00926816 /* MyUserDefaults.swift */; }; 18 | B58A5FBA2906555000926816 /* FilePaths.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58A5FB92906555000926816 /* FilePaths.swift */; }; 19 | B58A5FBE29065DEA00926816 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B58A5FBD29065DEA00926816 /* Launch Screen.storyboard */; }; 20 | B58A5FC12906B12400926816 /* EditAppInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58A5FC02906B12400926816 /* EditAppInfoView.swift */; }; 21 | B58A5FC32906B15500926816 /* MyFileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58A5FC22906B15500926816 /* MyFileManager.swift */; }; 22 | B58A5FC72906B89D00926816 /* ZipArchive in Frameworks */ = {isa = PBXBuildFile; productRef = B58A5FC62906B89D00926816 /* ZipArchive */; }; 23 | B58A5FC92906BA3500926816 /* IPAFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58A5FC82906BA3500926816 /* IPAFile.swift */; }; 24 | B58A5FCB2906E95E00926816 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58A5FCA2906E95E00926816 /* Extensions.swift */; }; 25 | B58A5FCD290763AC00926816 /* PackageListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58A5FCC290763AB00926816 /* PackageListView.swift */; }; 26 | B58A5FCF2907D5E400926816 /* ShareSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58A5FCE2907D5E400926816 /* ShareSheet.swift */; }; 27 | /* End PBXBuildFile section */ 28 | 29 | /* Begin PBXFileReference section */ 30 | B58A5F9D29064F4100926816 /* ModMyIPA.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ModMyIPA.app; sourceTree = BUILT_PRODUCTS_DIR; }; 31 | B58A5FA029064F4100926816 /* ModMyIPAApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModMyIPAApp.swift; sourceTree = ""; }; 32 | B58A5FA229064F4100926816 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 33 | B58A5FA429064F4300926816 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 34 | B58A5FA729064F4300926816 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 35 | B58A5FB12906500A00926816 /* InfoView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InfoView.swift; sourceTree = ""; }; 36 | B58A5FB32906501F00926816 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; 37 | B58A5FB52906509200926816 /* Version.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Version.swift; sourceTree = ""; }; 38 | B58A5FB7290653AF00926816 /* MyUserDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyUserDefaults.swift; sourceTree = ""; }; 39 | B58A5FB92906555000926816 /* FilePaths.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilePaths.swift; sourceTree = ""; }; 40 | B58A5FBD29065DEA00926816 /* Launch Screen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = ""; }; 41 | B58A5FC02906B12400926816 /* EditAppInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditAppInfoView.swift; sourceTree = ""; }; 42 | B58A5FC22906B15500926816 /* MyFileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyFileManager.swift; sourceTree = ""; }; 43 | B58A5FC82906BA3500926816 /* IPAFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IPAFile.swift; sourceTree = ""; }; 44 | B58A5FCA2906E95E00926816 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; 45 | B58A5FCC290763AB00926816 /* PackageListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PackageListView.swift; sourceTree = ""; }; 46 | B58A5FCE2907D5E400926816 /* ShareSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareSheet.swift; sourceTree = ""; }; 47 | /* End PBXFileReference section */ 48 | 49 | /* Begin PBXFrameworksBuildPhase section */ 50 | B58A5F9A29064F4100926816 /* Frameworks */ = { 51 | isa = PBXFrameworksBuildPhase; 52 | buildActionMask = 2147483647; 53 | files = ( 54 | B58A5FC72906B89D00926816 /* ZipArchive in Frameworks */, 55 | ); 56 | runOnlyForDeploymentPostprocessing = 0; 57 | }; 58 | /* End PBXFrameworksBuildPhase section */ 59 | 60 | /* Begin PBXGroup section */ 61 | B58A5F9429064F4000926816 = { 62 | isa = PBXGroup; 63 | children = ( 64 | B58A5F9F29064F4100926816 /* ModMyIPA */, 65 | B58A5F9E29064F4100926816 /* Products */, 66 | ); 67 | sourceTree = ""; 68 | }; 69 | B58A5F9E29064F4100926816 /* Products */ = { 70 | isa = PBXGroup; 71 | children = ( 72 | B58A5F9D29064F4100926816 /* ModMyIPA.app */, 73 | ); 74 | name = Products; 75 | sourceTree = ""; 76 | }; 77 | B58A5F9F29064F4100926816 /* ModMyIPA */ = { 78 | isa = PBXGroup; 79 | children = ( 80 | B58A5FA029064F4100926816 /* ModMyIPAApp.swift */, 81 | B58A5FA229064F4100926816 /* ContentView.swift */, 82 | B58A5FCE2907D5E400926816 /* ShareSheet.swift */, 83 | B58A5FC42906B5BE00926816 /* Managers */, 84 | B58A5FBF2906AD0300926816 /* Misc */, 85 | B58A5FB02906500A00926816 /* Views */, 86 | B58A5FA429064F4300926816 /* Assets.xcassets */, 87 | B58A5FBD29065DEA00926816 /* Launch Screen.storyboard */, 88 | B58A5FA629064F4300926816 /* Preview Content */, 89 | ); 90 | path = ModMyIPA; 91 | sourceTree = ""; 92 | }; 93 | B58A5FA629064F4300926816 /* Preview Content */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | B58A5FA729064F4300926816 /* Preview Assets.xcassets */, 97 | ); 98 | path = "Preview Content"; 99 | sourceTree = ""; 100 | }; 101 | B58A5FB02906500A00926816 /* Views */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | B58A5FB32906501F00926816 /* MainView.swift */, 105 | B58A5FC02906B12400926816 /* EditAppInfoView.swift */, 106 | B58A5FB12906500A00926816 /* InfoView.swift */, 107 | B58A5FCC290763AB00926816 /* PackageListView.swift */, 108 | ); 109 | name = Views; 110 | path = ModMyIPA/Views; 111 | sourceTree = SOURCE_ROOT; 112 | }; 113 | B58A5FBF2906AD0300926816 /* Misc */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | B58A5FB52906509200926816 /* Version.swift */, 117 | B58A5FB7290653AF00926816 /* MyUserDefaults.swift */, 118 | B58A5FB92906555000926816 /* FilePaths.swift */, 119 | B58A5FCA2906E95E00926816 /* Extensions.swift */, 120 | ); 121 | path = Misc; 122 | sourceTree = ""; 123 | }; 124 | B58A5FC42906B5BE00926816 /* Managers */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | B58A5FC22906B15500926816 /* MyFileManager.swift */, 128 | B58A5FC82906BA3500926816 /* IPAFile.swift */, 129 | ); 130 | path = Managers; 131 | sourceTree = ""; 132 | }; 133 | /* End PBXGroup section */ 134 | 135 | /* Begin PBXNativeTarget section */ 136 | B58A5F9C29064F4100926816 /* ModMyIPA */ = { 137 | isa = PBXNativeTarget; 138 | buildConfigurationList = B58A5FAB29064F4300926816 /* Build configuration list for PBXNativeTarget "ModMyIPA" */; 139 | buildPhases = ( 140 | B58A5F9929064F4100926816 /* Sources */, 141 | B58A5F9A29064F4100926816 /* Frameworks */, 142 | B58A5F9B29064F4100926816 /* Resources */, 143 | ); 144 | buildRules = ( 145 | ); 146 | dependencies = ( 147 | ); 148 | name = ModMyIPA; 149 | packageProductDependencies = ( 150 | B58A5FC62906B89D00926816 /* ZipArchive */, 151 | ); 152 | productName = ModMyIPA; 153 | productReference = B58A5F9D29064F4100926816 /* ModMyIPA.app */; 154 | productType = "com.apple.product-type.application"; 155 | }; 156 | /* End PBXNativeTarget section */ 157 | 158 | /* Begin PBXProject section */ 159 | B58A5F9529064F4000926816 /* Project object */ = { 160 | isa = PBXProject; 161 | attributes = { 162 | BuildIndependentTargetsInParallel = 1; 163 | LastSwiftUpdateCheck = 1400; 164 | LastUpgradeCheck = 1400; 165 | TargetAttributes = { 166 | B58A5F9C29064F4100926816 = { 167 | CreatedOnToolsVersion = 14.0.1; 168 | }; 169 | }; 170 | }; 171 | buildConfigurationList = B58A5F9829064F4000926816 /* Build configuration list for PBXProject "ModMyIPA" */; 172 | compatibilityVersion = "Xcode 14.0"; 173 | developmentRegion = en; 174 | hasScannedForEncodings = 0; 175 | knownRegions = ( 176 | en, 177 | Base, 178 | ); 179 | mainGroup = B58A5F9429064F4000926816; 180 | packageReferences = ( 181 | B58A5FC52906B89D00926816 /* XCRemoteSwiftPackageReference "ZipArchive" */, 182 | ); 183 | productRefGroup = B58A5F9E29064F4100926816 /* Products */; 184 | projectDirPath = ""; 185 | projectRoot = ""; 186 | targets = ( 187 | B58A5F9C29064F4100926816 /* ModMyIPA */, 188 | ); 189 | }; 190 | /* End PBXProject section */ 191 | 192 | /* Begin PBXResourcesBuildPhase section */ 193 | B58A5F9B29064F4100926816 /* Resources */ = { 194 | isa = PBXResourcesBuildPhase; 195 | buildActionMask = 2147483647; 196 | files = ( 197 | B58A5FBE29065DEA00926816 /* Launch Screen.storyboard in Resources */, 198 | B58A5FA829064F4300926816 /* Preview Assets.xcassets in Resources */, 199 | B58A5FA529064F4300926816 /* Assets.xcassets in Resources */, 200 | ); 201 | runOnlyForDeploymentPostprocessing = 0; 202 | }; 203 | /* End PBXResourcesBuildPhase section */ 204 | 205 | /* Begin PBXSourcesBuildPhase section */ 206 | B58A5F9929064F4100926816 /* Sources */ = { 207 | isa = PBXSourcesBuildPhase; 208 | buildActionMask = 2147483647; 209 | files = ( 210 | B58A5FA329064F4100926816 /* ContentView.swift in Sources */, 211 | B58A5FB62906509200926816 /* Version.swift in Sources */, 212 | B58A5FB8290653AF00926816 /* MyUserDefaults.swift in Sources */, 213 | B58A5FB42906501F00926816 /* MainView.swift in Sources */, 214 | B58A5FC92906BA3500926816 /* IPAFile.swift in Sources */, 215 | B58A5FCF2907D5E400926816 /* ShareSheet.swift in Sources */, 216 | B58A5FBA2906555000926816 /* FilePaths.swift in Sources */, 217 | B58A5FB22906500A00926816 /* InfoView.swift in Sources */, 218 | B58A5FCD290763AC00926816 /* PackageListView.swift in Sources */, 219 | B58A5FC32906B15500926816 /* MyFileManager.swift in Sources */, 220 | B58A5FC12906B12400926816 /* EditAppInfoView.swift in Sources */, 221 | B58A5FCB2906E95E00926816 /* Extensions.swift in Sources */, 222 | B58A5FA129064F4100926816 /* ModMyIPAApp.swift in Sources */, 223 | ); 224 | runOnlyForDeploymentPostprocessing = 0; 225 | }; 226 | /* End PBXSourcesBuildPhase section */ 227 | 228 | /* Begin XCBuildConfiguration section */ 229 | B58A5FA929064F4300926816 /* Debug */ = { 230 | isa = XCBuildConfiguration; 231 | buildSettings = { 232 | ALWAYS_SEARCH_USER_PATHS = NO; 233 | CLANG_ANALYZER_NONNULL = YES; 234 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 235 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 236 | CLANG_ENABLE_MODULES = YES; 237 | CLANG_ENABLE_OBJC_ARC = YES; 238 | CLANG_ENABLE_OBJC_WEAK = YES; 239 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 240 | CLANG_WARN_BOOL_CONVERSION = YES; 241 | CLANG_WARN_COMMA = YES; 242 | CLANG_WARN_CONSTANT_CONVERSION = YES; 243 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 244 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 245 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 246 | CLANG_WARN_EMPTY_BODY = YES; 247 | CLANG_WARN_ENUM_CONVERSION = YES; 248 | CLANG_WARN_INFINITE_RECURSION = YES; 249 | CLANG_WARN_INT_CONVERSION = YES; 250 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 251 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 252 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 253 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 254 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 255 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 256 | CLANG_WARN_STRICT_PROTOTYPES = YES; 257 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 258 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 259 | CLANG_WARN_UNREACHABLE_CODE = YES; 260 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 261 | COPY_PHASE_STRIP = NO; 262 | DEBUG_INFORMATION_FORMAT = dwarf; 263 | ENABLE_STRICT_OBJC_MSGSEND = YES; 264 | ENABLE_TESTABILITY = YES; 265 | GCC_C_LANGUAGE_STANDARD = gnu11; 266 | GCC_DYNAMIC_NO_PIC = NO; 267 | GCC_NO_COMMON_BLOCKS = YES; 268 | GCC_OPTIMIZATION_LEVEL = 0; 269 | GCC_PREPROCESSOR_DEFINITIONS = ( 270 | "DEBUG=1", 271 | "$(inherited)", 272 | ); 273 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 274 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 275 | GCC_WARN_UNDECLARED_SELECTOR = YES; 276 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 277 | GCC_WARN_UNUSED_FUNCTION = YES; 278 | GCC_WARN_UNUSED_VARIABLE = YES; 279 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 280 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 281 | MTL_FAST_MATH = YES; 282 | ONLY_ACTIVE_ARCH = YES; 283 | SDKROOT = iphoneos; 284 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 285 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 286 | }; 287 | name = Debug; 288 | }; 289 | B58A5FAA29064F4300926816 /* Release */ = { 290 | isa = XCBuildConfiguration; 291 | buildSettings = { 292 | ALWAYS_SEARCH_USER_PATHS = NO; 293 | CLANG_ANALYZER_NONNULL = YES; 294 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 295 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 296 | CLANG_ENABLE_MODULES = YES; 297 | CLANG_ENABLE_OBJC_ARC = YES; 298 | CLANG_ENABLE_OBJC_WEAK = YES; 299 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 300 | CLANG_WARN_BOOL_CONVERSION = YES; 301 | CLANG_WARN_COMMA = YES; 302 | CLANG_WARN_CONSTANT_CONVERSION = YES; 303 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 304 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 305 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 306 | CLANG_WARN_EMPTY_BODY = YES; 307 | CLANG_WARN_ENUM_CONVERSION = YES; 308 | CLANG_WARN_INFINITE_RECURSION = YES; 309 | CLANG_WARN_INT_CONVERSION = YES; 310 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 311 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 312 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 313 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 314 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 315 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 316 | CLANG_WARN_STRICT_PROTOTYPES = YES; 317 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 318 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 319 | CLANG_WARN_UNREACHABLE_CODE = YES; 320 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 321 | COPY_PHASE_STRIP = NO; 322 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 323 | ENABLE_NS_ASSERTIONS = NO; 324 | ENABLE_STRICT_OBJC_MSGSEND = YES; 325 | GCC_C_LANGUAGE_STANDARD = gnu11; 326 | GCC_NO_COMMON_BLOCKS = YES; 327 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 328 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 329 | GCC_WARN_UNDECLARED_SELECTOR = YES; 330 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 331 | GCC_WARN_UNUSED_FUNCTION = YES; 332 | GCC_WARN_UNUSED_VARIABLE = YES; 333 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 334 | MTL_ENABLE_DEBUG_INFO = NO; 335 | MTL_FAST_MATH = YES; 336 | SDKROOT = iphoneos; 337 | SWIFT_COMPILATION_MODE = wholemodule; 338 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 339 | VALIDATE_PRODUCT = YES; 340 | }; 341 | name = Release; 342 | }; 343 | B58A5FAC29064F4300926816 /* Debug */ = { 344 | isa = XCBuildConfiguration; 345 | buildSettings = { 346 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 347 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 348 | CODE_SIGN_STYLE = Automatic; 349 | CURRENT_PROJECT_VERSION = 2; 350 | DEVELOPMENT_ASSET_PATHS = "\"ModMyIPA/Preview Content\""; 351 | DEVELOPMENT_TEAM = L4LN9U3ZS7; 352 | ENABLE_PREVIEWS = YES; 353 | GENERATE_INFOPLIST_FILE = YES; 354 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 355 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 356 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 357 | INFOPLIST_KEY_UILaunchStoryboardName = "Launch Screen.storyboard"; 358 | INFOPLIST_KEY_UIRequiresFullScreen = YES; 359 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 360 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 361 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 362 | LD_RUNPATH_SEARCH_PATHS = ( 363 | "$(inherited)", 364 | "@executable_path/Frameworks", 365 | ); 366 | MARKETING_VERSION = 1.0; 367 | PRODUCT_BUNDLE_IDENTIFIER = com.powen.ModMyIPA; 368 | PRODUCT_NAME = "$(TARGET_NAME)"; 369 | SWIFT_EMIT_LOC_STRINGS = YES; 370 | SWIFT_VERSION = 5.0; 371 | TARGETED_DEVICE_FAMILY = "1,2"; 372 | }; 373 | name = Debug; 374 | }; 375 | B58A5FAD29064F4300926816 /* Release */ = { 376 | isa = XCBuildConfiguration; 377 | buildSettings = { 378 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 379 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 380 | CODE_SIGN_STYLE = Automatic; 381 | CURRENT_PROJECT_VERSION = 2; 382 | DEVELOPMENT_ASSET_PATHS = "\"ModMyIPA/Preview Content\""; 383 | DEVELOPMENT_TEAM = L4LN9U3ZS7; 384 | ENABLE_PREVIEWS = YES; 385 | GENERATE_INFOPLIST_FILE = YES; 386 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 387 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 388 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 389 | INFOPLIST_KEY_UILaunchStoryboardName = "Launch Screen.storyboard"; 390 | INFOPLIST_KEY_UIRequiresFullScreen = YES; 391 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 392 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 393 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 394 | LD_RUNPATH_SEARCH_PATHS = ( 395 | "$(inherited)", 396 | "@executable_path/Frameworks", 397 | ); 398 | MARKETING_VERSION = 1.0; 399 | PRODUCT_BUNDLE_IDENTIFIER = com.powen.ModMyIPA; 400 | PRODUCT_NAME = "$(TARGET_NAME)"; 401 | SWIFT_EMIT_LOC_STRINGS = YES; 402 | SWIFT_VERSION = 5.0; 403 | TARGETED_DEVICE_FAMILY = "1,2"; 404 | }; 405 | name = Release; 406 | }; 407 | /* End XCBuildConfiguration section */ 408 | 409 | /* Begin XCConfigurationList section */ 410 | B58A5F9829064F4000926816 /* Build configuration list for PBXProject "ModMyIPA" */ = { 411 | isa = XCConfigurationList; 412 | buildConfigurations = ( 413 | B58A5FA929064F4300926816 /* Debug */, 414 | B58A5FAA29064F4300926816 /* Release */, 415 | ); 416 | defaultConfigurationIsVisible = 0; 417 | defaultConfigurationName = Release; 418 | }; 419 | B58A5FAB29064F4300926816 /* Build configuration list for PBXNativeTarget "ModMyIPA" */ = { 420 | isa = XCConfigurationList; 421 | buildConfigurations = ( 422 | B58A5FAC29064F4300926816 /* Debug */, 423 | B58A5FAD29064F4300926816 /* Release */, 424 | ); 425 | defaultConfigurationIsVisible = 0; 426 | defaultConfigurationName = Release; 427 | }; 428 | /* End XCConfigurationList section */ 429 | 430 | /* Begin XCRemoteSwiftPackageReference section */ 431 | B58A5FC52906B89D00926816 /* XCRemoteSwiftPackageReference "ZipArchive" */ = { 432 | isa = XCRemoteSwiftPackageReference; 433 | repositoryURL = "https://github.com/ZipArchive/ZipArchive.git"; 434 | requirement = { 435 | branch = master; 436 | kind = branch; 437 | }; 438 | }; 439 | /* End XCRemoteSwiftPackageReference section */ 440 | 441 | /* Begin XCSwiftPackageProductDependency section */ 442 | B58A5FC62906B89D00926816 /* ZipArchive */ = { 443 | isa = XCSwiftPackageProductDependency; 444 | package = B58A5FC52906B89D00926816 /* XCRemoteSwiftPackageReference "ZipArchive" */; 445 | productName = ZipArchive; 446 | }; 447 | /* End XCSwiftPackageProductDependency section */ 448 | }; 449 | rootObject = B58A5F9529064F4000926816 /* Project object */; 450 | } 451 | -------------------------------------------------------------------------------- /ModMyIPA.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ModMyIPA.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ModMyIPA.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "pins" : [ 3 | { 4 | "identity" : "ziparchive", 5 | "kind" : "remoteSourceControl", 6 | "location" : "https://github.com/ZipArchive/ZipArchive.git", 7 | "state" : { 8 | "branch" : "master", 9 | "revision" : "28312ba171da6647f410c6e5128a1fca9d2110b5" 10 | } 11 | } 12 | ], 13 | "version" : 2 14 | } 15 | -------------------------------------------------------------------------------- /ModMyIPA.xcodeproj/xcuserdata/xiaobowen.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | ModMyIPA.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /ModMyIPA.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | application-identifier 6 | com.powen.ModMyIPA 7 | platform-application 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ModMyIPA/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ModMyIPA/Assets.xcassets/AppIcon.appiconset/1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/powenn/ModMyIPA/3449506b9ab50cc07dab09b92c749e702f2d539a/ModMyIPA/Assets.xcassets/AppIcon.appiconset/1024.png -------------------------------------------------------------------------------- /ModMyIPA/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "1024.png", 5 | "idiom" : "universal", 6 | "platform" : "ios", 7 | "size" : "1024x1024" 8 | } 9 | ], 10 | "info" : { 11 | "author" : "xcode", 12 | "version" : 1 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ModMyIPA/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ModMyIPA/Assets.xcassets/appicon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "icon.png", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ModMyIPA/Assets.xcassets/appicon.imageset/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/powenn/ModMyIPA/3449506b9ab50cc07dab09b92c749e702f2d539a/ModMyIPA/Assets.xcassets/appicon.imageset/icon.png -------------------------------------------------------------------------------- /ModMyIPA/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // ModMyIPA 4 | // 5 | // Created by 蕭博文 on 2022/10/24. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ContentView: View { 11 | var body: some View { 12 | NavigationView{ 13 | MainView() 14 | .navigationBarTitleDisplayMode(.inline) 15 | .navigationBarTitle("ModMyIPA") 16 | .toolbar(content: { 17 | NavigationLink(destination: { 18 | InfoView() 19 | }, label: { 20 | Image(systemName: "info.circle") 21 | }) 22 | }) 23 | }.onAppear(perform: { 24 | MyFileManager.shared.setUpPath() 25 | MyFileManager.shared.resetTmp() 26 | }) 27 | } 28 | } 29 | 30 | struct ContentView_Previews: PreviewProvider { 31 | static var previews: some View { 32 | ContentView() 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /ModMyIPA/Launch Screen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /ModMyIPA/Managers/IPAFile.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IPAFile.swift 3 | // ModMyIPA 4 | // 5 | // Created by 蕭博文 on 2022/10/24. 6 | // 7 | 8 | import Foundation 9 | import ZipArchive 10 | 11 | class IPAFile:ObservableObject { 12 | private init() {} 13 | static let shared = IPAFile() 14 | 15 | var fileURL:URL = URL(fileURLWithPath: "") 16 | @Published var fileName:String = "" 17 | var contentDirURL:URL = URL(fileURLWithPath: "") 18 | var fileImported:Bool = false 19 | var payloadURL:URL = URL(fileURLWithPath: "") 20 | var payloadExist:Bool = false 21 | var appContentExist:Bool = false 22 | var infoPlistExist:Bool = false 23 | var app_executableExist:Bool = false 24 | @Published var appNameInPayload:String = "" 25 | var infoPlistPath:URL = URL(fileURLWithPath: "") 26 | 27 | var config: [String: Any]? 28 | @Published var app_executable:String = "" 29 | @Published var app_name:String = "" 30 | @Published var app_bundle:String = "" 31 | @Published var app_min_ios:String = "" 32 | 33 | @Published var processing:Bool = false 34 | 35 | func getPayloadURL() { 36 | self.payloadURL = contentDirURL.appendingPathComponent("Payload") 37 | if FileManager.default.fileExists(atPath: payloadURL.path) { 38 | payloadExist=true 39 | } else { 40 | payloadExist = false 41 | } 42 | } 43 | 44 | func getAppNameInPayload() { 45 | let Content = try? FileManager.default.contentsOfDirectory(atPath: self.payloadURL.path) 46 | for content in Content! { 47 | if content.hasSuffix(".app") { 48 | appNameInPayload = content 49 | appContentExist = true 50 | break 51 | } 52 | appContentExist = false 53 | } 54 | } 55 | 56 | func getInfoPlistPath() { 57 | if self.appContentExist { 58 | infoPlistPath = self.payloadURL.appendingPathComponent("\(self.appNameInPayload)/Info.plist") 59 | } 60 | if FileManager.default.fileExists(atPath: infoPlistPath.path){ 61 | infoPlistExist = true 62 | } else { 63 | infoPlistExist = false 64 | } 65 | } 66 | 67 | func getInfoPlistValue() { 68 | do { 69 | // get Info in plist file 70 | let infoPlistData = try Data(contentsOf: infoPlistPath) 71 | if let dict = try PropertyListSerialization.propertyList(from: infoPlistData, options: [], format: nil) as? [String: Any] { 72 | config = dict 73 | // check is this Info.plist valid 74 | if ((config?["CFBundleExecutable"]) != nil) { 75 | app_executable = (config?["CFBundleExecutable"] as! String) 76 | app_name = config?["CFBundleName"] as! String 77 | app_bundle = config?["CFBundleIdentifier"] as! String 78 | app_min_ios = config?["MinimumOSVersion"] as! String? ?? "14.0" 79 | app_executableExist = true 80 | } else { 81 | app_executableExist = false 82 | } 83 | } 84 | } catch { 85 | print(error.localizedDescription) 86 | } 87 | } 88 | 89 | func updateInfoPlistValue() { 90 | let plistDict = NSMutableDictionary(contentsOfFile: infoPlistPath.path) 91 | plistDict!.setObject(app_name, forKey: "CFBundleDisplayName" as NSCopying) 92 | plistDict!.write(toFile: infoPlistPath.path, atomically: false) 93 | plistDict!.setObject(app_bundle, forKey: "CFBundleIdentifier" as NSCopying) 94 | plistDict!.write(toFile: infoPlistPath.path, atomically: false) 95 | } 96 | 97 | func moveModdedPackage() { 98 | do { 99 | if appNameInPayload != "\(app_executable).app" { 100 | try FileManager.default.moveItem(at: payloadURL.appendingPathComponent(appNameInPayload), to: payloadURL.appendingPathComponent("\(app_executable).app")) 101 | } 102 | try FileManager.default.moveItem(at: contentDirURL, to: tmpDirectory.appendingPathComponent(app_executable)) 103 | } catch { 104 | print(error.localizedDescription) 105 | } 106 | } 107 | 108 | func zipToIPA() { 109 | SSZipArchive.createZipFile(atPath: outputDirectory.appendingPathComponent("\(app_executable).ipa").path,withContentsOfDirectory: tmpDirectory.appendingPathComponent(app_executable).path) 110 | } 111 | 112 | func resultIPAExist() -> Bool { 113 | return FileManager.default.fileExists(atPath: outputDirectory.appendingPathComponent("\(app_executable).ipa").path) 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /ModMyIPA/Managers/MyFileManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FileManager.swift 3 | // ModMyIPA 4 | // 5 | // Created by 蕭博文 on 2022/10/24. 6 | // 7 | 8 | import Foundation 9 | import ZipArchive 10 | 11 | class MyFileManager { 12 | private init() {} 13 | static let shared = MyFileManager() 14 | 15 | func setUpPath() { 16 | if !FileManager.default.fileExists(atPath: tmpDirectory.path) { 17 | try? FileManager.default.createDirectory( 18 | at: tmpDirectory, 19 | withIntermediateDirectories: true, 20 | attributes: nil 21 | ) 22 | } 23 | if !FileManager.default.fileExists(atPath: outputDirectory.path) { 24 | try? FileManager.default.createDirectory( 25 | at: outputDirectory, 26 | withIntermediateDirectories: true, 27 | attributes: nil 28 | ) 29 | } 30 | } 31 | 32 | func resetTmp() { 33 | try? FileManager.default.removeItem(at: tmpDirectory) 34 | try? FileManager.default.createDirectory( 35 | at: tmpDirectory, 36 | withIntermediateDirectories: true, 37 | attributes: nil 38 | ) 39 | } 40 | 41 | func resetOutput() { 42 | try? FileManager.default.removeItem(at: outputDirectory) 43 | try? FileManager.default.createDirectory( 44 | at: outputDirectory, 45 | withIntermediateDirectories: true, 46 | attributes: nil 47 | ) 48 | } 49 | 50 | func extractIpa() { 51 | var destination:URL 52 | guard IPAFile.shared.fileURL.startAccessingSecurityScopedResource() else { 53 | return 54 | } 55 | do { 56 | destination = tmpDirectory.appendingPathComponent(IPAFile.shared.fileName.replacingOccurrences(of: ".ipa", with: ".zip")) 57 | IPAFile.shared.contentDirURL = tmpDirectory.appendingPathComponent(IPAFile.shared.fileName.replacingOccurrences(of: ".ipa", with: "")) 58 | if FileManager.default.fileExists(atPath: destination.path) { 59 | try FileManager.default.removeItem(atPath: destination.path) 60 | } 61 | try FileManager.default.copyItem(at: IPAFile.shared.fileURL, to: destination) 62 | print("Copied file from \(IPAFile.shared.fileURL.path) to \(destination.path)") 63 | try SSZipArchive.unzipFile(atPath: destination.path, toDestination: IPAFile.shared.contentDirURL.path, overwrite: true, password: nil) 64 | print("Unzipped file from \(destination.path)to\(IPAFile.shared.contentDirURL.path)") 65 | IPAFile.shared.fileImported = true 66 | 67 | } catch { 68 | print(error.localizedDescription) 69 | } 70 | IPAFile.shared.fileURL.stopAccessingSecurityScopedResource() 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /ModMyIPA/Misc/Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extensions.swift 3 | // ModMyIPA 4 | // 5 | // Created by 蕭博文 on 2022/10/24. 6 | // 7 | 8 | import Foundation 9 | import SwiftUI 10 | 11 | // Press anywhere to hide keyboard 12 | extension View { 13 | func hideKeyboard() { 14 | UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ModMyIPA/Misc/FilePaths.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FilePaths.swift 3 | // ModMyIPA 4 | // 5 | // Created by 蕭博文 on 2022/10/24. 6 | // 7 | 8 | import Foundation 9 | 10 | let docPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] 11 | let tmpDirectory = docPath.appendingPathComponent("tmp") 12 | let outputDirectory = docPath.appendingPathComponent("output") 13 | -------------------------------------------------------------------------------- /ModMyIPA/Misc/MyUserDefaults.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserDefaults.swift 3 | // ModMyIPA 4 | // 5 | // Created by 蕭博文 on 2022/10/24. 6 | // 7 | 8 | import Foundation 9 | import SwiftUI 10 | 11 | class MyUserDefaults:ObservableObject { 12 | private init() {} 13 | static let shared = MyUserDefaults() 14 | @AppStorage("modmyipa.preference.debugging") var debugging = true 15 | } 16 | -------------------------------------------------------------------------------- /ModMyIPA/Misc/Version.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Version.swift 3 | // ModMyIPA 4 | // 5 | // Created by 蕭博文 on 2022/10/24. 6 | // 7 | 8 | import Foundation 9 | 10 | let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String 11 | let buildVersion = Bundle.main.infoDictionary?["CFBundleVersion"] as? String 12 | -------------------------------------------------------------------------------- /ModMyIPA/ModMyIPAApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ModMyIPAApp.swift 3 | // ModMyIPA 4 | // 5 | // Created by 蕭博文 on 2022/10/24. 6 | // 7 | 8 | import SwiftUI 9 | 10 | @main 11 | struct ModMyIPAApp: App { 12 | var body: some Scene { 13 | WindowGroup { 14 | ContentView() 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ModMyIPA/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ModMyIPA/ShareSheet.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ShareSheet.swift 3 | // ModMyIPA 4 | // 5 | // Created by 蕭博文 on 2022/10/25. 6 | // 7 | // https://developer.apple.com/forums/thread/123951 8 | 9 | import Foundation 10 | import UIKit 11 | import SwiftUI 12 | 13 | struct ShareSheet: UIViewControllerRepresentable { 14 | typealias Callback = (_ activityType: UIActivity.ActivityType?, _ completed: Bool, _ returnedItems: [Any]?, _ error: Error?) -> Void 15 | 16 | let activityItems: [Any] 17 | let applicationActivities: [UIActivity]? = nil 18 | let excludedActivityTypes: [UIActivity.ActivityType]? = nil 19 | let callback: Callback? = nil 20 | 21 | func makeUIViewController(context: Context) -> UIActivityViewController { 22 | let controller = UIActivityViewController( 23 | activityItems: activityItems, 24 | applicationActivities: applicationActivities) 25 | controller.excludedActivityTypes = excludedActivityTypes 26 | controller.completionWithItemsHandler = callback 27 | return controller 28 | } 29 | 30 | func updateUIViewController(_ uiViewController: UIActivityViewController, context: Context) { 31 | // nothing to do here 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ModMyIPA/Views/EditAppInfoView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ModifyView.swift 3 | // ModMyIPA 4 | // 5 | // Created by 蕭博文 on 2022/10/24. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct EditAppInfoView: View { 11 | @StateObject var ipafile:IPAFile = .shared 12 | @Environment(\.presentationMode) var presentationMode 13 | 14 | var body: some View { 15 | VStack{ 16 | VStack(alignment: .leading) { 17 | Text("Customize App Name") 18 | TextField("App Name", text: $ipafile.app_name) 19 | .textFieldStyle(.roundedBorder) 20 | Text("Customize App Package Name\n(The name of .app directory)") 21 | TextField("App Package Name", text: $ipafile.app_executable) 22 | .textFieldStyle(.roundedBorder) 23 | Text("Customize App Bundle") 24 | TextField("App Bundle", text: $ipafile.app_bundle) 25 | .textFieldStyle(.roundedBorder) 26 | }.padding() 27 | Button(action: { 28 | self.presentationMode.wrappedValue.dismiss() 29 | }, label: { 30 | Text("Done") 31 | }).padding() 32 | } 33 | .padding() 34 | .onTapGesture { 35 | hideKeyboard() 36 | } 37 | } 38 | } 39 | 40 | struct EditAppInfoView_Previews: PreviewProvider { 41 | static var previews: some View { 42 | EditAppInfoView() 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ModMyIPA/Views/InfoView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InfoView.swift 3 | // ModMyIPA 4 | // 5 | // Created by 蕭博文 on 2022/10/24. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct InfoView: View { 11 | @StateObject var myuserdefaults:MyUserDefaults = .shared 12 | @State var showPackagesList:Bool = false 13 | 14 | var body: some View { 15 | Form { 16 | Section(header: Text("version")){ 17 | Text("\(appVersion!).\(buildVersion!)") 18 | } 19 | Section(header: Text("View files"), content: { 20 | Button("View the output package list", action: { 21 | print("View package list button pressed") 22 | showPackagesList.toggle() 23 | }).sheet(isPresented: $showPackagesList, content: { 24 | NavigationView { 25 | PackageListView() 26 | .navigationBarTitle("PackageList", displayMode: .inline) 27 | } 28 | }) 29 | }) 30 | Section(header: Text("Clean up"), content: { 31 | Button("Clean up tmp directory", action: { 32 | MyFileManager.shared.resetTmp() 33 | }) 34 | Button("Clean up output directory", action: { 35 | MyFileManager.shared.resetOutput() 36 | }) 37 | }) 38 | Section(header: Text("source code")){ 39 | Link(destination: URL(string: "https://github.com/powenn/ModMyIPA")!, label: { 40 | HStack{ 41 | Text("View on Github") 42 | } 43 | }) 44 | } 45 | Section(footer: Text("Made by @powenn"), content: {}) 46 | Section(footer: Text("Output files path : \(outputDirectory.path)"), content: {}) 47 | Section(footer: Text("A nice sentence inspired me\nfrom a nice guy named yammy in Discord\n\"If it's what you want to do,\ndon't let anybody stop you\""), content: {}) 48 | } 49 | } 50 | } 51 | 52 | struct InfoView_Previews: PreviewProvider { 53 | static var previews: some View { 54 | InfoView() 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /ModMyIPA/Views/MainView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MainView.swift 3 | // ModMyIPA 4 | // 5 | // Created by 蕭博文 on 2022/10/24. 6 | // 7 | 8 | import SwiftUI 9 | import UniformTypeIdentifiers 10 | 11 | struct MainView: View { 12 | @StateObject var myuserdefaults:MyUserDefaults = .shared 13 | @StateObject var ipafile:IPAFile = .shared 14 | 15 | @State var isImporting: Bool = false 16 | @State var showInvalidAlert:Bool = false 17 | @State var alertTitle:String = "" 18 | @State var alertMeaasge:String = "" 19 | 20 | @State var showEditInfo:Bool = false 21 | @State var showSuccessedAlert:Bool = false 22 | 23 | func invalidFileAlert(title:String, message:String) { 24 | ipafile.fileName = "" 25 | alertTitle = title 26 | alertMeaasge = message 27 | showInvalidAlert.toggle() 28 | ipafile.fileImported = false 29 | } 30 | 31 | var body: some View { 32 | VStack{ 33 | Text(ipafile.fileName != "" ? ipafile.fileName: "No .ipa file selected").padding() 34 | Button("Select IPA File", action: { 35 | print("Select file button pressed") 36 | isImporting.toggle() 37 | }).disabled(ipafile.processing || isImporting) 38 | .padding() 39 | .alert(isPresented: $showInvalidAlert) { 40 | Alert(title: Text(alertTitle), message: Text(alertMeaasge), dismissButton: .default(Text("OK"))) 41 | } 42 | .fileImporter( 43 | isPresented: $isImporting, 44 | allowedContentTypes: [UTType(filenameExtension: "ipa")!], 45 | allowsMultipleSelection: false 46 | ) { result in 47 | do { 48 | ipafile.fileURL = try result.get().first! 49 | ipafile.fileName = ipafile.fileURL.lastPathComponent 50 | print(ipafile.fileURL.path,ipafile.fileName) 51 | MyFileManager.shared.extractIpa() 52 | ipafile.getPayloadURL() 53 | if !ipafile.payloadExist { 54 | invalidFileAlert(title: "Invalid IPA File", message: "There is no payload content found") 55 | return 56 | } 57 | ipafile.getAppNameInPayload() 58 | if !ipafile.appContentExist { 59 | invalidFileAlert(title: "Invalid IPA File", message: "There is no app content inside payload") 60 | return 61 | } 62 | ipafile.getInfoPlistPath() 63 | if !ipafile.infoPlistExist { 64 | invalidFileAlert(title: "Invalid IPA File", message: "There is no info.plist inside app content") 65 | return 66 | } 67 | ipafile.getInfoPlistValue() 68 | if !ipafile.app_executableExist { 69 | invalidFileAlert(title: "Invalid IPA File", message: "There is no executable binary inside app content") 70 | return 71 | } 72 | print(ipafile.appNameInPayload) 73 | }catch { 74 | print(error.localizedDescription) 75 | } 76 | } 77 | Button("Edit IPA Info", action: { 78 | print("Edit IPA_INFO button pressed") 79 | showEditInfo.toggle() 80 | }).sheet(isPresented: $showEditInfo, content: { 81 | EditAppInfoView() 82 | }) 83 | .disabled(!ipafile.fileImported||ipafile.processing) 84 | .padding() 85 | Button("Mod it", action: { 86 | print("Mod button pressed") 87 | print("APPNAME:\(ipafile.app_name)\nPACKAGENAME:\(ipafile.app_executable)\nAPPBUNDLE:\(ipafile.app_bundle)") 88 | ipafile.processing = true 89 | DispatchQueue.global(qos: .userInitiated).async { 90 | ipafile.updateInfoPlistValue() 91 | ipafile.moveModdedPackage() 92 | ipafile.zipToIPA() 93 | DispatchQueue.main.asyncAfter(deadline: .now()) { 94 | ipafile.fileName = "" 95 | ipafile.fileImported = false 96 | ipafile.processing = false 97 | if ipafile.resultIPAExist() { 98 | showSuccessedAlert.toggle() 99 | } 100 | } 101 | } 102 | }) 103 | .alert(isPresented: $showSuccessedAlert) { 104 | Alert(title: Text("Done"), message: Text("Success modded"), dismissButton: .default(Text("OK"))) 105 | } 106 | .disabled(!ipafile.fileImported||ipafile.processing) 107 | .padding() 108 | if ipafile.processing { 109 | ProgressView(label: { 110 | Text("Processing") 111 | }) 112 | } 113 | 114 | if isImporting { 115 | ProgressView(label: { 116 | Text("Importing IPA File") 117 | }) 118 | } 119 | }.padding() 120 | } 121 | } 122 | 123 | struct MainView_Previews: PreviewProvider { 124 | static var previews: some View { 125 | MainView() 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /ModMyIPA/Views/PackageListView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PackageLIstView.swift 3 | // ModMyIPA 4 | // 5 | // Created by 蕭博文 on 2022/10/25. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct PackageListView: View { 11 | @State var packageList = try! FileManager.default.contentsOfDirectory(atPath: outputDirectory.path) 12 | @State var showShareSheet:Bool = false 13 | @State var selectedPackage:String = "" 14 | 15 | var body: some View { 16 | List { 17 | ForEach(packageList, id: \.self) { package in 18 | HStack{ 19 | Text(package) 20 | .font(.title3) 21 | Spacer() 22 | Button("", action: { 23 | print("\(package) share tapped!") 24 | showShareSheet.toggle() 25 | }).sheet(isPresented: $showShareSheet, content: { 26 | ShareSheet(activityItems: [outputDirectory.appendingPathComponent(package)]) 27 | }) 28 | } 29 | .contentShape(Rectangle()) 30 | .padding() 31 | } 32 | .onDelete(perform: deleteItem) 33 | } 34 | .listStyle(.automatic) 35 | } 36 | 37 | func deleteItem(at indexSet: IndexSet) { 38 | let tmpList = packageList 39 | packageList.remove(atOffsets: indexSet) 40 | let deleted:String = Set(tmpList).symmetricDifference(Set(packageList)).first! 41 | try! FileManager.default.removeItem(atPath: outputDirectory.appendingPathComponent(deleted).path) 42 | print("Deleted:\(deleted)") 43 | print("Left:\(packageList)") 44 | } 45 | } 46 | 47 | struct PackageListView_Previews: PreviewProvider { 48 | static var previews: some View { 49 | PackageListView() 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ModMyIPA 2 | 3 |

4 | 5 | Releases 6 | 7 | 8 | Code Size in Bytes 9 | 10 |

11 | 12 | ## An app that modifies IPA files allows you to install the same app multiple times 13 | 14 | ![screenshot][1] 15 | ![screenshot][2] 16 | ![screenshot][3] 17 | 18 | 19 | 20 | [1]:https://github.com/powenn/ModMyIPA/blob/main/Screenshots/01.png 21 | [2]:https://github.com/powenn/ModMyIPA/blob/main/Screenshots/02.png 22 | [3]:https://github.com/powenn/ModMyIPA/blob/main/Screenshots/03.png 23 | -------------------------------------------------------------------------------- /Screenshots/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/powenn/ModMyIPA/3449506b9ab50cc07dab09b92c749e702f2d539a/Screenshots/01.png -------------------------------------------------------------------------------- /Screenshots/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/powenn/ModMyIPA/3449506b9ab50cc07dab09b92c749e702f2d539a/Screenshots/02.png -------------------------------------------------------------------------------- /Screenshots/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/powenn/ModMyIPA/3449506b9ab50cc07dab09b92c749e702f2d539a/Screenshots/03.png -------------------------------------------------------------------------------- /compile.command: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | # cd script dir 6 | cd "$(dirname "$0")" || exit 7 | 8 | GIT_ROOT=$(pwd) 9 | 10 | rm -rf build Payload ModMyIPA.ipa # ModMyIPA-TS.ipa 11 | 12 | xcodebuild -project "$GIT_ROOT/ModMyIPA.xcodeproj" \ 13 | -scheme ModMyIPA -configuration Release \ 14 | -derivedDataPath "$GIT_ROOT/build" \ 15 | -destination 'generic/platform=iOS' \ 16 | -sdk iphoneos \ 17 | clean build \ 18 | CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO ONLY_ACTIVE_ARCH=NO \ 19 | PRODUCT_BUNDLE_IDENTIFIER="com.powen.ModMyIPA" \ 20 | 21 | #ldid -S -M build/Build/Products/Release-iphoneos/ModMyIPA.app 22 | ln -sf build/Build/Products/Release-iphoneos Payload 23 | #zip -r9 ModMyIPA.ipa Payload/ModMyIPA.app 24 | 25 | 26 | # Build TrollStore Support Edition 27 | 28 | #cp -R build/Build/Products/Release-iphoneos/ModMyIPA.app build/Build/Products/Release-iphoneos/ModMyIPA-TS.app 29 | 30 | ldid -SModMyIPA.xml -M build/Build/Products/Release-iphoneos/ModMyIPA.app 31 | zip -r9 ModMyIPA.ipa Payload/ModMyIPA.app 32 | --------------------------------------------------------------------------------