├── .gitignore ├── AutoHeaderImportExtension ├── AutoHeaderImportExtension.entitlements ├── Info.plist ├── SourceEditorCommand.h ├── SourceEditorCommand.m ├── SourceEditorExtension.h └── SourceEditorExtension.m ├── AutoImportExtension.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── AutoImportExtension ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ └── Main.storyboard ├── Info.plist ├── ViewController.h ├── ViewController.m └── main.m ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | *.DS_Store 6 | 7 | ## Build generated 8 | build/ 9 | DerivedData/ 10 | 11 | ## Various settings 12 | *.pbxuser 13 | !default.pbxuser 14 | *.mode1v3 15 | !default.mode1v3 16 | *.mode2v3 17 | !default.mode2v3 18 | *.perspectivev3 19 | !default.perspectivev3 20 | xcuserdata/ 21 | 22 | ## Other 23 | *.moved-aside 24 | *.xcuserstate 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | *.dSYM.zip 30 | *.dSYM 31 | 32 | # CocoaPods 33 | # 34 | # We recommend against adding the Pods directory to your .gitignore. However 35 | # you should judge for yourself, the pros and cons are mentioned at: 36 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 37 | # 38 | # Pods/ 39 | 40 | # Carthage 41 | # 42 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 43 | # Carthage/Checkouts 44 | 45 | Carthage/Build 46 | 47 | # fastlane 48 | # 49 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 50 | # screenshots whenever they are needed. 51 | # For more information about the recommended setup visit: 52 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 53 | 54 | fastlane/report.xml 55 | fastlane/screenshots 56 | 57 | #Code Injection 58 | # 59 | # After new code Injection tools there's a generated folder /iOSInjectionProject 60 | # https://github.com/johnno1962/injectionforxcode 61 | 62 | iOSInjectionProject/ 63 | -------------------------------------------------------------------------------- /AutoHeaderImportExtension/AutoHeaderImportExtension.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.assets.movies.read-only 8 | 9 | com.apple.security.assets.music.read-only 10 | 11 | com.apple.security.assets.pictures.read-only 12 | 13 | com.apple.security.device.bluetooth 14 | 15 | com.apple.security.device.camera 16 | 17 | com.apple.security.device.microphone 18 | 19 | com.apple.security.device.usb 20 | 21 | com.apple.security.files.downloads.read-only 22 | 23 | com.apple.security.files.user-selected.read-only 24 | 25 | com.apple.security.network.client 26 | 27 | com.apple.security.network.server 28 | 29 | com.apple.security.personal-information.addressbook 30 | 31 | com.apple.security.personal-information.calendars 32 | 33 | com.apple.security.personal-information.location 34 | 35 | com.apple.security.print 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /AutoHeaderImportExtension/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | AutoHeaderImportExtension 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | XPC! 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSExtension 26 | 27 | NSExtensionAttributes 28 | 29 | XCSourceEditorCommandDefinitions 30 | 31 | 32 | XCSourceEditorCommandClassName 33 | SourceEditorCommand 34 | XCSourceEditorCommandIdentifier 35 | $(PRODUCT_BUNDLE_IDENTIFIER).SourceEditorCommand 36 | XCSourceEditorCommandName 37 | Source Editor Command 38 | 39 | 40 | XCSourceEditorExtensionPrincipalClass 41 | SourceEditorExtension 42 | 43 | NSExtensionPointIdentifier 44 | com.apple.dt.Xcode.extension.source-editor 45 | 46 | NSHumanReadableCopyright 47 | Copyright © 2017年 WillkYang. All rights reserved. 48 | 49 | 50 | -------------------------------------------------------------------------------- /AutoHeaderImportExtension/SourceEditorCommand.h: -------------------------------------------------------------------------------- 1 | // 2 | // SourceEditorCommand.h 3 | // AutoHeaderImportExtension 4 | // 5 | // Created by yate1996 on 2017/1/16. 6 | // Copyright © 2017年 WillkYang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SourceEditorCommand : NSObject 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /AutoHeaderImportExtension/SourceEditorCommand.m: -------------------------------------------------------------------------------- 1 | // 2 | // SourceEditorCommand.m 3 | // AutoHeaderImportExtension 4 | // 5 | // Created by yate1996 on 2017/1/16. 6 | // Copyright © 2017年 WillkYang. All rights reserved. 7 | // 8 | 9 | #import "SourceEditorCommand.h" 10 | 11 | @implementation SourceEditorCommand 12 | 13 | //TODO 检测头文件是否为父类类型~现有系统API无法检测~ 14 | //暂不支持库文件,不支持协议检测 15 | //暂时忽略文件名含有+号的的情况,认为此类文件属于分类,所以没有进行过滤 16 | //如果后期系统支持了项目文件空间的文件访问和GUI支持,则插件可以发挥更大作用 17 | 18 | //已实现功能 19 | //1.删除无用的类头文件,要求类名和文件名一致 20 | //2.删除重复导入的头文件,只保留一个 21 | //3.忽略文件扩展,即包含+号的文件 22 | 23 | - (void)performCommandWithInvocation:(XCSourceEditorCommandInvocation *)invocation completionHandler:(void (^)(NSError * _Nullable nilOrError))completionHandler 24 | { 25 | 26 | //headerDict存放文本中所有的头文件 27 | NSMutableDictionary *headerDict = [NSMutableDictionary dictionary]; 28 | //willCheckDict存放将要删除的头文件 29 | NSMutableDictionary *willCheckDict = [NSMutableDictionary dictionary]; 30 | 31 | //遍历编辑器每一行 32 | for (int idx = 0; idx < invocation.buffer.lines.count; idx++) { 33 | 34 | NSString *lineCode = invocation.buffer.lines[idx]; 35 | 36 | //若willCheckDict文件不为空,则进行是否使用了该头文件的判断 37 | if (willCheckDict.count > 0) { 38 | [willCheckDict enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull key, NSString * _Nonnull checkString, BOOL * _Nonnull stop) { 39 | if ([lineCode containsString:checkString]) { 40 | if (![lineCode containsString:@"#import"]) { 41 | if ([headerDict[checkString] isEqualToNumber: @1]) { 42 | //若使用了该头文件,则从willCheckDict字典中提出该项 43 | [willCheckDict removeObjectForKey:key]; 44 | //同时设置该头文件已经检查过,若后续仍出现该头文件,则可以进行删除 45 | headerDict[checkString] = @0; 46 | } 47 | } 48 | } 49 | }]; 50 | 51 | } 52 | 53 | //检测代码是否含有#import为头文件标志;+号我们认为是类扩展的标志 54 | if ([lineCode containsString:@"#import"] && ![lineCode containsString:@"+"]) { 55 | //解析获取类名 56 | NSRange range1 = [lineCode rangeOfString:@"\""]; 57 | NSRange range2 = [lineCode rangeOfString:@"\"" options:NSBackwardsSearch]; 58 | NSRange zeroRange = NSMakeRange(0, 0); 59 | 60 | if (!(NSEqualRanges(range1, zeroRange) || NSEqualRanges(range2, zeroRange))) { 61 | NSRange findRange = NSMakeRange(range1.location + 1, range2.location - range1.location - 3); 62 | NSString *classString = [lineCode substringWithRange:findRange]; 63 | willCheckDict[@(idx)] = classString; 64 | headerDict[classString] = @1; 65 | } 66 | } 67 | } 68 | 69 | 70 | //取出需要删除的行 71 | NSMutableIndexSet *index = [NSMutableIndexSet indexSet]; 72 | [willCheckDict.allKeys enumerateObjectsUsingBlock:^(NSNumber * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 73 | [index addIndex:obj.integerValue]; 74 | 75 | }]; 76 | 77 | //删除不符合条件的行 78 | [invocation.buffer.lines removeObjectsAtIndexes:index]; 79 | 80 | //通知系统完成 81 | completionHandler(nil); 82 | } 83 | 84 | @end 85 | -------------------------------------------------------------------------------- /AutoHeaderImportExtension/SourceEditorExtension.h: -------------------------------------------------------------------------------- 1 | // 2 | // SourceEditorExtension.h 3 | // AutoHeaderImportExtension 4 | // 5 | // Created by yate1996 on 2017/1/16. 6 | // Copyright © 2017年 WillkYang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SourceEditorExtension : NSObject 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /AutoHeaderImportExtension/SourceEditorExtension.m: -------------------------------------------------------------------------------- 1 | // 2 | // SourceEditorExtension.m 3 | // AutoHeaderImportExtension 4 | // 5 | // Created by yate1996 on 2017/1/16. 6 | // Copyright © 2017年 WillkYang. All rights reserved. 7 | // 8 | 9 | #import "SourceEditorExtension.h" 10 | 11 | @implementation SourceEditorExtension 12 | 13 | /* 14 | - (void)extensionDidFinishLaunching 15 | { 16 | // If your extension needs to do any work at launch, implement this optional method. 17 | } 18 | */ 19 | 20 | /* 21 | - (NSArray *> *)commandDefinitions 22 | { 23 | // If your extension needs to return a collection of command definitions that differs from those in its Info.plist, implement this optional property getter. 24 | return @[]; 25 | } 26 | */ 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /AutoImportExtension.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 841D7BE81E2D009F005E9ECA /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 841D7BE71E2D009F005E9ECA /* AppDelegate.m */; }; 11 | 841D7BEB1E2D009F005E9ECA /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 841D7BEA1E2D009F005E9ECA /* main.m */; }; 12 | 841D7BEE1E2D009F005E9ECA /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 841D7BED1E2D009F005E9ECA /* ViewController.m */; }; 13 | 841D7BF01E2D009F005E9ECA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 841D7BEF1E2D009F005E9ECA /* Assets.xcassets */; }; 14 | 841D7BF31E2D009F005E9ECA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 841D7BF11E2D009F005E9ECA /* Main.storyboard */; }; 15 | 841D7C011E2D00C6005E9ECA /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 841D7C001E2D00C6005E9ECA /* Cocoa.framework */; }; 16 | 841D7C071E2D00C6005E9ECA /* SourceEditorExtension.m in Sources */ = {isa = PBXBuildFile; fileRef = 841D7C061E2D00C6005E9ECA /* SourceEditorExtension.m */; }; 17 | 841D7C0A1E2D00C6005E9ECA /* SourceEditorCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = 841D7C091E2D00C6005E9ECA /* SourceEditorCommand.m */; }; 18 | 841D7C0E1E2D00C6005E9ECA /* AutoHeaderImportExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 841D7BFE1E2D00C6005E9ECA /* AutoHeaderImportExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXContainerItemProxy section */ 22 | 841D7C0C1E2D00C6005E9ECA /* PBXContainerItemProxy */ = { 23 | isa = PBXContainerItemProxy; 24 | containerPortal = 841D7BDB1E2D009F005E9ECA /* Project object */; 25 | proxyType = 1; 26 | remoteGlobalIDString = 841D7BFD1E2D00C6005E9ECA; 27 | remoteInfo = AutoHeaderImportExtension; 28 | }; 29 | /* End PBXContainerItemProxy section */ 30 | 31 | /* Begin PBXCopyFilesBuildPhase section */ 32 | 841D7C121E2D00C6005E9ECA /* Embed App Extensions */ = { 33 | isa = PBXCopyFilesBuildPhase; 34 | buildActionMask = 2147483647; 35 | dstPath = ""; 36 | dstSubfolderSpec = 13; 37 | files = ( 38 | 841D7C0E1E2D00C6005E9ECA /* AutoHeaderImportExtension.appex in Embed App Extensions */, 39 | ); 40 | name = "Embed App Extensions"; 41 | runOnlyForDeploymentPostprocessing = 0; 42 | }; 43 | /* End PBXCopyFilesBuildPhase section */ 44 | 45 | /* Begin PBXFileReference section */ 46 | 841D7BE31E2D009F005E9ECA /* AutoImportExtension.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AutoImportExtension.app; sourceTree = BUILT_PRODUCTS_DIR; }; 47 | 841D7BE61E2D009F005E9ECA /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 48 | 841D7BE71E2D009F005E9ECA /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 49 | 841D7BEA1E2D009F005E9ECA /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 50 | 841D7BEC1E2D009F005E9ECA /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 51 | 841D7BED1E2D009F005E9ECA /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 52 | 841D7BEF1E2D009F005E9ECA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 53 | 841D7BF21E2D009F005E9ECA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 54 | 841D7BF41E2D009F005E9ECA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 55 | 841D7BFE1E2D00C6005E9ECA /* AutoHeaderImportExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = AutoHeaderImportExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 56 | 841D7C001E2D00C6005E9ECA /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 57 | 841D7C041E2D00C6005E9ECA /* AutoHeaderImportExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = AutoHeaderImportExtension.entitlements; sourceTree = ""; }; 58 | 841D7C051E2D00C6005E9ECA /* SourceEditorExtension.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SourceEditorExtension.h; sourceTree = ""; }; 59 | 841D7C061E2D00C6005E9ECA /* SourceEditorExtension.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SourceEditorExtension.m; sourceTree = ""; }; 60 | 841D7C081E2D00C6005E9ECA /* SourceEditorCommand.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SourceEditorCommand.h; sourceTree = ""; }; 61 | 841D7C091E2D00C6005E9ECA /* SourceEditorCommand.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SourceEditorCommand.m; sourceTree = ""; }; 62 | 841D7C0B1E2D00C6005E9ECA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 63 | /* End PBXFileReference section */ 64 | 65 | /* Begin PBXFrameworksBuildPhase section */ 66 | 841D7BE01E2D009F005E9ECA /* Frameworks */ = { 67 | isa = PBXFrameworksBuildPhase; 68 | buildActionMask = 2147483647; 69 | files = ( 70 | ); 71 | runOnlyForDeploymentPostprocessing = 0; 72 | }; 73 | 841D7BFB1E2D00C6005E9ECA /* Frameworks */ = { 74 | isa = PBXFrameworksBuildPhase; 75 | buildActionMask = 2147483647; 76 | files = ( 77 | 841D7C011E2D00C6005E9ECA /* Cocoa.framework in Frameworks */, 78 | ); 79 | runOnlyForDeploymentPostprocessing = 0; 80 | }; 81 | /* End PBXFrameworksBuildPhase section */ 82 | 83 | /* Begin PBXGroup section */ 84 | 841D7BDA1E2D009F005E9ECA = { 85 | isa = PBXGroup; 86 | children = ( 87 | 841D7BE51E2D009F005E9ECA /* AutoImportExtension */, 88 | 841D7C021E2D00C6005E9ECA /* AutoHeaderImportExtension */, 89 | 841D7BFF1E2D00C6005E9ECA /* Frameworks */, 90 | 841D7BE41E2D009F005E9ECA /* Products */, 91 | ); 92 | sourceTree = ""; 93 | }; 94 | 841D7BE41E2D009F005E9ECA /* Products */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | 841D7BE31E2D009F005E9ECA /* AutoImportExtension.app */, 98 | 841D7BFE1E2D00C6005E9ECA /* AutoHeaderImportExtension.appex */, 99 | ); 100 | name = Products; 101 | sourceTree = ""; 102 | }; 103 | 841D7BE51E2D009F005E9ECA /* AutoImportExtension */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | 841D7BE61E2D009F005E9ECA /* AppDelegate.h */, 107 | 841D7BE71E2D009F005E9ECA /* AppDelegate.m */, 108 | 841D7BEC1E2D009F005E9ECA /* ViewController.h */, 109 | 841D7BED1E2D009F005E9ECA /* ViewController.m */, 110 | 841D7BEF1E2D009F005E9ECA /* Assets.xcassets */, 111 | 841D7BF11E2D009F005E9ECA /* Main.storyboard */, 112 | 841D7BF41E2D009F005E9ECA /* Info.plist */, 113 | 841D7BE91E2D009F005E9ECA /* Supporting Files */, 114 | ); 115 | path = AutoImportExtension; 116 | sourceTree = ""; 117 | }; 118 | 841D7BE91E2D009F005E9ECA /* Supporting Files */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | 841D7BEA1E2D009F005E9ECA /* main.m */, 122 | ); 123 | name = "Supporting Files"; 124 | sourceTree = ""; 125 | }; 126 | 841D7BFF1E2D00C6005E9ECA /* Frameworks */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | 841D7C001E2D00C6005E9ECA /* Cocoa.framework */, 130 | ); 131 | name = Frameworks; 132 | sourceTree = ""; 133 | }; 134 | 841D7C021E2D00C6005E9ECA /* AutoHeaderImportExtension */ = { 135 | isa = PBXGroup; 136 | children = ( 137 | 841D7C051E2D00C6005E9ECA /* SourceEditorExtension.h */, 138 | 841D7C061E2D00C6005E9ECA /* SourceEditorExtension.m */, 139 | 841D7C081E2D00C6005E9ECA /* SourceEditorCommand.h */, 140 | 841D7C091E2D00C6005E9ECA /* SourceEditorCommand.m */, 141 | 841D7C0B1E2D00C6005E9ECA /* Info.plist */, 142 | 841D7C031E2D00C6005E9ECA /* Supporting Files */, 143 | ); 144 | path = AutoHeaderImportExtension; 145 | sourceTree = ""; 146 | }; 147 | 841D7C031E2D00C6005E9ECA /* Supporting Files */ = { 148 | isa = PBXGroup; 149 | children = ( 150 | 841D7C041E2D00C6005E9ECA /* AutoHeaderImportExtension.entitlements */, 151 | ); 152 | name = "Supporting Files"; 153 | sourceTree = ""; 154 | }; 155 | /* End PBXGroup section */ 156 | 157 | /* Begin PBXNativeTarget section */ 158 | 841D7BE21E2D009F005E9ECA /* AutoImportExtension */ = { 159 | isa = PBXNativeTarget; 160 | buildConfigurationList = 841D7BF71E2D009F005E9ECA /* Build configuration list for PBXNativeTarget "AutoImportExtension" */; 161 | buildPhases = ( 162 | 841D7BDF1E2D009F005E9ECA /* Sources */, 163 | 841D7BE01E2D009F005E9ECA /* Frameworks */, 164 | 841D7BE11E2D009F005E9ECA /* Resources */, 165 | 841D7C121E2D00C6005E9ECA /* Embed App Extensions */, 166 | ); 167 | buildRules = ( 168 | ); 169 | dependencies = ( 170 | 841D7C0D1E2D00C6005E9ECA /* PBXTargetDependency */, 171 | ); 172 | name = AutoImportExtension; 173 | productName = AutoImportExtension; 174 | productReference = 841D7BE31E2D009F005E9ECA /* AutoImportExtension.app */; 175 | productType = "com.apple.product-type.application"; 176 | }; 177 | 841D7BFD1E2D00C6005E9ECA /* AutoHeaderImportExtension */ = { 178 | isa = PBXNativeTarget; 179 | buildConfigurationList = 841D7C0F1E2D00C6005E9ECA /* Build configuration list for PBXNativeTarget "AutoHeaderImportExtension" */; 180 | buildPhases = ( 181 | 841D7BFA1E2D00C6005E9ECA /* Sources */, 182 | 841D7BFB1E2D00C6005E9ECA /* Frameworks */, 183 | 841D7BFC1E2D00C6005E9ECA /* Resources */, 184 | ); 185 | buildRules = ( 186 | ); 187 | dependencies = ( 188 | ); 189 | name = AutoHeaderImportExtension; 190 | productName = AutoHeaderImportExtension; 191 | productReference = 841D7BFE1E2D00C6005E9ECA /* AutoHeaderImportExtension.appex */; 192 | productType = "com.apple.product-type.xcode-extension"; 193 | }; 194 | /* End PBXNativeTarget section */ 195 | 196 | /* Begin PBXProject section */ 197 | 841D7BDB1E2D009F005E9ECA /* Project object */ = { 198 | isa = PBXProject; 199 | attributes = { 200 | LastUpgradeCheck = 0820; 201 | ORGANIZATIONNAME = WillkYang; 202 | TargetAttributes = { 203 | 841D7BE21E2D009F005E9ECA = { 204 | CreatedOnToolsVersion = 8.2.1; 205 | DevelopmentTeam = N3VC6N6JE3; 206 | ProvisioningStyle = Automatic; 207 | }; 208 | 841D7BFD1E2D00C6005E9ECA = { 209 | CreatedOnToolsVersion = 8.2.1; 210 | DevelopmentTeam = N3VC6N6JE3; 211 | ProvisioningStyle = Automatic; 212 | SystemCapabilities = { 213 | com.apple.ApplicationGroups.Mac = { 214 | enabled = 0; 215 | }; 216 | }; 217 | }; 218 | }; 219 | }; 220 | buildConfigurationList = 841D7BDE1E2D009F005E9ECA /* Build configuration list for PBXProject "AutoImportExtension" */; 221 | compatibilityVersion = "Xcode 3.2"; 222 | developmentRegion = English; 223 | hasScannedForEncodings = 0; 224 | knownRegions = ( 225 | en, 226 | Base, 227 | ); 228 | mainGroup = 841D7BDA1E2D009F005E9ECA; 229 | productRefGroup = 841D7BE41E2D009F005E9ECA /* Products */; 230 | projectDirPath = ""; 231 | projectRoot = ""; 232 | targets = ( 233 | 841D7BE21E2D009F005E9ECA /* AutoImportExtension */, 234 | 841D7BFD1E2D00C6005E9ECA /* AutoHeaderImportExtension */, 235 | ); 236 | }; 237 | /* End PBXProject section */ 238 | 239 | /* Begin PBXResourcesBuildPhase section */ 240 | 841D7BE11E2D009F005E9ECA /* Resources */ = { 241 | isa = PBXResourcesBuildPhase; 242 | buildActionMask = 2147483647; 243 | files = ( 244 | 841D7BF01E2D009F005E9ECA /* Assets.xcassets in Resources */, 245 | 841D7BF31E2D009F005E9ECA /* Main.storyboard in Resources */, 246 | ); 247 | runOnlyForDeploymentPostprocessing = 0; 248 | }; 249 | 841D7BFC1E2D00C6005E9ECA /* Resources */ = { 250 | isa = PBXResourcesBuildPhase; 251 | buildActionMask = 2147483647; 252 | files = ( 253 | ); 254 | runOnlyForDeploymentPostprocessing = 0; 255 | }; 256 | /* End PBXResourcesBuildPhase section */ 257 | 258 | /* Begin PBXSourcesBuildPhase section */ 259 | 841D7BDF1E2D009F005E9ECA /* Sources */ = { 260 | isa = PBXSourcesBuildPhase; 261 | buildActionMask = 2147483647; 262 | files = ( 263 | 841D7BEE1E2D009F005E9ECA /* ViewController.m in Sources */, 264 | 841D7BEB1E2D009F005E9ECA /* main.m in Sources */, 265 | 841D7BE81E2D009F005E9ECA /* AppDelegate.m in Sources */, 266 | ); 267 | runOnlyForDeploymentPostprocessing = 0; 268 | }; 269 | 841D7BFA1E2D00C6005E9ECA /* Sources */ = { 270 | isa = PBXSourcesBuildPhase; 271 | buildActionMask = 2147483647; 272 | files = ( 273 | 841D7C071E2D00C6005E9ECA /* SourceEditorExtension.m in Sources */, 274 | 841D7C0A1E2D00C6005E9ECA /* SourceEditorCommand.m in Sources */, 275 | ); 276 | runOnlyForDeploymentPostprocessing = 0; 277 | }; 278 | /* End PBXSourcesBuildPhase section */ 279 | 280 | /* Begin PBXTargetDependency section */ 281 | 841D7C0D1E2D00C6005E9ECA /* PBXTargetDependency */ = { 282 | isa = PBXTargetDependency; 283 | target = 841D7BFD1E2D00C6005E9ECA /* AutoHeaderImportExtension */; 284 | targetProxy = 841D7C0C1E2D00C6005E9ECA /* PBXContainerItemProxy */; 285 | }; 286 | /* End PBXTargetDependency section */ 287 | 288 | /* Begin PBXVariantGroup section */ 289 | 841D7BF11E2D009F005E9ECA /* Main.storyboard */ = { 290 | isa = PBXVariantGroup; 291 | children = ( 292 | 841D7BF21E2D009F005E9ECA /* Base */, 293 | ); 294 | name = Main.storyboard; 295 | sourceTree = ""; 296 | }; 297 | /* End PBXVariantGroup section */ 298 | 299 | /* Begin XCBuildConfiguration section */ 300 | 841D7BF51E2D009F005E9ECA /* Debug */ = { 301 | isa = XCBuildConfiguration; 302 | buildSettings = { 303 | ALWAYS_SEARCH_USER_PATHS = NO; 304 | CLANG_ANALYZER_NONNULL = YES; 305 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 306 | CLANG_CXX_LIBRARY = "libc++"; 307 | CLANG_ENABLE_MODULES = YES; 308 | CLANG_ENABLE_OBJC_ARC = YES; 309 | CLANG_WARN_BOOL_CONVERSION = YES; 310 | CLANG_WARN_CONSTANT_CONVERSION = YES; 311 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 312 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 313 | CLANG_WARN_EMPTY_BODY = YES; 314 | CLANG_WARN_ENUM_CONVERSION = YES; 315 | CLANG_WARN_INFINITE_RECURSION = YES; 316 | CLANG_WARN_INT_CONVERSION = YES; 317 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 318 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 319 | CLANG_WARN_UNREACHABLE_CODE = YES; 320 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 321 | CODE_SIGN_IDENTITY = "-"; 322 | COPY_PHASE_STRIP = NO; 323 | DEBUG_INFORMATION_FORMAT = dwarf; 324 | ENABLE_STRICT_OBJC_MSGSEND = YES; 325 | ENABLE_TESTABILITY = YES; 326 | GCC_C_LANGUAGE_STANDARD = gnu99; 327 | GCC_DYNAMIC_NO_PIC = NO; 328 | GCC_NO_COMMON_BLOCKS = YES; 329 | GCC_OPTIMIZATION_LEVEL = 0; 330 | GCC_PREPROCESSOR_DEFINITIONS = ( 331 | "DEBUG=1", 332 | "$(inherited)", 333 | ); 334 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 335 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 336 | GCC_WARN_UNDECLARED_SELECTOR = YES; 337 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 338 | GCC_WARN_UNUSED_FUNCTION = YES; 339 | GCC_WARN_UNUSED_VARIABLE = YES; 340 | MACOSX_DEPLOYMENT_TARGET = 10.12; 341 | MTL_ENABLE_DEBUG_INFO = YES; 342 | ONLY_ACTIVE_ARCH = YES; 343 | SDKROOT = macosx; 344 | }; 345 | name = Debug; 346 | }; 347 | 841D7BF61E2D009F005E9ECA /* Release */ = { 348 | isa = XCBuildConfiguration; 349 | buildSettings = { 350 | ALWAYS_SEARCH_USER_PATHS = NO; 351 | CLANG_ANALYZER_NONNULL = YES; 352 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 353 | CLANG_CXX_LIBRARY = "libc++"; 354 | CLANG_ENABLE_MODULES = YES; 355 | CLANG_ENABLE_OBJC_ARC = YES; 356 | CLANG_WARN_BOOL_CONVERSION = YES; 357 | CLANG_WARN_CONSTANT_CONVERSION = YES; 358 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 359 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 360 | CLANG_WARN_EMPTY_BODY = YES; 361 | CLANG_WARN_ENUM_CONVERSION = YES; 362 | CLANG_WARN_INFINITE_RECURSION = YES; 363 | CLANG_WARN_INT_CONVERSION = YES; 364 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 365 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 366 | CLANG_WARN_UNREACHABLE_CODE = YES; 367 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 368 | CODE_SIGN_IDENTITY = "-"; 369 | COPY_PHASE_STRIP = NO; 370 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 371 | ENABLE_NS_ASSERTIONS = NO; 372 | ENABLE_STRICT_OBJC_MSGSEND = YES; 373 | GCC_C_LANGUAGE_STANDARD = gnu99; 374 | GCC_NO_COMMON_BLOCKS = YES; 375 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 376 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 377 | GCC_WARN_UNDECLARED_SELECTOR = YES; 378 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 379 | GCC_WARN_UNUSED_FUNCTION = YES; 380 | GCC_WARN_UNUSED_VARIABLE = YES; 381 | MACOSX_DEPLOYMENT_TARGET = 10.12; 382 | MTL_ENABLE_DEBUG_INFO = NO; 383 | SDKROOT = macosx; 384 | }; 385 | name = Release; 386 | }; 387 | 841D7BF81E2D009F005E9ECA /* Debug */ = { 388 | isa = XCBuildConfiguration; 389 | buildSettings = { 390 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 391 | CODE_SIGN_IDENTITY = "Mac Developer"; 392 | COMBINE_HIDPI_IMAGES = YES; 393 | DEVELOPMENT_TEAM = N3VC6N6JE3; 394 | INFOPLIST_FILE = AutoImportExtension/Info.plist; 395 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 396 | PRODUCT_BUNDLE_IDENTIFIER = com.WillkYang.AutoImportExtension; 397 | PRODUCT_NAME = "$(TARGET_NAME)"; 398 | }; 399 | name = Debug; 400 | }; 401 | 841D7BF91E2D009F005E9ECA /* Release */ = { 402 | isa = XCBuildConfiguration; 403 | buildSettings = { 404 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 405 | CODE_SIGN_IDENTITY = "Mac Developer"; 406 | COMBINE_HIDPI_IMAGES = YES; 407 | DEVELOPMENT_TEAM = N3VC6N6JE3; 408 | INFOPLIST_FILE = AutoImportExtension/Info.plist; 409 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 410 | PRODUCT_BUNDLE_IDENTIFIER = com.WillkYang.AutoImportExtension; 411 | PRODUCT_NAME = "$(TARGET_NAME)"; 412 | }; 413 | name = Release; 414 | }; 415 | 841D7C101E2D00C6005E9ECA /* Debug */ = { 416 | isa = XCBuildConfiguration; 417 | buildSettings = { 418 | CODE_SIGN_ENTITLEMENTS = AutoHeaderImportExtension/AutoHeaderImportExtension.entitlements; 419 | CODE_SIGN_IDENTITY = "Mac Developer"; 420 | COMBINE_HIDPI_IMAGES = YES; 421 | DEVELOPMENT_TEAM = N3VC6N6JE3; 422 | INFOPLIST_FILE = AutoHeaderImportExtension/Info.plist; 423 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @executable_path/../../../../Frameworks"; 424 | MACOSX_DEPLOYMENT_TARGET = 10.12; 425 | PRODUCT_BUNDLE_IDENTIFIER = com.WillkYang.AutoImportExtension.AutoHeaderImportExtension; 426 | PRODUCT_NAME = "$(TARGET_NAME)"; 427 | SKIP_INSTALL = YES; 428 | }; 429 | name = Debug; 430 | }; 431 | 841D7C111E2D00C6005E9ECA /* Release */ = { 432 | isa = XCBuildConfiguration; 433 | buildSettings = { 434 | CODE_SIGN_ENTITLEMENTS = AutoHeaderImportExtension/AutoHeaderImportExtension.entitlements; 435 | CODE_SIGN_IDENTITY = "Mac Developer"; 436 | COMBINE_HIDPI_IMAGES = YES; 437 | DEVELOPMENT_TEAM = N3VC6N6JE3; 438 | INFOPLIST_FILE = AutoHeaderImportExtension/Info.plist; 439 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @executable_path/../../../../Frameworks"; 440 | MACOSX_DEPLOYMENT_TARGET = 10.12; 441 | PRODUCT_BUNDLE_IDENTIFIER = com.WillkYang.AutoImportExtension.AutoHeaderImportExtension; 442 | PRODUCT_NAME = "$(TARGET_NAME)"; 443 | SKIP_INSTALL = YES; 444 | }; 445 | name = Release; 446 | }; 447 | /* End XCBuildConfiguration section */ 448 | 449 | /* Begin XCConfigurationList section */ 450 | 841D7BDE1E2D009F005E9ECA /* Build configuration list for PBXProject "AutoImportExtension" */ = { 451 | isa = XCConfigurationList; 452 | buildConfigurations = ( 453 | 841D7BF51E2D009F005E9ECA /* Debug */, 454 | 841D7BF61E2D009F005E9ECA /* Release */, 455 | ); 456 | defaultConfigurationIsVisible = 0; 457 | defaultConfigurationName = Release; 458 | }; 459 | 841D7BF71E2D009F005E9ECA /* Build configuration list for PBXNativeTarget "AutoImportExtension" */ = { 460 | isa = XCConfigurationList; 461 | buildConfigurations = ( 462 | 841D7BF81E2D009F005E9ECA /* Debug */, 463 | 841D7BF91E2D009F005E9ECA /* Release */, 464 | ); 465 | defaultConfigurationIsVisible = 0; 466 | }; 467 | 841D7C0F1E2D00C6005E9ECA /* Build configuration list for PBXNativeTarget "AutoHeaderImportExtension" */ = { 468 | isa = XCConfigurationList; 469 | buildConfigurations = ( 470 | 841D7C101E2D00C6005E9ECA /* Debug */, 471 | 841D7C111E2D00C6005E9ECA /* Release */, 472 | ); 473 | defaultConfigurationIsVisible = 0; 474 | }; 475 | /* End XCConfigurationList section */ 476 | }; 477 | rootObject = 841D7BDB1E2D009F005E9ECA /* Project object */; 478 | } 479 | -------------------------------------------------------------------------------- /AutoImportExtension.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AutoImportExtension/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // AutoImportExtension 4 | // 5 | // Created by yate1996 on 2017/1/16. 6 | // Copyright © 2017年 WillkYang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : NSObject 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /AutoImportExtension/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // AutoImportExtension 4 | // 5 | // Created by yate1996 on 2017/1/16. 6 | // Copyright © 2017年 WillkYang. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { 18 | // Insert code here to initialize your application 19 | } 20 | 21 | 22 | - (void)applicationWillTerminate:(NSNotification *)aNotification { 23 | // Insert code here to tear down your application 24 | } 25 | 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /AutoImportExtension/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "size" : "16x16", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "size" : "16x16", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "size" : "32x32", 16 | "scale" : "1x" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "size" : "32x32", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "size" : "128x128", 26 | "scale" : "1x" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "size" : "128x128", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "size" : "256x256", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "size" : "256x256", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "size" : "512x512", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "size" : "512x512", 51 | "scale" : "2x" 52 | } 53 | ], 54 | "info" : { 55 | "version" : 1, 56 | "author" : "xcode" 57 | } 58 | } -------------------------------------------------------------------------------- /AutoImportExtension/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 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | Default 509 | 510 | 511 | 512 | 513 | 514 | 515 | Left to Right 516 | 517 | 518 | 519 | 520 | 521 | 522 | Right to Left 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | Default 534 | 535 | 536 | 537 | 538 | 539 | 540 | Left to Right 541 | 542 | 543 | 544 | 545 | 546 | 547 | Right to Left 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | -------------------------------------------------------------------------------- /AutoImportExtension/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | Copyright © 2017年 WillkYang. All rights reserved. 27 | NSMainStoryboardFile 28 | Main 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /AutoImportExtension/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // AutoImportExtension 4 | // 5 | // Created by yate1996 on 2017/1/16. 6 | // Copyright © 2017年 WillkYang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : NSViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /AutoImportExtension/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // AutoImportExtension 4 | // 5 | // Created by yate1996 on 2017/1/16. 6 | // Copyright © 2017年 WillkYang. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | @implementation ViewController 12 | 13 | - (void)viewDidLoad { 14 | [super viewDidLoad]; 15 | 16 | // Do any additional setup after loading the view. 17 | } 18 | 19 | 20 | - (void)setRepresentedObject:(id)representedObject { 21 | [super setRepresentedObject:representedObject]; 22 | 23 | // Update the view, if already loaded. 24 | } 25 | 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /AutoImportExtension/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // AutoImportExtension 4 | // 5 | // Created by yate1996 on 2017/1/16. 6 | // Copyright © 2017年 WillkYang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, const char * argv[]) { 12 | return NSApplicationMain(argc, argv); 13 | } 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 WillkYang 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | >Xcode8开放了新的一个Extension:Xcode Source Editor Extension,目的是让开发者可以正规的自主为IDE编写插件,虽然说系统现提供的功能还比较拮据,但是不妨碍我们了解和使用,本文主要介绍Xcode Source Editor Extension的功能,并演示一个简单的插件的实现~ 2 | 3 | ###### 一、实现功能 4 | 1、删除无用的类头文件,要求类名和文件名一致 5 | 6 | 2、删除重复导入的头文件,只保留一个 7 | 8 | ###### 二、编写代码 9 | 10 | 1、新建项目,然后新建一个Target,类型选择Xcode Source Editor Extension,完成之后设置target的签名和项目的签名一致。 11 | 12 | ![在New中选择Target](http://upload-images.jianshu.io/upload_images/459563-6bad7552f26e7442.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 13 | 14 | 15 | 2、在info.plist中可以修改插件显示名称Bundle name和其它对Extension的设置。 16 | 17 | ![插件的info.plist](http://upload-images.jianshu.io/upload_images/459563-d97284d68d580069.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 18 | 19 | 3、系统默认为我们生成SourceEditorCommand文件,此处我们也可以在info里边修改配置项,类似于项目中系统生成的Main.storyboard。插件的重点基本在: 20 | ``` 21 | - (void)performCommandWithInvocation:(XCSourceEditorCommandInvocation *)invocation completionHandler:(void (^)(NSError * _Nullable nilOrError))completionHandler 22 | ``` 23 | 用户调用我们的插件时,系统会回调这个方法 24 | ###### XCSourceEditorCommandInvocation 25 | >Information about the source editor command that the user invoked, such as the identifier of the command, the text buffer on which the command is to operate, and whether the command has been canceled by Xcode or the user. 26 | 27 | 其中invocation.buffer是编辑器的全部文本 28 | ```objc 29 | /** 当前编辑器的全部文件内容 */ 30 | @property (readonly, strong) NSMutableArray *lines; 31 | /** 是当前选中的文本 */ 32 | @property (readonly, strong) NSMutableArray *selections; 33 | ``` 34 | 我们在回调方法中编写如下代码: 35 | 36 | ![源码图片一份,方便查看](http://upload-images.jianshu.io/upload_images/459563-eb2c20a81e60ee46.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 37 | 38 | ```objc 39 | //headerDict存放文本中所有的头文件 40 | NSMutableDictionary *headerDict = [NSMutableDictionary dictionary]; 41 | //willCheckDict存放将要删除的头文件 42 | NSMutableDictionary *willCheckDict = [NSMutableDictionary dictionary]; 43 | 44 | //遍历编辑器每一行 45 | for (int idx = 0; idx < invocation.buffer.lines.count; idx++) { 46 | 47 | NSString *lineCode = invocation.buffer.lines[idx]; 48 | 49 | //若willCheckDict文件不为空,则进行是否使用了该头文件的判断 50 | if (willCheckDict.count > 0) { 51 | [willCheckDict enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull key, NSString * _Nonnull checkString, BOOL * _Nonnull stop) { 52 | if ([lineCode containsString:checkString]) { 53 | if (![lineCode containsString:@"#import"]) { 54 | if ([headerDict[checkString] isEqualToNumber: @1]) { 55 | //若使用了该头文件,则从willCheckDict字典中提出该项 56 | [willCheckDict removeObjectForKey:key]; 57 | //同时设置该头文件已经检查过,若后续仍出现该头文件,则可以进行删除 58 | headerDict[checkString] = @0; 59 | } 60 | } 61 | } 62 | }]; 63 | 64 | } 65 | 66 | //检测代码是否含有#import为头文件标志;+号我们认为是类扩展的标志 67 | if ([lineCode containsString:@"#import"] && ![lineCode containsString:@"+"]) { 68 | //解析获取类名 69 | NSRange range1 = [lineCode rangeOfString:@"\""]; 70 | NSRange range2 = [lineCode rangeOfString:@"\"" options:NSBackwardsSearch]; 71 | NSRange zeroRange = NSMakeRange(0, 0); 72 | 73 | if (!(NSEqualRanges(range1, zeroRange) || NSEqualRanges(range2, zeroRange))) { 74 | NSRange findRange = NSMakeRange(range1.location + 1, range2.location - range1.location - 3); 75 | NSString *classString = [lineCode substringWithRange:findRange]; 76 | willCheckDict[@(idx)] = classString; 77 | headerDict[classString] = @1; 78 | } 79 | } 80 | } 81 | 82 | 83 | //取出需要删除的行 84 | NSMutableIndexSet *index = [NSMutableIndexSet indexSet]; 85 | [willCheckDict.allKeys enumerateObjectsUsingBlock:^(NSNumber * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 86 | [index addIndex:obj.integerValue]; 87 | 88 | }]; 89 | 90 | //删除不符合条件的行 91 | [invocation.buffer.lines removeObjectsAtIndexes:index]; 92 | 93 | //通知系统完成 94 | completionHandler(nil); 95 | ``` 96 | 97 | ##### 三、测试结果 98 | 99 | 1、运行,选择Xcode8 100 | 101 | ![command+r运行插件](http://upload-images.jianshu.io/upload_images/459563-34347f0d276c2e55.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 102 | 103 | 2、可以看见灰色的Xcode实例。随便选择一个项目打开 104 | 105 | ![测试的Xcode,用于区别正式的Xcode](http://upload-images.jianshu.io/upload_images/459563-5a4e6c5afb7641ca.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 106 | 107 | 3、测试。测试文件中含有未使用的头文件和冗余的头文件 108 | 109 | ![处理前代码](http://upload-images.jianshu.io/upload_images/459563-9850d7c6a1352711.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 110 | 111 | 4、Editor中选择插件运行 112 | 113 | ![不出意外Editor菜单最底下一栏,此处名字可以在info.plist修改](http://upload-images.jianshu.io/upload_images/459563-d1c732c5ecc548e3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 114 | 115 | 5、检验运行结果 116 | 117 | ![处理后代码](http://upload-images.jianshu.io/upload_images/459563-64f96edc2777c200.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 118 | 119 | 啦啦啦,多余的头文件已经被成功检测到并且移除了了~ 120 | 121 | ##### 四、总结 122 | 至此,我们完成并测试通过了一个简单的Xcode插件的编写。主要目的是简单了解和使用Xcode8的插件,如果觉得有用,可以找到product里边的文件复制出来打开,然后在系统设置辅助功能中启用,最后在Xcode中绑定快捷键即可食用。当然,功能十分简陋,还请大神勿怪~ 123 | 124 | 不足:受限于系统现有API,运行插件时,只能获取到当前编辑的文件,无法获取整个项目文件来分析,故很多功能暂时无法实现,如支持更加智能的检测等等,以后系统若能提供项目空间的文件访问和GUI支持,则插件可以发挥更大作用~ 125 | 126 | 知识链: 127 | [WWDC2016](https://developer.apple.com/videos/play/wwdc2016/414/) 128 | [iOS 10 Day By Day: Xcode Source Editor Extensions](http://www.cocoachina.com/ios/20161212/18344.html) 129 | [使用 Xcode Source Editor Extension开发Xcode 8 插件](http://blog.csdn.net/zhouzhoujianquan/article/details/52600763) 130 | 131 | 132 | 欢迎加群讨论其它~:578874451 133 | --------------------------------------------------------------------------------