├── ProjectMix.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── project.pbxproj ├── Demo └── ProjectFixDemo │ ├── ProjectFixDemo.xcodeproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── project.pbxproj │ └── ProjectFixDemo │ ├── JYTestFile.m │ ├── ViewController.h │ ├── JYTestFile.h │ ├── AppDelegate.h │ ├── main.m │ ├── ViewController.m │ ├── Info.plist │ ├── Base.lproj │ ├── Main.storyboard │ └── LaunchScreen.storyboard │ ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json │ └── AppDelegate.m ├── LICENSE ├── .gitignore ├── README.md └── ProjectMix └── main.m /ProjectMix.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Demo/ProjectFixDemo/ProjectFixDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Demo/ProjectFixDemo/ProjectFixDemo/JYTestFile.m: -------------------------------------------------------------------------------- 1 | // 2 | // JYTestFile.m 3 | // ProjectFixDemo 4 | // 5 | // Created by Journey on 2018/3/29. 6 | // Copyright © 2018年 Journey. All rights reserved. 7 | // 8 | 9 | #import "JYTestFile.h" 10 | 11 | @implementation JYTestFile 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Demo/ProjectFixDemo/ProjectFixDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // ProjectFixDemo 4 | // 5 | // Created by Journey on 2018/3/29. 6 | // Copyright © 2018年 Journey. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /ProjectMix.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Demo/ProjectFixDemo/ProjectFixDemo/JYTestFile.h: -------------------------------------------------------------------------------- 1 | // 2 | // JYTestFile.h 3 | // ProjectFixDemo 4 | // 5 | // Created by Journey on 2018/3/29. 6 | // Copyright © 2018年 Journey. All rights reserved. 7 | // 8 | 9 | 10 | 11 | ///JY就是类前缀,也是文件的前缀 12 | 13 | #import 14 | 15 | @interface JYTestFile : NSObject 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Demo/ProjectFixDemo/ProjectFixDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // ProjectFixDemo 4 | // 5 | // Created by Journey on 2018/3/29. 6 | // Copyright © 2018年 Journey. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /Demo/ProjectFixDemo/ProjectFixDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // ProjectFixDemo 4 | // 5 | // Created by Journey on 2018/3/29. 6 | // Copyright © 2018年 Journey. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Demo/ProjectFixDemo/ProjectFixDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // ProjectFixDemo 4 | // 5 | // Created by Journey on 2018/3/29. 6 | // Copyright © 2018年 Journey. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | @interface ViewController () 12 | 13 | @end 14 | 15 | @implementation ViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | // Do any additional setup after loading the view, typically from a nib. 20 | } 21 | 22 | ///ie_就是方法前缀 23 | - (void)ie_testFixAPI{ 24 | 25 | } 26 | 27 | - (void)didReceiveMemoryWarning { 28 | [super didReceiveMemoryWarning]; 29 | // Dispose of any resources that can be recreated. 30 | } 31 | 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 YuYang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | # CocoaPods 32 | # 33 | # We recommend against adding the Pods directory to your .gitignore. However 34 | # you should judge for yourself, the pros and cons are mentioned at: 35 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 36 | # 37 | # Pods/ 38 | 39 | # Carthage 40 | # 41 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 42 | # Carthage/Checkouts 43 | 44 | Carthage/Build 45 | 46 | # fastlane 47 | # 48 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 49 | # screenshots whenever they are needed. 50 | # For more information about the recommended setup visit: 51 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 52 | 53 | fastlane/report.xml 54 | fastlane/Preview.html 55 | fastlane/screenshots 56 | fastlane/test_output 57 | 58 | # Code Injection 59 | # 60 | # After new code Injection tools there's a generated folder /iOSInjectionProject 61 | # https://github.com/johnno1962/injectionforxcode 62 | 63 | iOSInjectionProject/ 64 | -------------------------------------------------------------------------------- /Demo/ProjectFixDemo/ProjectFixDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Demo/ProjectFixDemo/ProjectFixDemo/Base.lproj/Main.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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iOSMixProject 2 | 混淆加固工程 3 | 4 | # 最近的思路 5 | 不少人私信问最新的思路,在18年10月之前,只要过了机审基本上就等于上架,所以混淆脚本市场很大,目前我主要采用是LLVM混淆,本脚本目前仍能过机审。 6 | 7 | # 原工程地址 8 | 首先感谢将此脚本初始脚本开源的大佬,但不太适合我们工程,于是我们在原有的轮子上加了几颗螺丝钉,仅供参考思路,奉上原仓库地址。 9 | 注意看这里!原始代码仓库地址:[https://github.com/klaus01/KLGenerateSpamCode](https://github.com/klaus01/KLGenerateSpamCode) 10 | 11 | # 新增功能 12 | 除了已有的图片资源递增修改、修改工程名、类前缀修改(修改了遍历方案)外,还加了一些骚东西 13 | 14 | 0、直接在工程中添加垃圾代码,垃圾代码的规则可自己修改脚本代码自定义 15 | 16 | 1、混淆随机添加垃圾代码、参数 17 | 18 | 2、修改方法名前缀 19 | 20 | 3、修改方法名,使用plist文件创建原始方法名仓库,共有6^6个方法名可以配置,随机方法名配参数 21 | 22 | 4、删除垃圾代码。以脚本前缀为索引 23 | 24 | 5、混淆概率 25 | 26 | # 注意点 27 | 28 | 1、这个工程里的方法名前缀只适应我们自己的工程,因为我们的工程方法名是前缀_xxx这类格式的,所以不要再问为什么没有资源改变了兄dei。没有执行的代码,麻烦看看main函数里是不是注释掉了,先看代码,再发问。 29 | 30 | 2、api名字是随机从6^6个方法名生成的,可以在plist文件中修改 31 | 32 | # 使用方法 33 | 34 | 和原来的轮子一样,先配置启动参数再运行,如图 35 | 36 | ![image_0](http://puioc6h3a.bkt.clouddn.com/E02D60A5-1DA2-46A9-B759-AB29AEE7C096.png) 37 | 38 | 参数解释: 39 | 40 | 1.工程代码的绝对路径 41 | 42 | 2.-modifyProjectName [原工程名]>[新工程名] 43 | 44 | 3.-modifyClassNamePrefix [xcodeproj文件的绝对路径,不是pod安装后的那个打开文件] [旧类前缀]>[新类前缀] 45 | 46 | 4.-spamCodeOut 47 | 48 | 5.-ignoreDirNames [需要忽略的文件夹],[需要忽略的文件夹] 注意,Pods文件夹不在混淆范围内,不需要写 49 | 50 | 6.-handleXcassets (混淆图片文件) 51 | 52 | 7.-deleteComments (删除多余的空格和注释) 53 | 54 | 8.-chageAPIPrefix [旧方法名前缀]>[新方法名前缀] 注意,前缀要有“_”才能被识别,如果之前工程中没有xx_下划线开头来命名方法的,此项不要勾选 55 | 56 | 9.-modifyAPIName 改变api名字,注意是随机的,这个更改最好不要提交,只用来上架,一次性操作,否则可能增加后续维护的负担(看不懂方法名了) 57 | 58 | ***此工程可以选择混淆概率,修改工程中kPercent数值。*** 59 | 60 | # 详情 61 | 有关此工程的设计详情请看这篇文章[传送门](http://www.imyuyang.com/2018/02/15/iOS%E9%A9%AC%E7%94%B2%E5%8C%85%E6%B7%B7%E6%B7%86%E6%96%B9%E6%A1%88/) 62 | 63 | # 痛点 64 | 时间复杂度可以说是非常的高,跑起来运行时CPU占用率几乎达到百分百。好在这基本是一次性工具。。。 65 | 66 | -------------------------------------------------------------------------------- /Demo/ProjectFixDemo/ProjectFixDemo/Base.lproj/LaunchScreen.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 | -------------------------------------------------------------------------------- /Demo/ProjectFixDemo/ProjectFixDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | } 88 | ], 89 | "info" : { 90 | "version" : 1, 91 | "author" : "xcode" 92 | } 93 | } -------------------------------------------------------------------------------- /Demo/ProjectFixDemo/ProjectFixDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // ProjectFixDemo 4 | // 5 | // Created by Journey on 2018/3/29. 6 | // Copyright © 2018年 Journey. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /ProjectMix.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | B517AAAB202C500000E7D046 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B517AAAA202C500000E7D046 /* main.m */; }; 11 | /* End PBXBuildFile section */ 12 | 13 | /* Begin PBXCopyFilesBuildPhase section */ 14 | B517AAA5202C500000E7D046 /* CopyFiles */ = { 15 | isa = PBXCopyFilesBuildPhase; 16 | buildActionMask = 2147483647; 17 | dstPath = /usr/share/man/man1/; 18 | dstSubfolderSpec = 0; 19 | files = ( 20 | ); 21 | runOnlyForDeploymentPostprocessing = 1; 22 | }; 23 | /* End PBXCopyFilesBuildPhase section */ 24 | 25 | /* Begin PBXFileReference section */ 26 | B517AAA7202C500000E7D046 /* ProjectMix */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ProjectMix; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | B517AAAA202C500000E7D046 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 28 | /* End PBXFileReference section */ 29 | 30 | /* Begin PBXFrameworksBuildPhase section */ 31 | B517AAA4202C500000E7D046 /* Frameworks */ = { 32 | isa = PBXFrameworksBuildPhase; 33 | buildActionMask = 2147483647; 34 | files = ( 35 | ); 36 | runOnlyForDeploymentPostprocessing = 0; 37 | }; 38 | /* End PBXFrameworksBuildPhase section */ 39 | 40 | /* Begin PBXGroup section */ 41 | B517AA9E202C500000E7D046 = { 42 | isa = PBXGroup; 43 | children = ( 44 | B517AAA9202C500000E7D046 /* ProjectMix */, 45 | B517AAA8202C500000E7D046 /* Products */, 46 | ); 47 | sourceTree = ""; 48 | }; 49 | B517AAA8202C500000E7D046 /* Products */ = { 50 | isa = PBXGroup; 51 | children = ( 52 | B517AAA7202C500000E7D046 /* ProjectMix */, 53 | ); 54 | name = Products; 55 | sourceTree = ""; 56 | }; 57 | B517AAA9202C500000E7D046 /* ProjectMix */ = { 58 | isa = PBXGroup; 59 | children = ( 60 | B517AAAA202C500000E7D046 /* main.m */, 61 | ); 62 | path = ProjectMix; 63 | sourceTree = ""; 64 | }; 65 | /* End PBXGroup section */ 66 | 67 | /* Begin PBXNativeTarget section */ 68 | B517AAA6202C500000E7D046 /* ProjectMix */ = { 69 | isa = PBXNativeTarget; 70 | buildConfigurationList = B517AAAE202C500000E7D046 /* Build configuration list for PBXNativeTarget "ProjectMix" */; 71 | buildPhases = ( 72 | B517AAA3202C500000E7D046 /* Sources */, 73 | B517AAA4202C500000E7D046 /* Frameworks */, 74 | B517AAA5202C500000E7D046 /* CopyFiles */, 75 | ); 76 | buildRules = ( 77 | ); 78 | dependencies = ( 79 | ); 80 | name = ProjectMix; 81 | productName = ProjectMix; 82 | productReference = B517AAA7202C500000E7D046 /* ProjectMix */; 83 | productType = "com.apple.product-type.tool"; 84 | }; 85 | /* End PBXNativeTarget section */ 86 | 87 | /* Begin PBXProject section */ 88 | B517AA9F202C500000E7D046 /* Project object */ = { 89 | isa = PBXProject; 90 | attributes = { 91 | LastUpgradeCheck = 0920; 92 | ORGANIZATIONNAME = Journey; 93 | TargetAttributes = { 94 | B517AAA6202C500000E7D046 = { 95 | CreatedOnToolsVersion = 9.2; 96 | ProvisioningStyle = Automatic; 97 | }; 98 | }; 99 | }; 100 | buildConfigurationList = B517AAA2202C500000E7D046 /* Build configuration list for PBXProject "ProjectMix" */; 101 | compatibilityVersion = "Xcode 8.0"; 102 | developmentRegion = en; 103 | hasScannedForEncodings = 0; 104 | knownRegions = ( 105 | en, 106 | ); 107 | mainGroup = B517AA9E202C500000E7D046; 108 | productRefGroup = B517AAA8202C500000E7D046 /* Products */; 109 | projectDirPath = ""; 110 | projectRoot = ""; 111 | targets = ( 112 | B517AAA6202C500000E7D046 /* ProjectMix */, 113 | ); 114 | }; 115 | /* End PBXProject section */ 116 | 117 | /* Begin PBXSourcesBuildPhase section */ 118 | B517AAA3202C500000E7D046 /* Sources */ = { 119 | isa = PBXSourcesBuildPhase; 120 | buildActionMask = 2147483647; 121 | files = ( 122 | B517AAAB202C500000E7D046 /* main.m in Sources */, 123 | ); 124 | runOnlyForDeploymentPostprocessing = 0; 125 | }; 126 | /* End PBXSourcesBuildPhase section */ 127 | 128 | /* Begin XCBuildConfiguration section */ 129 | B517AAAC202C500000E7D046 /* Debug */ = { 130 | isa = XCBuildConfiguration; 131 | buildSettings = { 132 | ALWAYS_SEARCH_USER_PATHS = NO; 133 | CLANG_ANALYZER_NONNULL = YES; 134 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 135 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 136 | CLANG_CXX_LIBRARY = "libc++"; 137 | CLANG_ENABLE_MODULES = YES; 138 | CLANG_ENABLE_OBJC_ARC = YES; 139 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 140 | CLANG_WARN_BOOL_CONVERSION = YES; 141 | CLANG_WARN_COMMA = YES; 142 | CLANG_WARN_CONSTANT_CONVERSION = YES; 143 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 144 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 145 | CLANG_WARN_EMPTY_BODY = YES; 146 | CLANG_WARN_ENUM_CONVERSION = YES; 147 | CLANG_WARN_INFINITE_RECURSION = YES; 148 | CLANG_WARN_INT_CONVERSION = YES; 149 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 150 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 151 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 152 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 153 | CLANG_WARN_STRICT_PROTOTYPES = YES; 154 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 155 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 156 | CLANG_WARN_UNREACHABLE_CODE = YES; 157 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 158 | CODE_SIGN_IDENTITY = "Mac Developer"; 159 | COPY_PHASE_STRIP = NO; 160 | DEBUG_INFORMATION_FORMAT = dwarf; 161 | ENABLE_STRICT_OBJC_MSGSEND = YES; 162 | ENABLE_TESTABILITY = YES; 163 | GCC_C_LANGUAGE_STANDARD = gnu11; 164 | GCC_DYNAMIC_NO_PIC = NO; 165 | GCC_NO_COMMON_BLOCKS = YES; 166 | GCC_OPTIMIZATION_LEVEL = 0; 167 | GCC_PREPROCESSOR_DEFINITIONS = ( 168 | "DEBUG=1", 169 | "$(inherited)", 170 | ); 171 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 172 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 173 | GCC_WARN_UNDECLARED_SELECTOR = YES; 174 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 175 | GCC_WARN_UNUSED_FUNCTION = YES; 176 | GCC_WARN_UNUSED_VARIABLE = YES; 177 | MACOSX_DEPLOYMENT_TARGET = 10.13; 178 | MTL_ENABLE_DEBUG_INFO = YES; 179 | ONLY_ACTIVE_ARCH = YES; 180 | SDKROOT = macosx; 181 | }; 182 | name = Debug; 183 | }; 184 | B517AAAD202C500000E7D046 /* Release */ = { 185 | isa = XCBuildConfiguration; 186 | buildSettings = { 187 | ALWAYS_SEARCH_USER_PATHS = NO; 188 | CLANG_ANALYZER_NONNULL = YES; 189 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 190 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 191 | CLANG_CXX_LIBRARY = "libc++"; 192 | CLANG_ENABLE_MODULES = YES; 193 | CLANG_ENABLE_OBJC_ARC = YES; 194 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 195 | CLANG_WARN_BOOL_CONVERSION = YES; 196 | CLANG_WARN_COMMA = YES; 197 | CLANG_WARN_CONSTANT_CONVERSION = YES; 198 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 199 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 200 | CLANG_WARN_EMPTY_BODY = YES; 201 | CLANG_WARN_ENUM_CONVERSION = YES; 202 | CLANG_WARN_INFINITE_RECURSION = YES; 203 | CLANG_WARN_INT_CONVERSION = YES; 204 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 205 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 206 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 207 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 208 | CLANG_WARN_STRICT_PROTOTYPES = YES; 209 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 210 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 211 | CLANG_WARN_UNREACHABLE_CODE = YES; 212 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 213 | CODE_SIGN_IDENTITY = "Mac Developer"; 214 | COPY_PHASE_STRIP = NO; 215 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 216 | ENABLE_NS_ASSERTIONS = NO; 217 | ENABLE_STRICT_OBJC_MSGSEND = YES; 218 | GCC_C_LANGUAGE_STANDARD = gnu11; 219 | GCC_NO_COMMON_BLOCKS = YES; 220 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 221 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 222 | GCC_WARN_UNDECLARED_SELECTOR = YES; 223 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 224 | GCC_WARN_UNUSED_FUNCTION = YES; 225 | GCC_WARN_UNUSED_VARIABLE = YES; 226 | MACOSX_DEPLOYMENT_TARGET = 10.13; 227 | MTL_ENABLE_DEBUG_INFO = NO; 228 | SDKROOT = macosx; 229 | }; 230 | name = Release; 231 | }; 232 | B517AAAF202C500000E7D046 /* Debug */ = { 233 | isa = XCBuildConfiguration; 234 | buildSettings = { 235 | CODE_SIGN_STYLE = Automatic; 236 | DEVELOPMENT_TEAM = 9Z47E25487; 237 | PRODUCT_NAME = "$(TARGET_NAME)"; 238 | }; 239 | name = Debug; 240 | }; 241 | B517AAB0202C500000E7D046 /* Release */ = { 242 | isa = XCBuildConfiguration; 243 | buildSettings = { 244 | CODE_SIGN_STYLE = Automatic; 245 | DEVELOPMENT_TEAM = 9Z47E25487; 246 | PRODUCT_NAME = "$(TARGET_NAME)"; 247 | }; 248 | name = Release; 249 | }; 250 | /* End XCBuildConfiguration section */ 251 | 252 | /* Begin XCConfigurationList section */ 253 | B517AAA2202C500000E7D046 /* Build configuration list for PBXProject "ProjectMix" */ = { 254 | isa = XCConfigurationList; 255 | buildConfigurations = ( 256 | B517AAAC202C500000E7D046 /* Debug */, 257 | B517AAAD202C500000E7D046 /* Release */, 258 | ); 259 | defaultConfigurationIsVisible = 0; 260 | defaultConfigurationName = Release; 261 | }; 262 | B517AAAE202C500000E7D046 /* Build configuration list for PBXNativeTarget "ProjectMix" */ = { 263 | isa = XCConfigurationList; 264 | buildConfigurations = ( 265 | B517AAAF202C500000E7D046 /* Debug */, 266 | B517AAB0202C500000E7D046 /* Release */, 267 | ); 268 | defaultConfigurationIsVisible = 0; 269 | defaultConfigurationName = Release; 270 | }; 271 | /* End XCConfigurationList section */ 272 | }; 273 | rootObject = B517AA9F202C500000E7D046 /* Project object */; 274 | } 275 | -------------------------------------------------------------------------------- /Demo/ProjectFixDemo/ProjectFixDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | B5DD504A206CD38A00FBAD66 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B5DD5049206CD38A00FBAD66 /* AppDelegate.m */; }; 11 | B5DD504D206CD38A00FBAD66 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B5DD504C206CD38A00FBAD66 /* ViewController.m */; }; 12 | B5DD5050206CD38A00FBAD66 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B5DD504E206CD38A00FBAD66 /* Main.storyboard */; }; 13 | B5DD5052206CD38A00FBAD66 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B5DD5051206CD38A00FBAD66 /* Assets.xcassets */; }; 14 | B5DD5055206CD38A00FBAD66 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B5DD5053206CD38A00FBAD66 /* LaunchScreen.storyboard */; }; 15 | B5DD5058206CD38A00FBAD66 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B5DD5057206CD38A00FBAD66 /* main.m */; }; 16 | B5DD5060206CD3FB00FBAD66 /* JYTestFile.m in Sources */ = {isa = PBXBuildFile; fileRef = B5DD505F206CD3FB00FBAD66 /* JYTestFile.m */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXFileReference section */ 20 | B5DD5045206CD38A00FBAD66 /* ProjectFixDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ProjectFixDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 21 | B5DD5048206CD38A00FBAD66 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 22 | B5DD5049206CD38A00FBAD66 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 23 | B5DD504B206CD38A00FBAD66 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 24 | B5DD504C206CD38A00FBAD66 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 25 | B5DD504F206CD38A00FBAD66 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 26 | B5DD5051206CD38A00FBAD66 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 27 | B5DD5054206CD38A00FBAD66 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 28 | B5DD5056206CD38A00FBAD66 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 29 | B5DD5057206CD38A00FBAD66 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 30 | B5DD505E206CD3FB00FBAD66 /* JYTestFile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JYTestFile.h; sourceTree = ""; }; 31 | B5DD505F206CD3FB00FBAD66 /* JYTestFile.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JYTestFile.m; sourceTree = ""; }; 32 | /* End PBXFileReference section */ 33 | 34 | /* Begin PBXFrameworksBuildPhase section */ 35 | B5DD5042206CD38A00FBAD66 /* Frameworks */ = { 36 | isa = PBXFrameworksBuildPhase; 37 | buildActionMask = 2147483647; 38 | files = ( 39 | ); 40 | runOnlyForDeploymentPostprocessing = 0; 41 | }; 42 | /* End PBXFrameworksBuildPhase section */ 43 | 44 | /* Begin PBXGroup section */ 45 | B5DD503C206CD38A00FBAD66 = { 46 | isa = PBXGroup; 47 | children = ( 48 | B5DD5047206CD38A00FBAD66 /* ProjectFixDemo */, 49 | B5DD5046206CD38A00FBAD66 /* Products */, 50 | ); 51 | sourceTree = ""; 52 | }; 53 | B5DD5046206CD38A00FBAD66 /* Products */ = { 54 | isa = PBXGroup; 55 | children = ( 56 | B5DD5045206CD38A00FBAD66 /* ProjectFixDemo.app */, 57 | ); 58 | name = Products; 59 | sourceTree = ""; 60 | }; 61 | B5DD5047206CD38A00FBAD66 /* ProjectFixDemo */ = { 62 | isa = PBXGroup; 63 | children = ( 64 | B5DD5048206CD38A00FBAD66 /* AppDelegate.h */, 65 | B5DD5049206CD38A00FBAD66 /* AppDelegate.m */, 66 | B5DD505E206CD3FB00FBAD66 /* JYTestFile.h */, 67 | B5DD505F206CD3FB00FBAD66 /* JYTestFile.m */, 68 | B5DD504B206CD38A00FBAD66 /* ViewController.h */, 69 | B5DD504C206CD38A00FBAD66 /* ViewController.m */, 70 | B5DD504E206CD38A00FBAD66 /* Main.storyboard */, 71 | B5DD5051206CD38A00FBAD66 /* Assets.xcassets */, 72 | B5DD5053206CD38A00FBAD66 /* LaunchScreen.storyboard */, 73 | B5DD5056206CD38A00FBAD66 /* Info.plist */, 74 | B5DD5057206CD38A00FBAD66 /* main.m */, 75 | ); 76 | path = ProjectFixDemo; 77 | sourceTree = ""; 78 | }; 79 | /* End PBXGroup section */ 80 | 81 | /* Begin PBXNativeTarget section */ 82 | B5DD5044206CD38A00FBAD66 /* ProjectFixDemo */ = { 83 | isa = PBXNativeTarget; 84 | buildConfigurationList = B5DD505B206CD38A00FBAD66 /* Build configuration list for PBXNativeTarget "ProjectFixDemo" */; 85 | buildPhases = ( 86 | B5DD5041206CD38A00FBAD66 /* Sources */, 87 | B5DD5042206CD38A00FBAD66 /* Frameworks */, 88 | B5DD5043206CD38A00FBAD66 /* Resources */, 89 | ); 90 | buildRules = ( 91 | ); 92 | dependencies = ( 93 | ); 94 | name = ProjectFixDemo; 95 | productName = ProjectFixDemo; 96 | productReference = B5DD5045206CD38A00FBAD66 /* ProjectFixDemo.app */; 97 | productType = "com.apple.product-type.application"; 98 | }; 99 | /* End PBXNativeTarget section */ 100 | 101 | /* Begin PBXProject section */ 102 | B5DD503D206CD38A00FBAD66 /* Project object */ = { 103 | isa = PBXProject; 104 | attributes = { 105 | CLASSPREFIX = JY; 106 | LastUpgradeCheck = 0920; 107 | ORGANIZATIONNAME = Journey; 108 | TargetAttributes = { 109 | B5DD5044206CD38A00FBAD66 = { 110 | CreatedOnToolsVersion = 9.2; 111 | ProvisioningStyle = Automatic; 112 | }; 113 | }; 114 | }; 115 | buildConfigurationList = B5DD5040206CD38A00FBAD66 /* Build configuration list for PBXProject "ProjectFixDemo" */; 116 | compatibilityVersion = "Xcode 8.0"; 117 | developmentRegion = en; 118 | hasScannedForEncodings = 0; 119 | knownRegions = ( 120 | en, 121 | Base, 122 | ); 123 | mainGroup = B5DD503C206CD38A00FBAD66; 124 | productRefGroup = B5DD5046206CD38A00FBAD66 /* Products */; 125 | projectDirPath = ""; 126 | projectRoot = ""; 127 | targets = ( 128 | B5DD5044206CD38A00FBAD66 /* ProjectFixDemo */, 129 | ); 130 | }; 131 | /* End PBXProject section */ 132 | 133 | /* Begin PBXResourcesBuildPhase section */ 134 | B5DD5043206CD38A00FBAD66 /* Resources */ = { 135 | isa = PBXResourcesBuildPhase; 136 | buildActionMask = 2147483647; 137 | files = ( 138 | B5DD5055206CD38A00FBAD66 /* LaunchScreen.storyboard in Resources */, 139 | B5DD5052206CD38A00FBAD66 /* Assets.xcassets in Resources */, 140 | B5DD5050206CD38A00FBAD66 /* Main.storyboard in Resources */, 141 | ); 142 | runOnlyForDeploymentPostprocessing = 0; 143 | }; 144 | /* End PBXResourcesBuildPhase section */ 145 | 146 | /* Begin PBXSourcesBuildPhase section */ 147 | B5DD5041206CD38A00FBAD66 /* Sources */ = { 148 | isa = PBXSourcesBuildPhase; 149 | buildActionMask = 2147483647; 150 | files = ( 151 | B5DD504D206CD38A00FBAD66 /* ViewController.m in Sources */, 152 | B5DD5058206CD38A00FBAD66 /* main.m in Sources */, 153 | B5DD5060206CD3FB00FBAD66 /* JYTestFile.m in Sources */, 154 | B5DD504A206CD38A00FBAD66 /* AppDelegate.m in Sources */, 155 | ); 156 | runOnlyForDeploymentPostprocessing = 0; 157 | }; 158 | /* End PBXSourcesBuildPhase section */ 159 | 160 | /* Begin PBXVariantGroup section */ 161 | B5DD504E206CD38A00FBAD66 /* Main.storyboard */ = { 162 | isa = PBXVariantGroup; 163 | children = ( 164 | B5DD504F206CD38A00FBAD66 /* Base */, 165 | ); 166 | name = Main.storyboard; 167 | sourceTree = ""; 168 | }; 169 | B5DD5053206CD38A00FBAD66 /* LaunchScreen.storyboard */ = { 170 | isa = PBXVariantGroup; 171 | children = ( 172 | B5DD5054206CD38A00FBAD66 /* Base */, 173 | ); 174 | name = LaunchScreen.storyboard; 175 | sourceTree = ""; 176 | }; 177 | /* End PBXVariantGroup section */ 178 | 179 | /* Begin XCBuildConfiguration section */ 180 | B5DD5059206CD38A00FBAD66 /* Debug */ = { 181 | isa = XCBuildConfiguration; 182 | buildSettings = { 183 | ALWAYS_SEARCH_USER_PATHS = NO; 184 | CLANG_ANALYZER_NONNULL = YES; 185 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 186 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 187 | CLANG_CXX_LIBRARY = "libc++"; 188 | CLANG_ENABLE_MODULES = YES; 189 | CLANG_ENABLE_OBJC_ARC = YES; 190 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 191 | CLANG_WARN_BOOL_CONVERSION = YES; 192 | CLANG_WARN_COMMA = YES; 193 | CLANG_WARN_CONSTANT_CONVERSION = YES; 194 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 195 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 196 | CLANG_WARN_EMPTY_BODY = YES; 197 | CLANG_WARN_ENUM_CONVERSION = YES; 198 | CLANG_WARN_INFINITE_RECURSION = YES; 199 | CLANG_WARN_INT_CONVERSION = YES; 200 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 201 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 202 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 203 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 204 | CLANG_WARN_STRICT_PROTOTYPES = YES; 205 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 206 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 207 | CLANG_WARN_UNREACHABLE_CODE = YES; 208 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 209 | CODE_SIGN_IDENTITY = "iPhone Developer"; 210 | COPY_PHASE_STRIP = NO; 211 | DEBUG_INFORMATION_FORMAT = dwarf; 212 | ENABLE_STRICT_OBJC_MSGSEND = YES; 213 | ENABLE_TESTABILITY = YES; 214 | GCC_C_LANGUAGE_STANDARD = gnu11; 215 | GCC_DYNAMIC_NO_PIC = NO; 216 | GCC_NO_COMMON_BLOCKS = YES; 217 | GCC_OPTIMIZATION_LEVEL = 0; 218 | GCC_PREPROCESSOR_DEFINITIONS = ( 219 | "DEBUG=1", 220 | "$(inherited)", 221 | ); 222 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 223 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 224 | GCC_WARN_UNDECLARED_SELECTOR = YES; 225 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 226 | GCC_WARN_UNUSED_FUNCTION = YES; 227 | GCC_WARN_UNUSED_VARIABLE = YES; 228 | IPHONEOS_DEPLOYMENT_TARGET = 11.2; 229 | MTL_ENABLE_DEBUG_INFO = YES; 230 | ONLY_ACTIVE_ARCH = YES; 231 | SDKROOT = iphoneos; 232 | }; 233 | name = Debug; 234 | }; 235 | B5DD505A206CD38A00FBAD66 /* Release */ = { 236 | isa = XCBuildConfiguration; 237 | buildSettings = { 238 | ALWAYS_SEARCH_USER_PATHS = NO; 239 | CLANG_ANALYZER_NONNULL = YES; 240 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 241 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 242 | CLANG_CXX_LIBRARY = "libc++"; 243 | CLANG_ENABLE_MODULES = YES; 244 | CLANG_ENABLE_OBJC_ARC = YES; 245 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 246 | CLANG_WARN_BOOL_CONVERSION = YES; 247 | CLANG_WARN_COMMA = YES; 248 | CLANG_WARN_CONSTANT_CONVERSION = YES; 249 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 250 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 251 | CLANG_WARN_EMPTY_BODY = YES; 252 | CLANG_WARN_ENUM_CONVERSION = YES; 253 | CLANG_WARN_INFINITE_RECURSION = YES; 254 | CLANG_WARN_INT_CONVERSION = YES; 255 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 256 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 257 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 258 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 259 | CLANG_WARN_STRICT_PROTOTYPES = YES; 260 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 261 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 262 | CLANG_WARN_UNREACHABLE_CODE = YES; 263 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 264 | CODE_SIGN_IDENTITY = "iPhone Developer"; 265 | COPY_PHASE_STRIP = NO; 266 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 267 | ENABLE_NS_ASSERTIONS = NO; 268 | ENABLE_STRICT_OBJC_MSGSEND = YES; 269 | GCC_C_LANGUAGE_STANDARD = gnu11; 270 | GCC_NO_COMMON_BLOCKS = YES; 271 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 272 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 273 | GCC_WARN_UNDECLARED_SELECTOR = YES; 274 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 275 | GCC_WARN_UNUSED_FUNCTION = YES; 276 | GCC_WARN_UNUSED_VARIABLE = YES; 277 | IPHONEOS_DEPLOYMENT_TARGET = 11.2; 278 | MTL_ENABLE_DEBUG_INFO = NO; 279 | SDKROOT = iphoneos; 280 | VALIDATE_PRODUCT = YES; 281 | }; 282 | name = Release; 283 | }; 284 | B5DD505C206CD38A00FBAD66 /* Debug */ = { 285 | isa = XCBuildConfiguration; 286 | buildSettings = { 287 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 288 | CODE_SIGN_STYLE = Automatic; 289 | DEVELOPMENT_TEAM = XC2SCRAXU5; 290 | INFOPLIST_FILE = ProjectFixDemo/Info.plist; 291 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 292 | PRODUCT_BUNDLE_IDENTIFIER = me.dingtone.ProjectFixDemo; 293 | PRODUCT_NAME = "$(TARGET_NAME)"; 294 | TARGETED_DEVICE_FAMILY = "1,2"; 295 | }; 296 | name = Debug; 297 | }; 298 | B5DD505D206CD38A00FBAD66 /* Release */ = { 299 | isa = XCBuildConfiguration; 300 | buildSettings = { 301 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 302 | CODE_SIGN_STYLE = Automatic; 303 | DEVELOPMENT_TEAM = XC2SCRAXU5; 304 | INFOPLIST_FILE = ProjectFixDemo/Info.plist; 305 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 306 | PRODUCT_BUNDLE_IDENTIFIER = me.dingtone.ProjectFixDemo; 307 | PRODUCT_NAME = "$(TARGET_NAME)"; 308 | TARGETED_DEVICE_FAMILY = "1,2"; 309 | }; 310 | name = Release; 311 | }; 312 | /* End XCBuildConfiguration section */ 313 | 314 | /* Begin XCConfigurationList section */ 315 | B5DD5040206CD38A00FBAD66 /* Build configuration list for PBXProject "ProjectFixDemo" */ = { 316 | isa = XCConfigurationList; 317 | buildConfigurations = ( 318 | B5DD5059206CD38A00FBAD66 /* Debug */, 319 | B5DD505A206CD38A00FBAD66 /* Release */, 320 | ); 321 | defaultConfigurationIsVisible = 0; 322 | defaultConfigurationName = Release; 323 | }; 324 | B5DD505B206CD38A00FBAD66 /* Build configuration list for PBXNativeTarget "ProjectFixDemo" */ = { 325 | isa = XCConfigurationList; 326 | buildConfigurations = ( 327 | B5DD505C206CD38A00FBAD66 /* Debug */, 328 | B5DD505D206CD38A00FBAD66 /* Release */, 329 | ); 330 | defaultConfigurationIsVisible = 0; 331 | defaultConfigurationName = Release; 332 | }; 333 | /* End XCConfigurationList section */ 334 | }; 335 | rootObject = B5DD503D206CD38A00FBAD66 /* Project object */; 336 | } 337 | -------------------------------------------------------------------------------- /ProjectMix/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // ProjectMix 4 | // 5 | // Created by Journey on 2018/2/8. 6 | // Copyright © 2018年 Journey. All rights reserved. 7 | // 8 | 9 | #import 10 | #include 11 | 12 | // 命令行修改工程目录下所有 png 资源 hash 值 13 | // 使用 ImageMagick 进行图片压缩,所以需要安装 ImageMagick,安装方法 brew install imagemagick 14 | // find . -iname "*.png" -exec echo {} \; -exec convert {} {} \; 15 | // or 16 | // find . -iname "*.png" -exec echo {} \; -exec convert {} -quality 95 {} \; 17 | 18 | typedef NS_ENUM(NSInteger, GSCSourceType) { 19 | GSCSourceTypeClass, 20 | GSCSourceTypeCategory, 21 | }; 22 | 23 | void recursiveDirectory(NSString *directory, NSArray *ignoreDirNames, void(^handleMFile)(NSString *mFilePath), void(^handleSwiftFile)(NSString *swiftFilePath)); 24 | void generateSpamCodeFile(NSString *outDirectory, NSString *mFilePath, GSCSourceType type); 25 | void addSpamCodeFile(NSString *sourceCodeDir); 26 | void generateSwiftSpamCodeFile(NSString *outDirectory, NSString *swiftFilePath); 27 | NSString *randomString(NSInteger length); 28 | void handleXcassetsFiles(NSString *directory); 29 | void deleteComments(NSString *directory); 30 | void modifyProjectName(NSString *projectDir, NSString *oldName, NSString *newName); 31 | void modifyClassNamePrefix(NSMutableString *projectContent, NSString *sourceCodeDir, NSArray *ignoreDirNames, NSString *oldName, NSString *newName); 32 | void replaceFileContend(NSString *sourceCodeDir,NSString *oldClassName,NSString *newClassName); 33 | void creatApiToFile(NSString *sourceCodeDir,NSString *apiName, NSString *paramName,NSString *logName,NSString *filePath, BOOL isHfile); 34 | void deleteAllSpamCode(NSString *sourceCodeDir,NSString *prefix); 35 | void changePrefix(NSString *sourceCodeDir, NSArray *ignoreDirNames,NSString *oldName, NSString *newName); 36 | void writeToFile(NSString *apiName); 37 | void modifyApi(NSString *sourceCodeDir,NSString *oldName,NSString *newName); 38 | void changeAPIName(NSString *sourceCodeDir,NSString *oldName); 39 | NSString *gOutParameterName = nil; 40 | NSString *gSourceCodeDir = nil; 41 | NSInteger kLocalImageIndex = 0; 42 | NSInteger kSpamCount = 0;//每四个垃圾方法加参数 43 | NSInteger kPercent = 101;//百分之多少概率加密就写多少 44 | NSInteger kImageCount = 0; 45 | NSInteger kfixImageCount = 0; 46 | 47 | 48 | #pragma mark - 公共方法 49 | 50 | static const NSString *kRandomAlphabet = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; 51 | 52 | 53 | ///递增命名本地图片资源,xcode中的图片名称不变 54 | NSString *randomString(NSInteger length) { 55 | //使用统一——背景名称 56 | NSString *imageName = [NSString stringWithFormat:@"insEyeImageSource_%03ld",(long)kLocalImageIndex]; 57 | kLocalImageIndex +=1; 58 | return imageName; 59 | } 60 | 61 | NSRange getOutermostCurlyBraceRange(NSString *string, unichar beginChar, unichar endChar, NSInteger beginIndex) { 62 | NSInteger braceCount = -1; 63 | NSInteger endIndex = string.length - 1; 64 | for (NSInteger i = beginIndex; i <= endIndex; i++) { 65 | unichar c = [string characterAtIndex:i]; 66 | if (c == beginChar) { 67 | braceCount = ((braceCount == -1) ? 0 : braceCount) + 1; 68 | } else if (c == endChar) { 69 | braceCount--; 70 | } 71 | if (braceCount == 0) { 72 | endIndex = i; 73 | break; 74 | } 75 | } 76 | return NSMakeRange(beginIndex + 1, endIndex - beginIndex - 1); 77 | } 78 | 79 | NSString * getSwiftImportString(NSString *string) { 80 | NSMutableString *ret = [NSMutableString string]; 81 | 82 | NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:@"^ *import *.+" options:NSRegularExpressionAnchorsMatchLines|NSRegularExpressionUseUnicodeWordBoundaries error:nil]; 83 | 84 | NSArray *matches = [expression matchesInString:string options:0 range:NSMakeRange(0, string.length)]; 85 | [matches enumerateObjectsUsingBlock:^(NSTextCheckingResult * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 86 | NSString *importRow = [string substringWithRange:obj.range]; 87 | [ret appendString:importRow]; 88 | [ret appendString:@"\n"]; 89 | }]; 90 | 91 | return ret; 92 | } 93 | 94 | BOOL regularReplacement(NSMutableString *originalString, NSString *regularExpression, NSString *newString) { 95 | __block BOOL isChanged = NO; 96 | BOOL isGroupNo1 = [newString isEqualToString:@"\\1"]; 97 | NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:regularExpression options:NSRegularExpressionAnchorsMatchLines|NSRegularExpressionUseUnixLineSeparators error:nil]; 98 | NSArray *matches = [expression matchesInString:originalString options:0 range:NSMakeRange(0, originalString.length)]; 99 | [matches enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(NSTextCheckingResult * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 100 | if (!isChanged) { 101 | isChanged = YES; 102 | } 103 | if (isGroupNo1) { 104 | NSString *withString = [originalString substringWithRange:[obj rangeAtIndex:1]]; 105 | [originalString replaceCharactersInRange:obj.range withString:withString]; 106 | } else { 107 | [originalString replaceCharactersInRange:obj.range withString:newString]; 108 | } 109 | }]; 110 | return isChanged; 111 | } 112 | 113 | void renameFile(NSString *oldPath, NSString *newPath) { 114 | NSError *error; 115 | [[NSFileManager defaultManager] moveItemAtPath:oldPath toPath:newPath error:&error]; 116 | if (error) { 117 | printf("修改文件名称失败。\n oldPath=%s\n newPath=%s\n ERROR:%s\n", oldPath.UTF8String, newPath.UTF8String, error.localizedDescription.UTF8String); 118 | abort(); 119 | } 120 | } 121 | 122 | #pragma mark - 主入口 123 | 124 | int main(int argc, const char * argv[]) { 125 | @autoreleasepool { 126 | NSArray *arguments = [[NSProcessInfo processInfo] arguments]; 127 | if (!arguments || arguments.count <= 1) { 128 | printf("缺少工程目录参数\n"); 129 | return 1; 130 | } 131 | if (arguments.count <= 2) { 132 | printf("缺少任务参数 -spamCodeOut or -handleXcassets or -deleteComments\n"); 133 | return 1; 134 | } 135 | 136 | BOOL isDirectory = NO; 137 | NSString *outDirString = nil; 138 | NSArray *ignoreDirNames = nil; 139 | BOOL needHandleXcassets = NO; 140 | BOOL needDeleteComments = NO; 141 | BOOL needModifyAPIName = NO; 142 | NSString *oldProjectName = nil; 143 | NSString *newProjectName = nil; 144 | NSString *projectFilePath = nil; 145 | NSString *oldClassNamePrefix = nil; 146 | NSString *newClassNamePrefix = nil; 147 | NSString *oldAPiPrefix = nil; 148 | NSString *newAPiPrefix = nil; 149 | 150 | NSFileManager *fm = [NSFileManager defaultManager]; 151 | for (NSInteger i = 1; i < arguments.count; i++) { 152 | NSString *argument = arguments[i]; 153 | if (i == 1) { 154 | gSourceCodeDir = argument; 155 | if (![fm fileExistsAtPath:gSourceCodeDir isDirectory:&isDirectory]) { 156 | printf("%s不存在\n", [gSourceCodeDir UTF8String]); 157 | return 1; 158 | } 159 | if (!isDirectory) { 160 | printf("%s不是目录\n", [gSourceCodeDir UTF8String]); 161 | return 1; 162 | } 163 | continue; 164 | } 165 | ///修改图片名字 166 | if ([argument isEqualToString:@"-handleXcassets"]) { 167 | needHandleXcassets = YES; 168 | continue; 169 | } 170 | if ([argument isEqualToString:@"-deleteComments"]) { 171 | needDeleteComments = YES; 172 | continue; 173 | } 174 | if ([argument isEqualToString:@"-modifyProjectName"]) { 175 | NSString *string = arguments[++i]; 176 | NSArray *names = [string componentsSeparatedByString:@">"]; 177 | if (names.count < 2) { 178 | printf("修改工程名参数错误。参数示例:CCApp>DDApp,传入参数:%s\n", string.UTF8String); 179 | return 1; 180 | } 181 | oldProjectName = names[0]; 182 | newProjectName = names[1]; 183 | if (oldProjectName.length <= 0 || newProjectName.length <= 0) { 184 | printf("修改工程名参数错误。参数示例:CCApp>DDApp,传入参数:%s\n", string.UTF8String); 185 | return 1; 186 | } 187 | continue; 188 | } 189 | if ([argument isEqualToString:@"-modifyClassNamePrefix"]) { 190 | NSString *string = arguments[++i]; 191 | projectFilePath = [string stringByAppendingPathComponent:@"project.pbxproj"]; 192 | if (![fm fileExistsAtPath:string isDirectory:&isDirectory] || !isDirectory 193 | || ![fm fileExistsAtPath:projectFilePath isDirectory:&isDirectory] || isDirectory) { 194 | printf("修改类名前缀的工程文件参数错误。%s", string.UTF8String); 195 | return 1; 196 | } 197 | 198 | string = arguments[++i]; 199 | NSArray *names = [string componentsSeparatedByString:@">"]; 200 | if (names.count < 2) { 201 | printf("修改类名前缀参数错误。参数示例:CC>DD,传入参数:%s\n", string.UTF8String); 202 | return 1; 203 | } 204 | oldClassNamePrefix = names[0]; 205 | newClassNamePrefix = names[1]; 206 | if (oldClassNamePrefix.length <= 0 || newClassNamePrefix.length <= 0) { 207 | printf("修改类名前缀参数错误。参数示例:CC>DD,传入参数:%s\n", string.UTF8String); 208 | return 1; 209 | } 210 | continue; 211 | } 212 | if ([argument isEqualToString:@"-spamCodeOut"]) { 213 | outDirString = @"新增垃圾代码"; 214 | // outDirString = arguments[++i]; 215 | // if ([fm fileExistsAtPath:outDirString isDirectory:&isDirectory]) { 216 | // if (!isDirectory) { 217 | // printf("%s 已存在但不是文件夹,需要传入一个输出文件夹目录\n", [outDirString UTF8String]); 218 | // return 1; 219 | // } 220 | // } else { 221 | // NSError *error = nil; 222 | // if (![fm createDirectoryAtPath:outDirString withIntermediateDirectories:YES attributes:nil error:&error]) { 223 | // printf("创建输出目录失败,请确认 -spamCodeOut 之后接的是一个“输出文件夹目录”参数,错误信息如下:\n传入的输出文件夹目录:%s\n%s\n", [outDirString UTF8String], [error.localizedDescription UTF8String]); 224 | // return 1; 225 | // } 226 | // } 227 | // 228 | // i++; 229 | // if (i < arguments.count) { 230 | // gOutParameterName = arguments[i]; 231 | // NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"[a-zA-Z]+" options:0 error:nil]; 232 | // if ([regex numberOfMatchesInString:gOutParameterName options:0 range:NSMakeRange(0, gOutParameterName.length)] <= 0) { 233 | // printf("缺少垃圾代码参数名,或参数名\"%s\"不合法(需要字母开头)\n", [gOutParameterName UTF8String]); 234 | // return 1; 235 | // } 236 | // } else { 237 | // printf("缺少垃圾代码参数名,参数名需要根在输出目录后面\n"); 238 | // return 1; 239 | // } 240 | // 241 | continue; 242 | } 243 | if ([argument isEqualToString:@"-ignoreDirNames"]) { 244 | ignoreDirNames = [arguments[++i] componentsSeparatedByString:@","]; 245 | continue; 246 | } 247 | if ([argument isEqualToString:@"-chageAPIPrefix"]){ 248 | NSString *string = arguments[++i]; 249 | NSArray *names = [string componentsSeparatedByString:@">"]; 250 | if (names.count < 2) { 251 | printf("修改方法名前缀参数错误。参数示例:gd_>ie_,传入参数:%s\n", string.UTF8String); 252 | return 1; 253 | } 254 | oldAPiPrefix = names[0]; 255 | newAPiPrefix = names[1]; 256 | if (oldAPiPrefix.length <= 0 || newAPiPrefix.length <= 0 || ![oldAPiPrefix containsString:@"_"] || ![newAPiPrefix containsString:@"_"]) { 257 | printf("修改方法名前缀参数错误。参数示例:gd_>ie_,传入参数:%s\n", string.UTF8String); 258 | return 1; 259 | } 260 | continue; 261 | } 262 | if([argument isEqualToString:@"-modifyAPIName"]){ 263 | needModifyAPIName = YES; 264 | continue; 265 | } 266 | } 267 | 268 | if (needHandleXcassets) { 269 | @autoreleasepool { 270 | handleXcassetsFiles(gSourceCodeDir); 271 | printf("正在修改图片。。。"); 272 | } 273 | printf("修改 Xcassets 中的图片名称完成,一共有%ld个图片文件,修改了%ld个\n",(long)kImageCount,(long)kfixImageCount); 274 | } 275 | if (needModifyAPIName){ 276 | printf("正在修改api名称\n"); 277 | @autoreleasepool { 278 | deleteAllSpamCode(gSourceCodeDir,@"sp_"); 279 | } 280 | printf("修改api名称完成\n"); 281 | } 282 | if (needDeleteComments) { 283 | @autoreleasepool { 284 | deleteComments(gSourceCodeDir); 285 | } 286 | printf("删除注释和空行完成\n"); 287 | } 288 | if (oldProjectName && newProjectName) { 289 | printf("正在修改工程名\n"); 290 | @autoreleasepool { 291 | NSString *dir = gSourceCodeDir.stringByDeletingLastPathComponent; 292 | modifyProjectName(dir, oldProjectName, newProjectName); 293 | } 294 | printf("修改工程名完成\n"); 295 | } 296 | if (oldClassNamePrefix && newClassNamePrefix) { 297 | printf("开始修改类名前缀...\n"); 298 | @autoreleasepool { 299 | // 打开工程文件 300 | NSError *error = nil; 301 | NSMutableString *projectContent = [NSMutableString stringWithContentsOfFile:projectFilePath encoding:NSUTF8StringEncoding error:&error]; 302 | if (error) { 303 | printf("打开工程文件 %s 失败:%s\n", projectFilePath.UTF8String, error.localizedDescription.UTF8String); 304 | return 1; 305 | } 306 | 307 | modifyClassNamePrefix(projectContent, gSourceCodeDir, ignoreDirNames, oldClassNamePrefix, newClassNamePrefix); 308 | 309 | [projectContent writeToFile:projectFilePath atomically:YES encoding:NSUTF8StringEncoding error:nil]; 310 | } 311 | printf("修改类名前缀完成\n"); 312 | } 313 | if (outDirString) { 314 | @autoreleasepool { 315 | printf("正在生成垃圾代码\n"); 316 | addSpamCodeFile(gSourceCodeDir); 317 | } 318 | // recursiveDirectory(gSourceCodeDir, ignoreDirNames, ^(NSString *mFilePath) { 319 | // 320 | // }, ^(NSString *swiftFilePath) { 321 | // @autoreleasepool { 322 | // generateSwiftSpamCodeFile(outDirString, swiftFilePath); 323 | // } 324 | // }); 325 | printf("生成垃圾代码完成\n"); 326 | } 327 | if(newAPiPrefix &&oldAPiPrefix){ 328 | @autoreleasepool { 329 | printf("正在替换方法名前缀\n"); 330 | changePrefix(gSourceCodeDir, ignoreDirNames, oldAPiPrefix, newAPiPrefix); 331 | } 332 | printf("替换方法名前缀完成\n"); 333 | } 334 | } 335 | return 0; 336 | } 337 | 338 | #pragma mark - 生成垃圾代码 339 | 340 | void recursiveDirectory(NSString *directory, NSArray *ignoreDirNames, void(^handleMFile)(NSString *mFilePath), void(^handleSwiftFile)(NSString *swiftFilePath)) { 341 | NSFileManager *fm = [NSFileManager defaultManager]; 342 | NSArray *files = [fm contentsOfDirectoryAtPath:directory error:nil]; 343 | BOOL isDirectory; 344 | for (NSString *filePath in files) { 345 | NSString *path = [directory stringByAppendingPathComponent:filePath]; 346 | if ([fm fileExistsAtPath:path isDirectory:&isDirectory] && isDirectory) { 347 | if (![ignoreDirNames containsObject:filePath]) { 348 | recursiveDirectory(path, nil, handleMFile, handleSwiftFile); 349 | } 350 | continue; 351 | } 352 | NSString *fileName = filePath.lastPathComponent; 353 | if ([fileName hasSuffix:@".h"]) { 354 | fileName = [fileName stringByDeletingPathExtension]; 355 | 356 | NSString *mFileName = [fileName stringByAppendingPathExtension:@"m"]; 357 | if ([files containsObject:mFileName]) { 358 | handleMFile([directory stringByAppendingPathComponent:mFileName]); 359 | } 360 | } else if ([fileName hasSuffix:@".swift"]) { 361 | handleSwiftFile([directory stringByAppendingPathComponent:fileName]); 362 | } 363 | } 364 | } 365 | 366 | NSString * getImportString(NSString *hFileContent, NSString *mFileContent) { 367 | NSMutableString *ret = [NSMutableString string]; 368 | 369 | NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:@"^ *[@#]import *.+" options:NSRegularExpressionAnchorsMatchLines|NSRegularExpressionUseUnicodeWordBoundaries error:nil]; 370 | 371 | NSArray *matches = [expression matchesInString:hFileContent options:0 range:NSMakeRange(0, hFileContent.length)]; 372 | [matches enumerateObjectsUsingBlock:^(NSTextCheckingResult * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 373 | NSString *importRow = [hFileContent substringWithRange:[obj rangeAtIndex:0]]; 374 | [ret appendString:importRow]; 375 | [ret appendString:@"\n"]; 376 | }]; 377 | 378 | matches = [expression matchesInString:mFileContent options:0 range:NSMakeRange(0, mFileContent.length)]; 379 | [matches enumerateObjectsUsingBlock:^(NSTextCheckingResult * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 380 | NSString *importRow = [mFileContent substringWithRange:[obj rangeAtIndex:0]]; 381 | [ret appendString:importRow]; 382 | [ret appendString:@"\n"]; 383 | }]; 384 | 385 | return ret; 386 | } 387 | 388 | static NSString *const kHClassFileTemplate = @"\ 389 | %@\n\ 390 | @interface %@ (%@)\n\ 391 | %@\n\ 392 | @end\n"; 393 | static NSString *const kMClassFileTemplate = @"\ 394 | #import \"%@+%@.h\"\n\ 395 | @implementation %@ (%@)\n\ 396 | %@\n\ 397 | @end\n"; 398 | 399 | ///添加垃圾代码的策略 400 | ///为每一个.m文件添加一个方法, 401 | void addSpamCodeFile(NSString *sourceCodeDir){ 402 | NSFileManager *fm = [NSFileManager defaultManager]; 403 | NSArray *files = [fm contentsOfDirectoryAtPath:sourceCodeDir error:nil]; 404 | BOOL isDirectory; 405 | 406 | for (NSString *filePath in files) { 407 | NSString *path = [sourceCodeDir stringByAppendingPathComponent:filePath]; 408 | ///如果路径下的是文件夹,继续往下走,知道找到一个文件 409 | if ([fm fileExistsAtPath:path isDirectory:&isDirectory] && isDirectory) { 410 | addSpamCodeFile(path); 411 | continue; 412 | } 413 | NSString *fileName = filePath.lastPathComponent; 414 | ///mm文件先不管 415 | if ([fileName hasSuffix:@".h"]) { 416 | NSString *hfileName = fileName.stringByDeletingPathExtension; 417 | NSString *mFileName = [hfileName stringByAppendingPathExtension:@"m"]; 418 | if (![files containsObject:mFileName]) { 419 | continue; 420 | } 421 | 422 | NSArray *apiList = @[@"sp_checkUserInfo",@"sp_upload",@"sp_getMediaData",@"sp_didGetInfoSuccess",@"sp_getUserFollowSuccess",@"sp_getLoginState",@"sp_checkNetWorking",@"sp_checkInfo",@"sp_getMediaFailed",@"sp_getUserName",@"sp_checkDefualtSetting",@"sp_didUserInfoFailed",@"sp_getUsersMostLiked",@"sp_getUsersMostLikedSuccess",@"sp_getUsersMostFollowerSuccess"]; 423 | NSArray *logList = @[@"Get Info Success",@"Get Info Failed",@"Continue",@"Check your Network",@"Get User Succrss"]; 424 | NSArray *param = @[@"string",@"mediaInfo",@"followCount",@"mediaCount",@"isLogin"]; 425 | int listIndex = arc4random() % 15; 426 | int logIndex = arc4random() % 5; 427 | 428 | ///概率修改 429 | NSInteger k = arc4random()%100; 430 | if(k>kPercent){ 431 | continue; 432 | } 433 | creatApiToFile(sourceCodeDir, apiList[listIndex], param[logIndex], logList[logIndex], [sourceCodeDir stringByAppendingPathComponent:filePath], YES); 434 | 435 | creatApiToFile(sourceCodeDir, apiList[listIndex], param[logIndex], logList[logIndex], filePath, NO); 436 | kSpamCount += 1; 437 | 438 | } 439 | } 440 | } 441 | 442 | void creatApiToFile(NSString *sourceCodeDir,NSString *apiName, NSString *paramName,NSString *logName,NSString *filePath, BOOL isHfile){ 443 | if(isHfile){ 444 | NSError *error = nil; 445 | NSMutableString *fileContent = [NSMutableString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error]; 446 | if([fileContent containsString:[NSString stringWithFormat:@"- (void)%@:(NSString *)%@;\n", apiName,paramName]]){ 447 | return; 448 | } 449 | if(kSpamCount%4 == 0){ 450 | NSString *s = @"@end"; 451 | NSArray *endArray = [fileContent componentsSeparatedByString:s]; 452 | NSMutableArray *arrayOfLocation=[NSMutableArray new]; 453 | int d=0; 454 | for (int i=0; i *matches = [expression matchesInString:mFileContent options:0 range:NSMakeRange(0, mFileContent.length)]; 563 | if (matches.count <= 0) return; 564 | 565 | NSString *hFilePath = [mFilePath.stringByDeletingPathExtension stringByAppendingPathExtension:@"h"]; 566 | NSString *hFileContent = [NSString stringWithContentsOfFile:hFilePath encoding:NSUTF8StringEncoding error:nil]; 567 | 568 | // 准备要引入的文件 569 | NSString *importString = getImportString(hFileContent, mFileContent); 570 | 571 | [matches enumerateObjectsUsingBlock:^(NSTextCheckingResult * _Nonnull impResult, NSUInteger idx, BOOL * _Nonnull stop) { 572 | NSString *className = [mFileContent substringWithRange:[impResult rangeAtIndex:1]]; 573 | NSString *categoryName = nil; 574 | if (impResult.numberOfRanges >= 3) { 575 | categoryName = [mFileContent substringWithRange:[impResult rangeAtIndex:2]]; 576 | } 577 | 578 | if (type == GSCSourceTypeClass) { 579 | // 如果该类型没有公开,只在 .m 文件中使用,则不处理 580 | NSString *regexStr = [NSString stringWithFormat:@"\\b%@\\b", className]; 581 | NSRange range = [hFileContent rangeOfString:regexStr options:NSRegularExpressionSearch]; 582 | if (range.location == NSNotFound) { 583 | return; 584 | } 585 | } 586 | 587 | // 查找方法 588 | NSString *implementation = [mFileContent substringWithRange:impResult.range]; 589 | NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:@"^ *([-+])[^)]+\\)([^;{]+)" options:NSRegularExpressionAnchorsMatchLines|NSRegularExpressionUseUnicodeWordBoundaries error:nil]; 590 | NSArray *matches = [expression matchesInString:implementation options:0 range:NSMakeRange(0, implementation.length)]; 591 | if (matches.count <= 0) return; 592 | 593 | // 生成 h m 垃圾文件内容 594 | NSMutableString *hFileMethodsString = [NSMutableString string]; 595 | NSMutableString *mFileMethodsString = [NSMutableString string]; 596 | [matches enumerateObjectsUsingBlock:^(NSTextCheckingResult * _Nonnull matche, NSUInteger idx, BOOL * _Nonnull stop) { 597 | NSString *symbol = [implementation substringWithRange:[matche rangeAtIndex:1]]; 598 | NSString *methodName = [[implementation substringWithRange:[matche rangeAtIndex:2]] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; 599 | if ([methodName containsString:@":"]) { 600 | methodName = [methodName stringByAppendingFormat:@" %@:(NSString *)%@", gOutParameterName, gOutParameterName]; 601 | } else { 602 | methodName = [methodName stringByAppendingFormat:@"%@:(NSString *)%@", gOutParameterName.capitalizedString, gOutParameterName]; 603 | } 604 | 605 | [hFileMethodsString appendFormat:@"%@ (void)%@;\n", symbol, methodName]; 606 | 607 | [mFileMethodsString appendFormat:@"%@ (void)%@ {\n", symbol, methodName]; 608 | [mFileMethodsString appendFormat:@" NSLog(@\"%%@\", %@);\n", gOutParameterName]; 609 | [mFileMethodsString appendString:@"}\n"]; 610 | }]; 611 | 612 | NSString *newCategoryName; 613 | switch (type) { 614 | case GSCSourceTypeClass: 615 | newCategoryName = gOutParameterName.capitalizedString; 616 | break; 617 | case GSCSourceTypeCategory: 618 | newCategoryName = [NSString stringWithFormat:@"%@%@", categoryName, gOutParameterName.capitalizedString]; 619 | break; 620 | } 621 | 622 | NSString *fileName = [NSString stringWithFormat:@"%@+%@.h", className, newCategoryName]; 623 | NSString *fileContent = [NSString stringWithFormat:kHClassFileTemplate, importString, className, newCategoryName, hFileMethodsString]; 624 | [fileContent writeToFile:[outDirectory stringByAppendingPathComponent:fileName] atomically:YES encoding:NSUTF8StringEncoding error:nil]; 625 | 626 | fileName = [NSString stringWithFormat:@"%@+%@.m", className, newCategoryName]; 627 | fileContent = [NSString stringWithFormat:kMClassFileTemplate, className, newCategoryName, className, newCategoryName, mFileMethodsString]; 628 | [fileContent writeToFile:[outDirectory stringByAppendingPathComponent:fileName] atomically:YES encoding:NSUTF8StringEncoding error:nil]; 629 | }]; 630 | } 631 | 632 | static NSString *const kSwiftFileTemplate = @"\ 633 | %@\n\ 634 | extension %@ {\n%@\ 635 | }\n"; 636 | static NSString *const kSwiftMethodTemplate = @"\ 637 | func %@%@(_ %@: String%@) {\n\ 638 | print(%@)\n\ 639 | }\n"; 640 | void generateSwiftSpamCodeFile(NSString *outDirectory, NSString *swiftFilePath) { 641 | NSString *swiftFileContent = [NSString stringWithContentsOfFile:swiftFilePath encoding:NSUTF8StringEncoding error:nil]; 642 | 643 | // 查找 class 声明 644 | NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:@" *(class|struct) +(\\w+)[^{]+" options:NSRegularExpressionUseUnicodeWordBoundaries error:nil]; 645 | NSArray *matches = [expression matchesInString:swiftFileContent options:0 range:NSMakeRange(0, swiftFileContent.length)]; 646 | if (matches.count <= 0) return; 647 | 648 | NSString *fileImportStrings = getSwiftImportString(swiftFileContent); 649 | __block NSInteger braceEndIndex = 0; 650 | [matches enumerateObjectsUsingBlock:^(NSTextCheckingResult * _Nonnull classResult, NSUInteger idx, BOOL * _Nonnull stop) { 651 | // 已经处理到该 range 后面去了,过掉 652 | NSInteger matchEndIndex = classResult.range.location + classResult.range.length; 653 | if (matchEndIndex < braceEndIndex) return; 654 | // 是 class 方法,过掉 655 | NSString *fullMatchString = [swiftFileContent substringWithRange:classResult.range]; 656 | if ([fullMatchString containsString:@"("]) return; 657 | 658 | NSRange braceRange = getOutermostCurlyBraceRange(swiftFileContent, '{', '}', matchEndIndex); 659 | braceEndIndex = braceRange.location + braceRange.length; 660 | 661 | // 查找方法 662 | NSString *classContent = [swiftFileContent substringWithRange:braceRange]; 663 | NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:@"func +([^(]+)\\([^{]+" options:NSRegularExpressionUseUnicodeWordBoundaries error:nil]; 664 | NSArray *matches = [expression matchesInString:classContent options:0 range:NSMakeRange(0, classContent.length)]; 665 | if (matches.count <= 0) return; 666 | 667 | NSMutableString *methodsString = [NSMutableString string]; 668 | [matches enumerateObjectsUsingBlock:^(NSTextCheckingResult * _Nonnull funcResult, NSUInteger idx, BOOL * _Nonnull stop) { 669 | NSRange funcNameRange = [funcResult rangeAtIndex:1]; 670 | NSString *funcName = [classContent substringWithRange:funcNameRange]; 671 | NSRange oldParameterRange = getOutermostCurlyBraceRange(classContent, '(', ')', funcNameRange.location + funcNameRange.length); 672 | NSString *oldParameterName = [classContent substringWithRange:oldParameterRange]; 673 | oldParameterName = [oldParameterName stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; 674 | if (oldParameterName.length > 0) { 675 | oldParameterName = [@", " stringByAppendingString:oldParameterName]; 676 | } 677 | [methodsString appendFormat:kSwiftMethodTemplate, funcName, gOutParameterName.capitalizedString, gOutParameterName, oldParameterName, gOutParameterName]; 678 | }]; 679 | if (methodsString.length <= 0) return; 680 | 681 | NSString *className = [swiftFileContent substringWithRange:[classResult rangeAtIndex:2]]; 682 | 683 | NSString *fileName = [NSString stringWithFormat:@"%@%@Ext.swift", className, gOutParameterName.capitalizedString]; 684 | NSString *filePath = [outDirectory stringByAppendingPathComponent:fileName]; 685 | NSString *fileContent = @""; 686 | if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) { 687 | fileContent = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; 688 | } 689 | fileContent = [fileContent stringByAppendingFormat:kSwiftFileTemplate, fileImportStrings, className, methodsString]; 690 | [fileContent writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil]; 691 | }]; 692 | } 693 | 694 | #pragma mark - 处理 Xcassets 中的图片文件 695 | 696 | void handleXcassetsFiles(NSString *directory) { 697 | NSFileManager *fm = [NSFileManager defaultManager]; 698 | NSArray *files = [fm contentsOfDirectoryAtPath:directory error:nil]; 699 | BOOL isDirectory; 700 | for (NSString *fileName in files) { 701 | NSString *filePath = [directory stringByAppendingPathComponent:fileName]; 702 | if ([fm fileExistsAtPath:filePath isDirectory:&isDirectory] && isDirectory) { 703 | handleXcassetsFiles(filePath); 704 | continue; 705 | } 706 | if (![fileName isEqualToString:@"Contents.json"]) continue; 707 | NSString *contentsDirectoryName = filePath.stringByDeletingLastPathComponent.lastPathComponent; 708 | if (![contentsDirectoryName hasSuffix:@".imageset"]) continue; 709 | 710 | NSString *fileContent = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; 711 | if (!fileContent) continue; 712 | 713 | NSMutableArray *processedImageFileNameArray = @[].mutableCopy; 714 | static NSString * const regexStr = @"\"filename\" *: *\"(.*)?\""; 715 | NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:regexStr options:NSRegularExpressionUseUnicodeWordBoundaries error:nil]; 716 | NSArray *matches = [expression matchesInString:fileContent options:0 range:NSMakeRange(0, fileContent.length)]; 717 | while (matches.count > 0) { 718 | NSInteger i = 0; 719 | NSString *imageFileName = nil; 720 | do { 721 | if (i >= matches.count) { 722 | i = -1; 723 | break; 724 | } 725 | imageFileName = [fileContent substringWithRange:[matches[i] rangeAtIndex:1]]; 726 | i++; 727 | } while ([processedImageFileNameArray containsObject:imageFileName]); 728 | if (i < 0) break; 729 | 730 | NSString *imageFilePath = [filePath.stringByDeletingLastPathComponent stringByAppendingPathComponent:imageFileName]; 731 | ///先 732 | NSInteger k = arc4random()%100; 733 | //概率混淆 734 | kImageCount += 1; 735 | if(k>kPercent){ 736 | continue; 737 | } 738 | kfixImageCount +=1; 739 | if ([fm fileExistsAtPath:imageFilePath]) { 740 | NSString *newImageFileName = [randomString(10) stringByAppendingPathExtension:imageFileName.pathExtension]; 741 | NSString *newImageFilePath = [filePath.stringByDeletingLastPathComponent stringByAppendingPathComponent:newImageFileName]; 742 | while ([fm fileExistsAtPath:newImageFileName]) { 743 | newImageFileName = [randomString(10) stringByAppendingPathExtension:imageFileName.pathExtension]; 744 | newImageFilePath = [filePath.stringByDeletingLastPathComponent stringByAppendingPathComponent:newImageFileName]; 745 | } 746 | 747 | renameFile(imageFilePath, newImageFilePath); 748 | 749 | fileContent = [fileContent stringByReplacingOccurrencesOfString:[NSString stringWithFormat:@"\"%@\"", imageFileName] 750 | withString:[NSString stringWithFormat:@"\"%@\"", newImageFileName]]; 751 | [fileContent writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil]; 752 | 753 | [processedImageFileNameArray addObject:newImageFileName]; 754 | } else { 755 | [processedImageFileNameArray addObject:imageFileName]; 756 | } 757 | 758 | matches = [expression matchesInString:fileContent options:0 range:NSMakeRange(0, fileContent.length)]; 759 | } 760 | } 761 | } 762 | 763 | #pragma mark - 删除注释 764 | 765 | void deleteComments(NSString *directory) { 766 | NSFileManager *fm = [NSFileManager defaultManager]; 767 | NSArray *files = [fm contentsOfDirectoryAtPath:directory error:nil]; 768 | BOOL isDirectory; 769 | for (NSString *fileName in files) { 770 | NSString *filePath = [directory stringByAppendingPathComponent:fileName]; 771 | if ([fm fileExistsAtPath:filePath isDirectory:&isDirectory] && isDirectory) { 772 | deleteComments(filePath); 773 | continue; 774 | } 775 | if (![fileName hasSuffix:@".h"] && ![fileName hasSuffix:@".m"] && ![fileName hasSuffix:@".swift"]) continue; 776 | NSMutableString *fileContent = [NSMutableString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; 777 | regularReplacement(fileContent, @"([^:/])//.*", @"\\1"); 778 | regularReplacement(fileContent, @"^//.*", @""); 779 | regularReplacement(fileContent, @"/\\*{1,2}[\\s\\S]*?\\*/", @""); 780 | regularReplacement(fileContent, @"^\\s*\\n", @""); 781 | [fileContent writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil]; 782 | } 783 | } 784 | 785 | #pragma mark - 修改工程名 786 | 787 | void resetEntitlementsFileName(NSString *projectPbxprojFilePath, NSString *oldName, NSString *newName) { 788 | NSString *rootPath = projectPbxprojFilePath.stringByDeletingLastPathComponent.stringByDeletingLastPathComponent; 789 | NSMutableString *fileContent = [NSMutableString stringWithContentsOfFile:projectPbxprojFilePath encoding:NSUTF8StringEncoding error:nil]; 790 | 791 | NSString *regularExpression = @"CODE_SIGN_ENTITLEMENTS = \"?([^\";]+)"; 792 | NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:regularExpression options:0 error:nil]; 793 | NSArray *matches = [expression matchesInString:fileContent options:0 range:NSMakeRange(0, fileContent.length)]; 794 | [matches enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(NSTextCheckingResult * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 795 | NSString *entitlementsPath = [fileContent substringWithRange:[obj rangeAtIndex:1]]; 796 | NSString *entitlementsName = entitlementsPath.lastPathComponent.stringByDeletingPathExtension; 797 | if (![entitlementsName isEqualToString:oldName]) return; 798 | entitlementsPath = [rootPath stringByAppendingPathComponent:entitlementsPath]; 799 | if (![[NSFileManager defaultManager] fileExistsAtPath:entitlementsPath]) return; 800 | NSString *newPath = [entitlementsPath.stringByDeletingLastPathComponent stringByAppendingPathComponent:[newName stringByAppendingPathExtension:@"entitlements"]]; 801 | renameFile(entitlementsPath, newPath); 802 | }]; 803 | } 804 | 805 | void resetBridgingHeaderFileName(NSString *projectPbxprojFilePath, NSString *oldName, NSString *newName) { 806 | NSString *rootPath = projectPbxprojFilePath.stringByDeletingLastPathComponent.stringByDeletingLastPathComponent; 807 | NSMutableString *fileContent = [NSMutableString stringWithContentsOfFile:projectPbxprojFilePath encoding:NSUTF8StringEncoding error:nil]; 808 | 809 | NSString *regularExpression = @"SWIFT_OBJC_BRIDGING_HEADER = \"?([^\";]+)"; 810 | NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:regularExpression options:0 error:nil]; 811 | NSArray *matches = [expression matchesInString:fileContent options:0 range:NSMakeRange(0, fileContent.length)]; 812 | [matches enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(NSTextCheckingResult * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 813 | NSString *entitlementsPath = [fileContent substringWithRange:[obj rangeAtIndex:1]]; 814 | NSString *entitlementsName = entitlementsPath.lastPathComponent.stringByDeletingPathExtension; 815 | if (![entitlementsName isEqualToString:oldName]) return; 816 | entitlementsPath = [rootPath stringByAppendingPathComponent:entitlementsPath]; 817 | if (![[NSFileManager defaultManager] fileExistsAtPath:entitlementsPath]) return; 818 | NSString *newPath = [entitlementsPath.stringByDeletingLastPathComponent stringByAppendingPathComponent:[newName stringByAppendingPathExtension:@"h"]]; 819 | renameFile(entitlementsPath, newPath); 820 | }]; 821 | } 822 | 823 | void replacePodfileContent(NSString *filePath, NSString *oldString, NSString *newString) { 824 | NSMutableString *fileContent = [NSMutableString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; 825 | 826 | NSString *regularExpression = [NSString stringWithFormat:@"target +'%@", oldString]; 827 | NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:regularExpression options:0 error:nil]; 828 | NSArray *matches = [expression matchesInString:fileContent options:0 range:NSMakeRange(0, fileContent.length)]; 829 | [matches enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(NSTextCheckingResult * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 830 | [fileContent replaceCharactersInRange:obj.range withString:[NSString stringWithFormat:@"target '%@", newString]]; 831 | }]; 832 | 833 | regularExpression = [NSString stringWithFormat:@"project +'%@.", oldString]; 834 | expression = [NSRegularExpression regularExpressionWithPattern:regularExpression options:0 error:nil]; 835 | matches = [expression matchesInString:fileContent options:0 range:NSMakeRange(0, fileContent.length)]; 836 | [matches enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(NSTextCheckingResult * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 837 | [fileContent replaceCharactersInRange:obj.range withString:[NSString stringWithFormat:@"project '%@.", newString]]; 838 | }]; 839 | 840 | [fileContent writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil]; 841 | } 842 | 843 | void replaceProjectFileContent(NSString *filePath, NSString *oldString, NSString *newString) { 844 | NSMutableString *fileContent = [NSMutableString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; 845 | 846 | NSString *regularExpression = [NSString stringWithFormat:@"\\b%@\\b", oldString]; 847 | NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:regularExpression options:0 error:nil]; 848 | NSArray *matches = [expression matchesInString:fileContent options:0 range:NSMakeRange(0, fileContent.length)]; 849 | [matches enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(NSTextCheckingResult * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 850 | [fileContent replaceCharactersInRange:obj.range withString:newString]; 851 | }]; 852 | 853 | [fileContent writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil]; 854 | } 855 | 856 | void modifyFilesClassName(NSString *sourceCodeDir, NSString *oldClassName, NSString *newClassName); 857 | 858 | void modifyProjectName(NSString *projectDir, NSString *oldName, NSString *newName) { 859 | NSString *sourceCodeDirPath = [projectDir stringByAppendingPathComponent:oldName]; 860 | NSString *xcodeprojFilePath = [sourceCodeDirPath stringByAppendingPathExtension:@"xcodeproj"]; 861 | NSString *xcworkspaceFilePath = [sourceCodeDirPath stringByAppendingPathExtension:@"xcworkspace"]; 862 | 863 | NSFileManager *fm = [NSFileManager defaultManager]; 864 | BOOL isDirectory; 865 | 866 | // old-Swift.h > new-Swift.h 867 | modifyFilesClassName(projectDir, [oldName stringByAppendingString:@"-Swift.h"], [newName stringByAppendingString:@"-Swift.h"]); 868 | 869 | // 改 Podfile 中的工程名 870 | NSString *podfilePath = [projectDir stringByAppendingPathComponent:@"Podfile"]; 871 | if ([fm fileExistsAtPath:podfilePath isDirectory:&isDirectory] && !isDirectory) { 872 | replacePodfileContent(podfilePath, oldName, newName); 873 | } 874 | 875 | // 改工程文件内容 876 | if ([fm fileExistsAtPath:xcodeprojFilePath isDirectory:&isDirectory] && isDirectory) { 877 | // 替换 project.pbxproj 文件内容 878 | NSString *projectPbxprojFilePath = [xcodeprojFilePath stringByAppendingPathComponent:@"project.pbxproj"]; 879 | if ([fm fileExistsAtPath:projectPbxprojFilePath]) { 880 | resetBridgingHeaderFileName(projectPbxprojFilePath, [oldName stringByAppendingString:@"-Bridging-Header"], [newName stringByAppendingString:@"-Bridging-Header"]); 881 | resetEntitlementsFileName(projectPbxprojFilePath, oldName, newName); 882 | replaceProjectFileContent(projectPbxprojFilePath, oldName, newName); 883 | } 884 | // 替换 project.xcworkspace/contents.xcworkspacedata 文件内容 885 | NSString *contentsXcworkspacedataFilePath = [xcodeprojFilePath stringByAppendingPathComponent:@"project.xcworkspace/contents.xcworkspacedata"]; 886 | if ([fm fileExistsAtPath:contentsXcworkspacedataFilePath]) { 887 | replaceProjectFileContent(contentsXcworkspacedataFilePath, oldName, newName); 888 | } 889 | // xcuserdata 本地用户文件 890 | NSString *xcuserdataFilePath = [xcodeprojFilePath stringByAppendingPathComponent:@"xcuserdata"]; 891 | if ([fm fileExistsAtPath:xcuserdataFilePath]) { 892 | [fm removeItemAtPath:xcuserdataFilePath error:nil]; 893 | } 894 | // 改名工程文件 895 | renameFile(xcodeprojFilePath, [[projectDir stringByAppendingPathComponent:newName] stringByAppendingPathExtension:@"xcodeproj"]); 896 | } 897 | 898 | // 改工程组文件内容 899 | if ([fm fileExistsAtPath:xcworkspaceFilePath isDirectory:&isDirectory] && isDirectory) { 900 | // 替换 contents.xcworkspacedata 文件内容 901 | NSString *contentsXcworkspacedataFilePath = [xcworkspaceFilePath stringByAppendingPathComponent:@"contents.xcworkspacedata"]; 902 | if ([fm fileExistsAtPath:contentsXcworkspacedataFilePath]) { 903 | replaceProjectFileContent(contentsXcworkspacedataFilePath, oldName, newName); 904 | } 905 | // xcuserdata 本地用户文件 906 | NSString *xcuserdataFilePath = [xcworkspaceFilePath stringByAppendingPathComponent:@"xcuserdata"]; 907 | if ([fm fileExistsAtPath:xcuserdataFilePath]) { 908 | [fm removeItemAtPath:xcuserdataFilePath error:nil]; 909 | } 910 | // 改名工程文件 911 | renameFile(xcworkspaceFilePath, [[projectDir stringByAppendingPathComponent:newName] stringByAppendingPathExtension:@"xcworkspace"]); 912 | } 913 | 914 | // 改源代码文件夹名称 915 | if ([fm fileExistsAtPath:sourceCodeDirPath isDirectory:&isDirectory] && isDirectory) { 916 | renameFile(sourceCodeDirPath, [projectDir stringByAppendingPathComponent:newName]); 917 | } 918 | } 919 | 920 | #pragma mark - 修改类名前缀 921 | 922 | void modifyFilesClassName(NSString *sourceCodeDir, NSString *oldClassName, NSString *newClassName) { 923 | // 文件内容 Const > DDConst (h,m,swift,xib,storyboard) 924 | NSFileManager *fm = [NSFileManager defaultManager]; 925 | NSArray *files = [fm contentsOfDirectoryAtPath:sourceCodeDir error:nil]; 926 | BOOL isDirectory; 927 | for (NSString *filePath in files) { 928 | NSString *path = [sourceCodeDir stringByAppendingPathComponent:filePath]; 929 | ///如果路径下的是文件夹,继续往下走,知道找到一个文件 930 | if ([fm fileExistsAtPath:path isDirectory:&isDirectory] && isDirectory) { 931 | modifyFilesClassName(path, oldClassName, newClassName); 932 | continue; 933 | } 934 | 935 | NSString *fileName = filePath.lastPathComponent; 936 | if ([fileName hasSuffix:@".h"] || [fileName hasSuffix:@".m"] || [fileName hasSuffix:@".mm"] || [fileName hasSuffix:@".pch"] || [fileName hasSuffix:@".swift"] || [fileName hasSuffix:@".xib"] || [fileName hasSuffix:@".storyboard"]) { 937 | NSError *error = nil; 938 | NSMutableString *fileContent = [NSMutableString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error]; 939 | if (error) { 940 | printf("打开文件 %s 失败:%s\n", path.UTF8String, error.localizedDescription.UTF8String); 941 | abort(); 942 | } 943 | 944 | NSString *regularExpression = [NSString stringWithFormat:@"\\b%@\\b", oldClassName]; 945 | BOOL isChanged = regularReplacement(fileContent, regularExpression, newClassName); 946 | if (!isChanged) continue; 947 | error = nil; 948 | [fileContent writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:&error]; 949 | if (error) { 950 | printf("保存文件 %s 失败:%s\n", path.UTF8String, error.localizedDescription.UTF8String); 951 | abort(); 952 | } 953 | replaceFileContend(gSourceCodeDir, oldClassName, newClassName); 954 | } 955 | } 956 | } 957 | 958 | ///当修改类前缀时,将引入到的地方也遍历修改 959 | void replaceFileContend(NSString *sourceCodeDir,NSString *oldClassName,NSString *newClassName){ 960 | NSFileManager *fm = [NSFileManager defaultManager]; 961 | NSArray *files = [fm contentsOfDirectoryAtPath:sourceCodeDir error:nil]; 962 | BOOL isDirectory; 963 | for (NSString *filePath in files) { 964 | NSString *path = [sourceCodeDir stringByAppendingPathComponent:filePath]; 965 | ///如果路径下的是文件夹,继续往下走,知道找到一个文件 966 | if ([fm fileExistsAtPath:path isDirectory:&isDirectory] && isDirectory) { 967 | replaceFileContend(path,oldClassName,newClassName); 968 | continue; 969 | } 970 | NSString *fileName = filePath.lastPathComponent; 971 | ///mm文件先不管 972 | if ([fileName hasSuffix:@".h"] || [fileName hasSuffix:@".m"] || [fileName hasSuffix:@".mm"] || [fileName hasSuffix:@".pch"] || [fileName hasSuffix:@".swift"] || [fileName hasSuffix:@".xib"] || [fileName hasSuffix:@".storyboard"]) { 973 | NSError *error = nil; 974 | NSMutableString *fileContent = [NSMutableString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error]; 975 | if (error) { 976 | printf("打开文件 %s 失败:%s\n", path.UTF8String, error.localizedDescription.UTF8String); 977 | abort(); 978 | } 979 | if([fileContent containsString:oldClassName]){ 980 | NSRange range = NSMakeRange(0, fileContent.length); 981 | [fileContent replaceOccurrencesOfString:oldClassName withString:newClassName options:NSCaseInsensitiveSearch range:range]; 982 | } 983 | } 984 | } 985 | } 986 | 987 | ///替换类的前缀 988 | void modifyClassNamePrefix(NSMutableString *projectContent, NSString *sourceCodeDir, NSArray *ignoreDirNames, NSString *oldName, NSString *newName) { 989 | NSFileManager *fm = [NSFileManager defaultManager]; 990 | 991 | // 遍历源代码文件 h 与 m 配对,swift 992 | NSArray *files = [fm contentsOfDirectoryAtPath:sourceCodeDir error:nil]; 993 | BOOL isDirectory; 994 | for (NSString *filePath in files) { 995 | NSString *path = [sourceCodeDir stringByAppendingPathComponent:filePath]; 996 | if ([fm fileExistsAtPath:path isDirectory:&isDirectory] && isDirectory) { 997 | if (![ignoreDirNames containsObject:filePath]) { 998 | modifyClassNamePrefix(projectContent, path, ignoreDirNames, oldName, newName); 999 | } 1000 | continue; 1001 | } 1002 | ///概率修改 1003 | NSInteger k = arc4random()%100; 1004 | if(k>kPercent){ 1005 | continue; 1006 | } 1007 | NSString *fileName = filePath.lastPathComponent.stringByDeletingPathExtension; 1008 | NSString *fileExtension = filePath.pathExtension; 1009 | NSString *newClassName; 1010 | if ([fileName hasPrefix:oldName]) { 1011 | newClassName = [newName stringByAppendingString:[fileName substringFromIndex:oldName.length]]; 1012 | } else { 1013 | // newClassName = [newName stringByAppendingString:fileName]; 1014 | //不包含前缀的不加新前缀 1015 | newClassName = fileName; 1016 | } 1017 | 1018 | // 文件名 Const.ext > DDConst.ext 1019 | if ([fileExtension isEqualToString:@"h"]) { 1020 | NSString *mFileName = [fileName stringByAppendingPathExtension:@"m"]; 1021 | NSString *mmFileName = [fileName stringByAppendingPathExtension:@"mm"]; 1022 | if ([files containsObject:mFileName]) { 1023 | NSString *oldFilePath = [[sourceCodeDir stringByAppendingPathComponent:fileName] stringByAppendingPathExtension:@"h"]; 1024 | NSString *newFilePath = [[sourceCodeDir stringByAppendingPathComponent:newClassName] stringByAppendingPathExtension:@"h"]; 1025 | renameFile(oldFilePath, newFilePath); 1026 | oldFilePath = [[sourceCodeDir stringByAppendingPathComponent:fileName] stringByAppendingPathExtension:@"m"]; 1027 | newFilePath = [[sourceCodeDir stringByAppendingPathComponent:newClassName] stringByAppendingPathExtension:@"m"]; 1028 | renameFile(oldFilePath, newFilePath); 1029 | oldFilePath = [[sourceCodeDir stringByAppendingPathComponent:fileName] stringByAppendingPathExtension:@"xib"]; 1030 | if ([fm fileExistsAtPath:oldFilePath]) { 1031 | newFilePath = [[sourceCodeDir stringByAppendingPathComponent:newClassName] stringByAppendingPathExtension:@"xib"]; 1032 | renameFile(oldFilePath, newFilePath); 1033 | } 1034 | 1035 | @autoreleasepool { 1036 | modifyFilesClassName(gSourceCodeDir, fileName, newClassName); 1037 | } 1038 | } 1039 | else if([files containsObject:mmFileName]){ 1040 | NSString *oldFilePath = [[sourceCodeDir stringByAppendingPathComponent:fileName] stringByAppendingPathExtension:@"h"]; 1041 | NSString *newFilePath = [[sourceCodeDir stringByAppendingPathComponent:newClassName] stringByAppendingPathExtension:@"h"]; 1042 | renameFile(oldFilePath, newFilePath); 1043 | oldFilePath = [[sourceCodeDir stringByAppendingPathComponent:fileName] stringByAppendingPathExtension:@"mm"]; 1044 | newFilePath = [[sourceCodeDir stringByAppendingPathComponent:newClassName] stringByAppendingPathExtension:@"mm"]; 1045 | renameFile(oldFilePath, newFilePath); 1046 | oldFilePath = [[sourceCodeDir stringByAppendingPathComponent:fileName] stringByAppendingPathExtension:@"xib"]; 1047 | if ([fm fileExistsAtPath:oldFilePath]) { 1048 | newFilePath = [[sourceCodeDir stringByAppendingPathComponent:newClassName] stringByAppendingPathExtension:@"xib"]; 1049 | renameFile(oldFilePath, newFilePath); 1050 | } 1051 | 1052 | @autoreleasepool { 1053 | modifyFilesClassName(gSourceCodeDir, fileName, newClassName); 1054 | } 1055 | } 1056 | else { 1057 | NSString *oldFilePath = [[sourceCodeDir stringByAppendingPathComponent:fileName] stringByAppendingPathExtension:@"h"]; 1058 | NSString *newFilePath = [[sourceCodeDir stringByAppendingPathComponent:newClassName] stringByAppendingPathExtension:@"h"]; 1059 | renameFile(oldFilePath, newFilePath); 1060 | @autoreleasepool { 1061 | modifyFilesClassName(gSourceCodeDir, fileName, newClassName); 1062 | } 1063 | // continue; 1064 | } 1065 | } else if ([fileExtension isEqualToString:@"swift"]) { 1066 | NSString *oldFilePath = [[sourceCodeDir stringByAppendingPathComponent:fileName] stringByAppendingPathExtension:@"swift"]; 1067 | NSString *newFilePath = [[sourceCodeDir stringByAppendingPathComponent:newClassName] stringByAppendingPathExtension:@"swift"]; 1068 | renameFile(oldFilePath, newFilePath); 1069 | oldFilePath = [[sourceCodeDir stringByAppendingPathComponent:fileName] stringByAppendingPathExtension:@"xib"]; 1070 | if ([fm fileExistsAtPath:oldFilePath]) { 1071 | newFilePath = [[sourceCodeDir stringByAppendingPathComponent:newClassName] stringByAppendingPathExtension:@"xib"]; 1072 | renameFile(oldFilePath, newFilePath); 1073 | } 1074 | 1075 | @autoreleasepool { 1076 | modifyFilesClassName(gSourceCodeDir, fileName.stringByDeletingPathExtension, newClassName); 1077 | } 1078 | } else { 1079 | continue; 1080 | } 1081 | 1082 | // 修改工程文件中的文件名 1083 | NSString *regularExpression = [NSString stringWithFormat:@"\\b%@\\b", fileName]; 1084 | regularReplacement(projectContent, regularExpression, newClassName); 1085 | } 1086 | } 1087 | 1088 | ///删除所有垃圾代码以"sp_"开头,前缀可自定义,只要不与本身方法重合就可以 1089 | void deleteAllSpamCode(NSString *sourceCodeDir,NSString *prefix){ 1090 | 1091 | } 1092 | 1093 | void writeToFile(NSString *apiName){ 1094 | NSInteger k = arc4random()%100; 1095 | if(k>kPercent){ 1096 | return; 1097 | } 1098 | NSString *path = @"/Users/journeyyoung/GDIOSProjectMix/ProjectMix/LocalAPIList.plist"; 1099 | NSMutableArray* points = [NSMutableArray arrayWithContentsOfFile:path]; 1100 | NSString *newName = [apiName stringByReplacingOccurrencesOfString:@":" withString:@""]; 1101 | [points addObject:newName]; 1102 | [points writeToFile:path atomically:YES]; 1103 | 1104 | } 1105 | 1106 | 1107 | void changePrefix(NSString *sourceCodeDir, NSArray *ignoreDirNames,NSString *oldName, NSString *newName){ 1108 | NSFileManager *fm = [NSFileManager defaultManager]; 1109 | 1110 | // 遍历源代码文件 h 与 m 配对 1111 | NSArray *files = [fm contentsOfDirectoryAtPath:sourceCodeDir error:nil]; 1112 | BOOL isDirectory; 1113 | for (NSString *filePath in files) { 1114 | NSString *path = [sourceCodeDir stringByAppendingPathComponent:filePath]; 1115 | if ([fm fileExistsAtPath:path isDirectory:&isDirectory] && isDirectory) { 1116 | // if (![ignoreDirNames containsObject:filePath]) { 1117 | // changePrefix(path, ignoreDirNames, oldName, newName); 1118 | // } 1119 | changePrefix(path, ignoreDirNames, oldName, newName); 1120 | continue; 1121 | } 1122 | 1123 | NSString *fileName = filePath.lastPathComponent.stringByDeletingPathExtension; 1124 | NSString *fileExtension = filePath.pathExtension; 1125 | if ([fileExtension isEqualToString:@"h"]) { 1126 | ///概率修改 1127 | NSInteger k = arc4random()%100; 1128 | if(k>kPercent){ 1129 | continue; 1130 | } 1131 | NSString *mFileName = [fileName stringByAppendingPathExtension:@"m"]; 1132 | NSString *mmFileName = [fileName stringByAppendingPathExtension:@"mm"]; 1133 | if ([files containsObject:mFileName]){ 1134 | NSString *hFilePath = [[sourceCodeDir stringByAppendingPathComponent:fileName] stringByAppendingPathExtension:@"h"]; 1135 | NSString *mFilePath = [[sourceCodeDir stringByAppendingPathComponent:fileName] stringByAppendingPathExtension:@"m"]; 1136 | NSError *error = nil; 1137 | NSMutableString *fileContent = [NSMutableString stringWithContentsOfFile:mFilePath encoding:NSUTF8StringEncoding error:&error]; 1138 | if([fileContent containsString:oldName]){ 1139 | [fileContent replaceOccurrencesOfString:oldName withString:newName options:NSCaseInsensitiveSearch range:NSMakeRange(0, fileContent.length)]; 1140 | [fileContent writeToFile:mFilePath atomically:YES encoding:NSUTF8StringEncoding error:nil]; 1141 | } 1142 | NSMutableString *hfileConten = [NSMutableString stringWithContentsOfFile:hFilePath encoding:NSUTF8StringEncoding error:nil]; 1143 | if([hfileConten containsString:oldName]){ 1144 | [hfileConten replaceOccurrencesOfString:oldName withString:newName options:NSCaseInsensitiveSearch range:NSMakeRange(0, hfileConten.length)]; 1145 | [hfileConten writeToFile:hFilePath atomically:YES encoding:NSUTF8StringEncoding error:nil]; 1146 | } 1147 | } 1148 | 1149 | else if ([files containsObject:mmFileName]){ 1150 | NSString *hFilePath = [[sourceCodeDir stringByAppendingPathComponent:fileName] stringByAppendingPathExtension:@"h"]; 1151 | NSString *mFilePath = [[sourceCodeDir stringByAppendingPathComponent:fileName] stringByAppendingPathExtension:@"mm"]; 1152 | NSError *error = nil; 1153 | NSMutableString *fileContent = [NSMutableString stringWithContentsOfFile:mFilePath encoding:NSUTF8StringEncoding error:&error]; 1154 | if([fileContent containsString:oldName]){ 1155 | [fileContent replaceOccurrencesOfString:oldName withString:newName options:NSCaseInsensitiveSearch range:NSMakeRange(0, fileContent.length)]; 1156 | [fileContent writeToFile:mFilePath atomically:YES encoding:NSUTF8StringEncoding error:nil]; 1157 | } 1158 | NSMutableString *hfileConten = [NSMutableString stringWithContentsOfFile:hFilePath encoding:NSUTF8StringEncoding error:nil]; 1159 | if([hfileConten containsString:oldName]){ 1160 | [hfileConten replaceOccurrencesOfString:oldName withString:newName options:NSCaseInsensitiveSearch range:NSMakeRange(0, hfileConten.length)]; 1161 | [hfileConten writeToFile:hFilePath atomically:YES encoding:NSUTF8StringEncoding error:nil]; 1162 | } 1163 | } 1164 | else{ 1165 | NSString *hFilePath = [[sourceCodeDir stringByAppendingPathComponent:fileName] stringByAppendingPathExtension:@"h"]; 1166 | NSMutableString *hfileConten = [NSMutableString stringWithContentsOfFile:hFilePath encoding:NSUTF8StringEncoding error:nil]; 1167 | if([hfileConten containsString:oldName]){ 1168 | [hfileConten replaceOccurrencesOfString:oldName withString:newName options:NSCaseInsensitiveSearch range:NSMakeRange(0, hfileConten.length)]; 1169 | [hfileConten writeToFile:hFilePath atomically:YES encoding:NSUTF8StringEncoding error:nil]; 1170 | } 1171 | } 1172 | } 1173 | } 1174 | } 1175 | --------------------------------------------------------------------------------